Computational Recruiting
4 minutes to read
We are given a large text file called data.txt
:
$ head data.txt
============ ============== ======== ========= ========== =========== ======== =================
First Name Last Name Health Agility Charisma Knowledge Energy Resourcefulness
============ ============== ======== ========= ========== =========== ======== =================
Alis Reeson 2 5 5 8 7 10
Gerri Bielfelt 8 9 3 8 5 9
Wolfie Appleby 5 1 2 7 2 1
Krishnah Minker 1 7 7 10 6 5
Cassondra Peizer 9 8 8 2 6 4
Jamie Aston 10 7 4 1 5 9
$ wc -l data.txt
204 data.txt
And we also have a remote instance to connect to:
$ nc 94.237.55.39 38975
You will be given a file with N = 200 different potential candidates. Every candidates has 6 different skills, with a score 1 <= s <= 10 for each.
The formulas to calculate their general value are:
<skill>_score = round(6 * (int(s) * <skill>_weight)) + 10
overall_value = round(5 * ((health * 0.18) + (agility * 0.20) + (charisma * 0.21) + (knowledge * 0.08) + (energy * 0.17) + (resourcefulness * 0.16)))
Note: The round() function here is Python 3's round(), which uses a concept called Banker's Rounding
The weights for the 6 skills are: health_weight = 0.2, agility_weight = 0.3, charisma_weight = 0.1, knowledge_weight = 0.05, energy_weight = 0.05, resourcefulness_weight = 0.3
Enter the first 14 candidates ordered in the highest overall values.
Enter them like so: Name_1 Surname_1 - score_1, Name_2 Surname_2 - score_2, ..., Name_i Surname_i - score_i
e.g. Timothy Pempleton - 94, Jimmy Jones - 92, Randolf Ray - 92, ...
>
As can be seen, we have some formulas to calculate <skill>_score
and overall_value
, where <skill>
is one of:
health
agility
charisma
knowledge
energy
resourcefulness
There are weights for each skill too:
health_weight = 0.2
agility_weight = 0.3
charisma_weight = 0.1
knowledge_weight = 0.05
energy_weight = 0.05
resourcefulness_weight = 0.3
Also, we are told to use Python because of the built-in round
function. We need to enter the first 14 candidates ordered in the highest overall values, using the provided format:
Name_1 Surname_1 - score_1, Name_2 Surname_2 - score_2, ..., Name_i Surname_i - score_i
Solution
The following code will use a Regular Expression to parse all lines of the file and save all the statistics using a Candidate
class:
regex = r'^\s+(\w+?)\s+(\w+?)\s+(\d+?)\s+(\d+?)\s+(\d+?)\s+(\d+?)\s+(\d+?)\s+(\d+?)\s+$'
candidates = []
with open('data.txt') as f:
while (line := f.readline()):
matches = re.search(regex, line)
if not matches:
continue
first_name = matches[1]
last_name = matches[2]
health = int(matches[3])
agility = int(matches[4])
charisma = int(matches[5])
knowledge = int(matches[6])
energy = int(matches[7])
resourcefulness = int(matches[8])
candidates.append(Candidate(
first_name, last_name, health, agility, charisma, knowledge, energy, resourcefulness,
))
This Candidate
class is defined here:
health_weight = 0.2
agility_weight = 0.3
charisma_weight = 0.1
knowledge_weight = 0.05
energy_weight = 0.05
resourcefulness_weight = 0.3
class Candidate:
def __init__(self,
first_name: str,
last_name: str,
health: int,
agility: int,
charisma: int,
knowledge: int,
energy: int,
resourcefulness: int):
self.first_name = first_name
self.last_name = last_name
self.health = health
self.agility = agility
self.charisma = charisma
self.knowledge = knowledge
self.energy = energy
self.resourcefulness = resourcefulness
def overall(self) -> int:
health_score = round(6 * self.health * health_weight) + 10
agility_score = round(6 * self.agility * agility_weight) + 10
charisma_score = round(6 * self.charisma * charisma_weight) + 10
knowledge_score = round(6 * self.knowledge * knowledge_weight) + 10
energy_score = round(6 * self.energy * energy_weight) + 10
resourcefulness_score = round(6 * self.resourcefulness * resourcefulness_weight) + 10
return round(5 * ((health_score * 0.18) + (agility_score * 0.20) + (charisma_score * 0.21) + (knowledge_score * 0.08) + (energy_score * 0.17) + (resourcefulness_score * 0.16)))
We have defined a method called overall
to compute the value of overall_value
of a candidate, using each of the <skill>_score
.
Finally, we only need to call overall
on each of the candidates and sort the candidates accordingly. Once we have it, we can get the solution in the given text format:
candidates.sort(key=lambda c: c.overall(), reverse=True)
solution = ', '.join(
f'{c.first_name} {c.last_name} - {c.overall()}' for c in candidates[:14]
)
The only thing we need to do now is to connect to the remote instance and enter the solution:
host, port = sys.argv[1].split(':')
io = remote(host, port)
io.sendlineafter(b'> ', solution.encode())
io.success(io.recvline().decode())
Flag
With all this, we have the flag:
$ python3 solve.py 94.237.55.39:38975
[+] Opening connection to 94.237.55.39 on port 38975: Done
[+] You have recruited the best possible companions. Before you leave, take this: HTB{t3xT_p4rS1ng_4nD_maTh_f0rmUl4s...}
[*] Closed connection to 94.237.55.39 port 38975
The full script can be found in here: solve.py
.