My Advent of Code solutions in Python. kevinyap.ca/2019/12/going-fast-in-advent-of-code/
advent-of-code python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add solution for 2019/15

+187
+80
2019/day15.py
··· 1 + import random 2 + import fileinput 3 + from collections import defaultdict 4 + 5 + from utils import Point 6 + from intcode import emulate 7 + 8 + 9 + def bfs(graph, start, end=None): 10 + seen = set() 11 + dist = 0 12 + horizon = [start] 13 + while horizon: 14 + new_horizon = [] 15 + for p in horizon: 16 + for np in p.neighbours_4(): 17 + if graph.get(np, 1) == 0: 18 + continue 19 + 20 + if end is not None and np == end: 21 + return dist + 1 22 + 23 + if np not in seen: 24 + new_horizon.append(np) 25 + 26 + seen.add(np) 27 + 28 + horizon = new_horizon 29 + dist += 1 30 + 31 + return dist 32 + 33 + 34 + # Read input 35 + TAPE = [int(x) for x in fileinput.input()[0].split(',')] 36 + TAPE += [0] * 100000 37 + 38 + GLOBAL_INPUTS = [0] 39 + BOARD = {} 40 + OXYGEN = None 41 + 42 + ROBOT_DIRS = [ 43 + Point(1, 0), # north 44 + Point(-1, 0), # south 45 + Point(0, -1), # west 46 + Point(0, 1), # east 47 + ] 48 + 49 + 50 + # Build up board state by exploration 51 + vm = emulate(TAPE, 0, GLOBAL_INPUTS) 52 + 53 + try: 54 + curr = Point(0, 0) 55 + for _ in range(1000000): 56 + facing = random.choice(xrange(4)) 57 + while BOARD.get(curr + ROBOT_DIRS[facing], 1) == 0: 58 + facing = random.choice(xrange(4)) 59 + 60 + GLOBAL_INPUTS[0] = facing + 1 61 + resp = next(vm) 62 + 63 + if resp == 0: 64 + BOARD[curr + ROBOT_DIRS[facing]] = 0 65 + elif resp == 1: 66 + curr += ROBOT_DIRS[facing] 67 + BOARD[curr] = 1 68 + elif resp == 2: 69 + curr += ROBOT_DIRS[facing] 70 + OXYGEN = curr 71 + BOARD[curr] = 2 72 + 73 + except StopIteration: 74 + pass 75 + 76 + # We should have found the oxygen tank after this many ticks 77 + assert 2 in BOARD.values() 78 + 79 + print "Optimal movement to oxygen:", bfs(BOARD, Point(0, 0), OXYGEN) 80 + print "Minutes taken to fill up:", bfs(BOARD, OXYGEN)
+1
2019/inputs/15.txt
··· 1 + 3,1033,1008,1033,1,1032,1005,1032,31,1008,1033,2,1032,1005,1032,58,1008,1033,3,1032,1005,1032,81,1008,1033,4,1032,1005,1032,104,99,1002,1034,1,1039,102,1,1036,1041,1001,1035,-1,1040,1008,1038,0,1043,102,-1,1043,1032,1,1037,1032,1042,1105,1,124,101,0,1034,1039,102,1,1036,1041,1001,1035,1,1040,1008,1038,0,1043,1,1037,1038,1042,1106,0,124,1001,1034,-1,1039,1008,1036,0,1041,1002,1035,1,1040,1001,1038,0,1043,101,0,1037,1042,1106,0,124,1001,1034,1,1039,1008,1036,0,1041,101,0,1035,1040,102,1,1038,1043,1002,1037,1,1042,1006,1039,217,1006,1040,217,1008,1039,40,1032,1005,1032,217,1008,1040,40,1032,1005,1032,217,1008,1039,35,1032,1006,1032,165,1008,1040,9,1032,1006,1032,165,1101,0,2,1044,1105,1,224,2,1041,1043,1032,1006,1032,179,1102,1,1,1044,1105,1,224,1,1041,1043,1032,1006,1032,217,1,1042,1043,1032,1001,1032,-1,1032,1002,1032,39,1032,1,1032,1039,1032,101,-1,1032,1032,101,252,1032,211,1007,0,26,1044,1105,1,224,1101,0,0,1044,1106,0,224,1006,1044,247,102,1,1039,1034,101,0,1040,1035,102,1,1041,1036,1002,1043,1,1038,1001,1042,0,1037,4,1044,1106,0,0,22,11,19,72,14,9,6,73,82,17,41,18,83,18,49,19,12,14,39,17,20,69,20,12,48,8,8,59,36,7,33,1,15,13,10,46,96,15,2,22,80,99,12,68,99,79,22,84,16,45,25,51,4,20,95,4,51,43,13,89,2,91,48,2,46,55,24,84,8,88,10,98,46,57,15,27,7,1,19,20,63,24,50,13,63,13,59,19,13,53,75,8,20,8,44,44,21,5,11,76,9,21,2,11,27,61,6,12,72,22,40,11,9,50,18,2,38,21,78,18,13,99,9,74,5,22,30,35,5,16,34,91,55,4,19,28,42,21,62,12,74,94,16,40,2,95,54,21,2,23,56,34,9,49,47,14,39,9,65,35,53,23,25,68,15,95,25,70,27,3,33,2,31,17,40,60,24,94,34,6,99,9,92,1,92,7,49,32,8,46,47,13,37,15,11,2,15,24,8,73,8,21,64,19,74,24,5,60,9,21,47,12,12,72,18,39,90,16,6,85,13,71,19,14,24,2,65,11,51,9,19,23,34,12,9,88,77,17,6,72,19,79,39,19,21,95,87,24,91,53,7,29,20,25,11,39,38,24,72,6,1,97,15,87,11,77,64,17,57,95,9,85,19,77,8,18,97,8,39,49,4,16,81,12,36,7,7,81,22,52,56,22,47,42,4,46,75,21,19,85,37,22,90,20,10,56,24,85,55,4,91,7,22,86,1,89,13,68,35,14,27,35,9,44,79,12,42,20,16,28,89,11,57,10,60,15,13,95,3,48,24,90,86,51,18,8,71,11,80,91,5,4,93,9,80,94,9,31,7,6,90,6,57,18,19,41,69,57,8,3,42,21,16,5,79,9,13,56,99,98,19,22,85,14,35,12,21,69,16,23,3,5,78,68,2,24,12,35,36,24,93,72,12,16,7,7,19,56,8,69,45,94,18,49,44,61,21,25,19,96,7,13,27,50,76,14,5,60,4,11,90,60,9,31,85,17,11,18,74,37,20,53,53,1,42,93,66,24,10,10,73,36,19,84,14,87,71,18,64,58,3,9,70,14,10,62,81,25,19,52,5,3,78,10,66,84,84,14,66,9,19,81,8,56,11,7,39,84,31,98,22,25,56,4,12,43,78,20,19,43,88,23,10,62,90,22,38,29,5,29,32,20,14,1,3,44,13,92,79,11,59,22,77,38,3,83,18,22,37,24,32,8,19,47,20,23,32,14,72,80,24,37,33,20,8,12,17,31,20,13,51,68,65,19,31,1,1,47,88,15,31,25,94,4,11,95,87,16,77,86,92,3,2,48,39,52,62,22,63,1,70,18,61,78,14,12,50,75,10,30,2,10,96,13,58,87,9,90,3,83,5,13,28,3,67,66,21,46,10,1,70,64,8,10,50,13,22,93,3,58,13,58,2,69,1,44,2,18,22,61,61,25,36,20,7,31,6,2,7,29,2,27,22,93,16,25,8,79,93,22,2,29,27,12,56,48,34,6,40,14,13,8,14,2,8,64,32,19,18,99,22,83,83,79,16,84,58,22,88,19,31,18,35,18,31,85,20,30,16,75,16,46,16,65,16,3,44,6,2,65,97,24,40,20,25,31,88,14,66,20,13,11,76,18,43,67,13,92,47,9,81,78,20,51,12,7,43,17,24,99,14,4,89,13,84,48,13,60,13,51,23,66,7,61,19,91,17,72,64,48,10,74,13,85,8,76,11,72,3,32,22,37,80,44,18,86,50,71,5,36,21,76,23,64,23,61,40,62,24,61,0,0,21,21,1,10,1,0,0,0,0,0,0
+106
2019/intcode.py
··· 1 + # True = read, False = write 2 + INSTRUCTIONS = { 3 + 1: ('ADD', (True, True, False)), 4 + 2: ('MUL', (True, True, False)), 5 + 3: ('INP', (False, None, None)), 6 + 4: ('OUT', (True, None, None)), 7 + 5: ('JZ ', (True, True, None)), 8 + 6: ('JNZ', (True, True, None)), 9 + 7: ('LT ', (True, True, False)), 10 + 8: ('EQ ', (True, True, False)), 11 + 9: ('REL', (True, None, None)), 12 + 99: ('HLT', (None, None, None)), 13 + } 14 + 15 + 16 + def parse_mode(tape, mode_op, a, b, c): 17 + op = mode_op % 100 18 + mode_a = (mode_op // 100) % 10 19 + mode_b = (mode_op // 1000) % 10 20 + mode_c = (mode_op // 10000) % 10 21 + 22 + return op, mode_a, mode_b, mode_c 23 + 24 + 25 + def emulate(tape, pid, GLOBAL_INPUTS, pc=0): 26 + tape = tape[:] 27 + relative_base = 0 28 + 29 + def resolve_modes(op, params, modes): 30 + res = [a, b, c] 31 + 32 + for i, (is_read, p, m) in enumerate(zip(INSTRUCTIONS[op][1], params, modes)): 33 + if is_read is None: 34 + continue 35 + 36 + if is_read: 37 + if m == 0: 38 + res[i] = tape[p] 39 + elif m == 1: 40 + res[i] = p 41 + elif m == 2: 42 + res[i] = tape[relative_base + p] 43 + else: 44 + if m == 0: 45 + res[i] = p 46 + elif m == 2: 47 + res[i] = relative_base + p 48 + 49 + return res 50 + 51 + while pc < len(tape): 52 + mode_op, a, b, c = tape[pc:pc+4] 53 + op, mode_a, mode_b, mode_c = parse_mode(tape, mode_op, a, b, c) 54 + a, b, c = resolve_modes(op, (a, b, c), (mode_a, mode_b, mode_c)) 55 + 56 + # ADD a b c 57 + if op == 1: 58 + tape[c] = a + b 59 + pc += 4 60 + 61 + # MUL a b c 62 + elif op == 2: 63 + tape[c] = a * b 64 + pc += 4 65 + 66 + # INP a 67 + elif op == 3: 68 + tape[a] = GLOBAL_INPUTS[pid] 69 + pc += 2 70 + 71 + # OUT b 72 + elif op == 4: 73 + yield a 74 + pc += 2 75 + 76 + # JZ a b 77 + elif op == 5: 78 + if a != 0: 79 + pc = b 80 + else: 81 + pc += 3 82 + 83 + # JNZ a b 84 + elif op == 6: 85 + if a == 0: 86 + pc = b 87 + else: 88 + pc += 3 89 + 90 + # LT a b c 91 + elif op == 7: 92 + tape[c] = 1 if a < b else 0 93 + pc += 4 94 + 95 + # EQ a b c 96 + elif op == 8: 97 + tape[c] = 1 if a == b else 0 98 + pc += 4 99 + 100 + elif op == 9: 101 + relative_base += a 102 + pc += 2 103 + 104 + # HALT 105 + elif op == 99: 106 + raise StopIteration()