Source: Balance Bots
Part 1: Create a sorting machine using input of the following form:
value X goes to bot A
- an input to botA
bot A gives low to (bot|output) B and high to (bot|output) C
- a sorter that takes two inputs and sends them to the specified bots or output channels
Find the bot that compares the values
17
and61
.
A bit of an odd problem. The bots sound like self contained entities, so we’ll create a class for them:
class Bot(object):
cache = {}
def __init__(self, name):
self.name = name
self.values = set()
self.low_output = None
self.high_output = None
self.compared = []
if args.debug:
print('{} created'.format(self))
@staticmethod
def get(name):
if not name in Bot.cache:
Bot.cache[name] = Bot(name)
return Bot.cache[name]
@staticmethod
def all():
for name in sorted(list(Bot.cache.keys())):
yield Bot.get(name)
def __str__(self):
return 'Bot<{name}, {values}, low:{low_output}, high:{high_output}>'.format(
name = self.name,
values = list(sorted(self.values)),
low_output = self.low_output,
high_output = self.high_output,
)
def give(self, value):
if args.debug:
print('{} given {}'.format(self, value))
self.values.add(value)
if len(self.values) == 2:
self.compared.append(set(self.values))
if not self.low_output or not self.high_output:
#raise Exception('{} got a second value but has not output'.format(self))
print('{} got a second value but has not output'.format(self))
return
Bot.get(self.low_output).give(min(self.values))
Bot.get(self.high_output).give(max(self.values))
self.values.clear()
After that, we can use regular expressions to parse the input:
re_value = re.compile(r'value (?P<value>\d+) goes to (?P<name>(?:(bot|output)) (\d+))')
re_mapping = re.compile(r'(?P<input>(?:(bot|output)) (\d+)) gives low to (?P<low_output>(?:(bot|output)) (\d+)) and high to (?P<high_output>(?:(bot|output)) (\d+))')
values = list()
with open(args.input, 'r') as fin:
for line in fin:
if args.debug:
print(line.strip())
m_value = re_value.match(line)
m_mapping = re_mapping.match(line)
if m_value:
values.append((m_value.group('name'), int(m_value.group('value'))))
elif m_mapping:
input = m_mapping.group('input')
low_output = m_mapping.group('low_output')
high_output = m_mapping.group('high_output')
Bot.get(input).low_output = low_output
Bot.get(input).high_output = high_output
Now that the chain of bots is set up, we can send in the input values and then check which bots compared what:
for name, value in values:
Bot.get(name).give(value)
for bot in Bot.all():
if set(args.targets) in bot.compared:
print(bot, 'compared', args.targets)
This specifically needs to happen after all of the bots are set up, since you cannot output to a bot if you haven’t see the input before the bots definition. That’s why the values are cached in values
.
A neat little bit of code.
Part 2: What is the product
output0 * output1 * output2
?
I’m actually just simulating outputs as bots that are named output
, so find the final values of those:
print('output0 * output1 * output2 = {}'.format(
list(Bot.get('output 0').values)[0]
* list(Bot.get('output 1').values)[0]
* list(Bot.get('output 2').values)[0]
))
And that’s it.
A neat simulation.