In [1]:
myinput = '/home/fmuinos/projects/adventofcode/2016/ferran/inputs/input10.txt'
In [2]:
! wc -l inputs/input10.txt
In [110]:
import re
def parse_bot_commands(myinput):
handle_dict = {}
handle_dict['input'] = set()
handle_dict['give'] = {}
with open(myinput, 'rt') as f:
for line in f:
match = re.findall('(value \d+|bot \d+|output \d+)', line)
if len(match) == 2:
value = int(match[0][6:])
bot = int(match[1][4:]) + 1
handle_dict['input'].add((bot, value))
if len(match) == 3:
bot = int(match[0][4:]) + 1
lo = (int(match[1].split()[1]) + 1) * (1 - 2 * (match[1].split()[0] == 'output'))
hi = (int(match[2].split()[1]) + 1) * (1 - 2 * (match[2].split()[0] == 'output'))
handle_dict['give'][bot] = (lo, hi)
return handle_dict
For the sake of a more compact notation to distinguish them, Bots and Outputs IDs have been re-numbered +1, then Ouput IDs have been made negative integers. The addition +1 at the beginning prevents confusion between bot 0 and output 0.
In [194]:
class Bot(object):
def __init__(self, ID):
self.ID = ID
self.status = 'not-full'
self.load = set()
def update_status(self):
if len(self.load) < 2:
self.status = 'not-full'
else:
self.status = 'full'
def get(self, chip):
if chip is None:
pass
elif self.status == 'not-full':
self.load.add(chip)
self.update_status()
def request(self, botlist, ID):
if ID < 0:
return True
elif botlist[ID-1].status == 'not-full':
return True
elif botlist[ID-1].status == 'full':
return False
def give(self, botlist, lower, higher):
lo = None
hi = None
if self.status == 'full':
if self.request(botlist, lower):
lo = min(self.load)
self.load.remove(lo)
if self.request(botlist, higher):
hi = max(self.load)
self.load.remove(hi)
self.update_status()
return lo, hi
class BotSwarm(object):
def __init__(self, size):
self.size = size
self.swarm = [None] * size
for ind in range(size):
self.swarm[ind] = Bot(ind+1)
self.output = [None] * 21
def initialize(self, handle_dict):
for tupl in handle_dict['input']:
receiver, value = tupl[0], tupl[1]
self.swarm[receiver-1].get(value)
def update(self, handle_dict):
for tpl in handle_dict['give'].items():
giver, lower, higher = tpl[0], tpl[1][0], tpl[1][1]
lo, hi = self.swarm[giver-1].give(self.swarm, lower, higher)
self.swarm[lower-1].get(lo)
self.swarm[higher-1].get(hi)
if (lower < 0) and (lo is not None):
self.output[-lower-1] = lo
if (higher < 0) and (hi is not None):
self.output[-higher-1] = hi
def who(self, chip):
for i in range(self.size):
if chip in self.swarm[i].load:
return self.swarm[i].ID
In [195]:
handle_dict = parse_bot_commands(myinput)
community = BotSwarm(210)
community.initialize(handle_dict)
while community.who(17) != community.who(61):
community.update(handle_dict)
print(community.who(17))
Since we had +1 the Bot labels for convenience, the sought answer is 73.
In [201]:
handle_dict = parse_bot_commands(myinput)
community = BotSwarm(210)
community.initialize(handle_dict)
while (community.output[0] is None) or (community.output[1] is None) or (community.output[2] is None):
community.update(handle_dict)
print(community.output[:3])
community.output[0]*community.output[1]*community.output[2]
Out[201]: