mirror of
https://github.com/thib8956/advent-of-code.git
synced 2025-08-23 16:01:59 +00:00
2019 day 13
This commit is contained in:
@@ -60,6 +60,6 @@ if __name__ == "__main__":
|
|||||||
import fileinput
|
import fileinput
|
||||||
with fileinput.input() as f:
|
with fileinput.input() as f:
|
||||||
main(f, part=1)
|
main(f, part=1)
|
||||||
with fileinput.input() as f:
|
#with fileinput.input() as f:
|
||||||
#main(f, part=2) # FIXME unable to run both parts simultaneously
|
#main(f, part=2) # FIXME unable to run both parts simultaneously
|
||||||
|
|
||||||
|
117
2019/day13/day13.py
Normal file
117
2019/day13/day13.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# TODO replace PYTHONPATH hack with a proper solution, like making intcode an
|
||||||
|
# installed module https://stackoverflow.com/a/50194143
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from itertools import zip_longest
|
||||||
|
from pathlib import Path
|
||||||
|
from collections import defaultdict, Counter
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
sys.path.append(str(Path(__file__).absolute().parent.parent / "intcode"))
|
||||||
|
from intcode import interpret_intcode, Interpreter
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class State:
|
||||||
|
grid: ...
|
||||||
|
score = 0
|
||||||
|
bounds = None
|
||||||
|
paddle_pos = None
|
||||||
|
ball_pos = None
|
||||||
|
stopped = False
|
||||||
|
|
||||||
|
|
||||||
|
def grouper(n, iterable):
|
||||||
|
"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
|
||||||
|
args = [iter(iterable)] * n
|
||||||
|
return zip_longest(*args)
|
||||||
|
|
||||||
|
|
||||||
|
def part1(program):
|
||||||
|
interpreter = interpret_intcode(program)
|
||||||
|
game = { (x, y): tile for x, y, tile in grouper(3, interpreter.stdout) }
|
||||||
|
print("Part 1: ", len([x for x in game.values() if x == 2]))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_map(output):
|
||||||
|
grid = {}
|
||||||
|
score = None
|
||||||
|
for x, y, tile in grouper(3, output):
|
||||||
|
if (x, y) == (-1, 0):
|
||||||
|
score = tile
|
||||||
|
else:
|
||||||
|
grid[x,y] = tile
|
||||||
|
paddle = next((k for k, v in grid.items() if v == 3), None)
|
||||||
|
ball = next((k for k, v in grid.items() if v == 4), None)
|
||||||
|
bounds = (max(x for x, y in grid.keys()),
|
||||||
|
max(y for x, y in grid.keys()))
|
||||||
|
return grid, bounds, score, paddle, ball
|
||||||
|
|
||||||
|
|
||||||
|
def update_state(state: State, stdout):
|
||||||
|
grid, bounds, score, paddle, ball = parse_map(stdout)
|
||||||
|
if ball is None:
|
||||||
|
state.stopped = True
|
||||||
|
if state.bounds is None: # only set bounds the first time
|
||||||
|
state.bounds = bounds
|
||||||
|
if score is not None:
|
||||||
|
state.score = score
|
||||||
|
if paddle is not None:
|
||||||
|
state.paddle_pos = paddle
|
||||||
|
if ball is not None:
|
||||||
|
state.ball_pos = ball
|
||||||
|
if grid is None:
|
||||||
|
state.grid = grid
|
||||||
|
else:
|
||||||
|
# merge grid
|
||||||
|
for (x, y), v in grid.items():
|
||||||
|
state.grid[x,y] = v
|
||||||
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
def part2(program):
|
||||||
|
program[0] = 2
|
||||||
|
interpreter = Interpreter(program)
|
||||||
|
state = State({})
|
||||||
|
while not interpreter.halted:
|
||||||
|
interpreter.interpret(break_on_output=False, break_on_input=True)
|
||||||
|
state = update_state(state, interpreter.stdout)
|
||||||
|
if state.stopped:
|
||||||
|
break
|
||||||
|
#print_map(state)
|
||||||
|
interpreter.stdout.clear()
|
||||||
|
paddle_x, ball_x = state.paddle_pos[0], state.ball_pos[0]
|
||||||
|
if paddle_x < ball_x: # move right
|
||||||
|
interpreter.stdin.append(1)
|
||||||
|
elif paddle_x > ball_x: # move left
|
||||||
|
interpreter.stdin.append(-1)
|
||||||
|
else:
|
||||||
|
interpreter.stdin.append(0)
|
||||||
|
print("Part 2: ", state.score)
|
||||||
|
|
||||||
|
|
||||||
|
def print_map(state):
|
||||||
|
clear = "\033[2J"
|
||||||
|
tiles = { 0: " ", 1: "#", 2: "~", 3: "_", 4: "O" }
|
||||||
|
max_x, max_y = state.bounds
|
||||||
|
print(clear)
|
||||||
|
for y in range(max_y + 1):
|
||||||
|
l = []
|
||||||
|
for x in range(max_x + 1):
|
||||||
|
tile = state.grid[x,y]
|
||||||
|
l.append(tiles[tile])
|
||||||
|
print("".join(l))
|
||||||
|
time.sleep(1/60)
|
||||||
|
|
||||||
|
|
||||||
|
def main(inp):
|
||||||
|
program = [int(x) for x in inp.readline().rstrip().split(",")]
|
||||||
|
part1(program)
|
||||||
|
part2(program)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
infile = sys.argv[1] if len(sys.argv) > 1 else "example.txt"
|
||||||
|
with open(infile) as raw_input:
|
||||||
|
main(raw_input)
|
||||||
|
|
@@ -165,25 +165,26 @@ class Interpreter:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"Interpreter(ip={self.ip}, stdin={self.stdin}, stdout={self.stdout}, halted={self.halted})"
|
return f"Interpreter(ip={self.ip}, stdin={self.stdin}, stdout={self.stdout}, halted={self.halted})"
|
||||||
|
|
||||||
def next_instruction(self):
|
def interpret(self, break_on_input=False, break_on_output=True):
|
||||||
instruction = Instruction(self.memory, self.ip, self.base)
|
while not self.halted:
|
||||||
if instruction.operation == Operation.INPUT:
|
# fetch next instruction
|
||||||
instruction.input = self.stdin.pop(0)
|
instruction = Instruction(self.memory, self.ip, self.base)
|
||||||
self.ip = instruction.handle()
|
# pause if INP + break on input
|
||||||
self.base = instruction.base
|
if instruction.operation == Operation.INPUT:
|
||||||
logging.debug(f"IP {self.ip}")
|
if break_on_input and self.stdin == []:
|
||||||
if instruction.output is not None:
|
break
|
||||||
self.stdout.append(instruction.output)
|
else:
|
||||||
elif instruction.halted:
|
instruction.input = self.stdin.pop(0)
|
||||||
self.halted = True
|
# execute instruction
|
||||||
return instruction
|
self.ip = instruction.handle()
|
||||||
|
self.base = instruction.base
|
||||||
def interpret(self, break_on_output=True):
|
logging.debug(f"IP {self.ip}")
|
||||||
while instruction := self.next_instruction():
|
if instruction.output is not None:
|
||||||
if self.halted:
|
self.stdout.append(instruction.output)
|
||||||
break
|
if break_on_output:
|
||||||
if break_on_output and instruction.output is not None:
|
break
|
||||||
break
|
if instruction.halted:
|
||||||
|
self.halted = True
|
||||||
|
|
||||||
|
|
||||||
def interpret_intcode(program, stdin=[]):
|
def interpret_intcode(program, stdin=[]):
|
||||||
|
Reference in New Issue
Block a user