def get_aws_instance_info(proxy): def state(instance): try: return instance.state['Name'] except Exception: return 'UNKNOWN' def groups(instance): return ','.join([g['GroupId'] for g in instance.security_groups]) keys = [aws_name_from_tag, attr('instance_id'), attr('instance_type'), state, attr('public_ip_address'), attr('private_ip_address'), attr('key_name'), groups] headers = ['Name', 'ID', 'Type', 'State', 'Public IP', 'Private IP', 'Key Name', 'Security Groups'] return headers, [[f(i) for f in keys] for i in proxy.get_instances()]
def get_aws_volume_info(proxy): def instance_id(volume): for a in volume.attachments: if a['State'] == 'attached': return a['InstanceId'] return '' def instance_name(instances): instance_dict = {i.id: aws_name_from_tag(i) for i in instances} def _instance_name(volume): _id = instance_id(volume) if _id != '': return instance_dict[_id] return '' return _instance_name def device(volume): for a in volume.attachments: if a['State'] == 'attached': return a['Device'] return '' keys = [ aws_name_from_tag, attr('id'), attr('state'), attr('size'), attr('availability_zone'), instance_name(proxy.get_instances()), instance_id, device] headers = ['Name', 'Volume ID', 'State', 'Size', 'Zone', 'Instance Name', 'Instance ID', 'Device'] return headers, [[f(v) for f in keys] for v in proxy.get_volumes()]
def trace(asteroids): for i in range(len(asteroids)): asteroid = asteroids[i] for j in range(i + 1, len(asteroids)): other = asteroids[j] x, y = (a - b for a, b in zip(asteroid.coords, other.coords)) slope = (y / x) if x != 0 else infinity positive = other.coords > asteroid.coords asteroid.traces[(slope, positive)].append(other) other.traces[(slope, not positive)].append(asteroid) # sort by distance for asteroid in asteroids: sortByDistance = compose(Point(asteroid.coords).manhattan, Point, attr('coords')) for slope in asteroid.traces: asteroid.traces[slope] = sorted(asteroid.traces[slope], key=sortByDistance) return asteroids
from utils import cmap, compose, invoker, at, attr from functools import partial, reduce from itertools import permutations from aoc.intcode import Runner parse = compose(list, cmap(int), invoker('split', ',')) def solve(input, intcode): runner = Runner(iter(input)) runner.run(intcode) return intcode, runner one = compose(at(-1), attr('output'), at(1), partial(solve, [1]), parse) two = compose(attr('output'), at(1), partial(solve, [2]), parse)
other.traces[(slope, not positive)].append(asteroid) # sort by distance for asteroid in asteroids: sortByDistance = compose(Point(asteroid.coords).manhattan, Point, attr('coords')) for slope in asteroid.traces: asteroid.traces[slope] = sorted(asteroid.traces[slope], key=sortByDistance) return asteroids def laserize(asteroid): # sorter of asteroid tracings depending on the laser movement def laserSort(slope, positive): prioritize_if = lambda value: 0 if value else 1 startPointingUp = prioritize_if(slope == infinity and not positive) clockwise = (prioritize_if(positive), slope) return startPointingUp, clockwise rotation = cycle(sorted(asteroid.traces.keys(), key=unpack(laserSort))) while any(asteroid.traces.values()): aligned = asteroid.traces[next(rotation)] if aligned: yield aligned.pop(0) # since we already split traces by line and direction, we simply need to count how many different line/directions there are countAdjacent = compose(len, attr('traces')) one = compose(countAdjacent, partial(max, key=countAdjacent), trace, parse) formatResult = lambda asteroid: asteroid.coords[0]*100 + asteroid.coords[1] two = compose(formatResult, next, lambda laser: islice(laser, 200 - 1, None), laserize, partial(max, key=countAdjacent), trace, parse)
gravitate = lambda body, towards, velocity: velocity + Point( tuple(sign(b - a) for a, b in zip(body.position, towards.position))) adjust = lambda system: [ alter('velocity', compose(*[partial(gravitate, body, other) for other in rest]))(body) for body, rest in isolate(system) ] move = lambda system: [ alter('position', lambda position: position + body.velocity)(body) for body in system ] step = compose(move, adjust) energy = compose(sum, cmap(abs)) potential = compose(energy, attr('position')) kinetic = compose(energy, attr('velocity')) total_energy = lambda system: sum( potential(body) * kinetic(body) for body in system) # We can see that gravity forces among planets affects each axis independently; i.e. the update to each # coordinate of the velocity vectors solely depend on the relative positions of the planets along that axis. # This means repeating cycles happen independently across all axis, so we can find the full-system repeating cycle length # by computing the least common multiple of all axis cycle lengths. def first_repeat(system): dimension = system[0].position.dimension # serializer of one axis for comparison between system states serialize_axis = lambda system, axis: [ body.position[axis] for body in system ] + [body.velocity[axis] for body in system]
elif turn == Robot.RIGHT: return Point((b, -a)) raise "Invalid turn" parse = compose(list, cmap(int), invoker('split', ',')) def solve(intcode, grid): robot = Robot(Runner()) robot.paint_all(intcode, grid) return grid, robot makeGrid = lambda defaults={}: defaultdict(lambda: BLACK, defaults) def display(grid): xs = sorted([p[0] for p, color in grid.items() if color == WHITE]) ys = sorted([p[1] for p, color in grid.items() if color == WHITE]) paintWhite = lambda color: color if color == WHITE else ' ' # for some reason we need to flip it vertically for it to display properly return '\n'.join(''.join( paintWhite(grid[(i, j)]) for i in range(xs[0], xs[-1] + 1)) for j in range(ys[-1], ys[0] - 1, -1)) one = compose(len, attr('painted'), at(1), unpack(solve), lambda intcode: (intcode, makeGrid()), parse) two = compose(display, at(0), unpack(solve), lambda intcode: (intcode, makeGrid({(0, 0): WHITE})), parse)