-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrwhite_13.py
110 lines (98 loc) · 3.67 KB
/
rwhite_13.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from operator import add, mul, lt, eq
from collections import defaultdict
from functools import wraps
from typing import List, Dict, Tuple
from rwhite_intcode import Intcode, WAITING_FOR_INPUT
# WAITING_FOR_INPUT = object()
def coroutine(gen):
@wraps(gen)
def start(*args, **kwargs):
g = gen(*args, **kwargs)
next(g)
return g
return start
# @coroutine
def run_program(state: List[int]):
def get_value(pntr, mode):
if mode == 0:
ret = memory[pntr]
if mode == 1:
ret = pntr
if mode == 2:
ret = memory[pntr+relative_base]
return ret
two_param_operations = {
1: add,
2: mul,
7: lt,
8: eq,
}
pointer_position = 0
relative_base = 0
op_params = (0, 3, 3, 1, 1, 2, 2, 3, 3, 1)
memory: Dict[int, int] = defaultdict(int) # Keeps me from guessing as to how much memory expansion I need to do.
memory.update(enumerate(state)) # Fastest way to convert a list into a dictionary and keep the indicies in order.
while memory[pointer_position] != 99:
# Get the current opcode, and storage location
opcode = f'{memory[pointer_position]:05d}'
op = int(opcode[-2:])
modes = [int(c) for c in opcode[:-2]][::-1]
param_count = op_params[op]
storage_position = memory[pointer_position+param_count] if modes[param_count-1] == 0 else memory[pointer_position+param_count] + relative_base
# Advance the pointer by 1 so we can start processing parameters.
pointer_position += 1
parameters = [get_value(memory[idx], mode) for idx, mode in zip(range(pointer_position, pointer_position+param_count), modes)]
if op in (1, 2, 7, 8): # 2 parameters
memory[storage_position] = int(two_param_operations[op](parameters[0], parameters[1]))
elif op == 3: # input
# yield WAITING_FOR_INPUT
memory[storage_position] = yield WAITING_FOR_INPUT
elif op == 4: # output
yield parameters[0]
elif op == 9: # update offset
relative_base += parameters[0]
elif (op == 5 and parameters[0]) or (op == 6 and not parameters[0]): # Jumps
pointer_position = parameters[1]
continue # We want to avoid incrementing the pointer position because we did a jump
pointer_position += param_count # Advance pointer to next opcode
return memory[0]
data = [int(v) for v in open('day_13.input').read().split(',')]
def run_game(data: List[int]):
grid: Dict[Tuple[int, int], int] = defaultdict(int)
game = Intcode(data[:]).run_until_input()
screen = [game[i:i+3] for i in range(0, len(game), 3)]
for x, y, typ in screen:
grid[(x, y)] = typ
return grid
grid = run_game(data[:])
print(list(grid.values()).count(2))
def free_play(data: List[int]):
data[0] = 2
game = Intcode(data[:])
ball_pos = (0, 0)
padd_pos = (0, 0)
state: List[int] = []
grid: Dict[Tuple[int, int], int] = defaultdict(int)
while True:
if ball_pos[0] < padd_pos[0]:
move = -1
elif ball_pos[0] > padd_pos[0]:
move = 1
else:
move = 0
new_state = game.run_until_input(move)
if None in new_state:
break
state[:] = new_state
coords = [state[i:i+3] for i in range(0, len(state), 3)]
for idx in range(0, len(state), 3):
x, y, typ = state[idx:idx+3]
if x == -1:
continue
elif typ == 4:
ball_pos = (x, y)
elif typ == 3:
padd_pos = (x, y)
grid[x, y] = typ
return state[-1]
print(free_play(data[:]))