2019, take 2 #2

Open
aey wants to merge 19 commits from 2019-rerun into main
4 changed files with 158 additions and 45 deletions
Showing only changes of commit c51638fac1 - Show all commits

View file

@ -1,7 +1,7 @@
from output import answer, puzzleinput from output import answer, puzzleinput
from collections import defaultdict from collections import defaultdict
from output.intcode_computer import execute from output.intcode_computer import execute, parse
n = 2 n = 2
title = "1202 Program Alarm" title = "1202 Program Alarm"
@ -9,18 +9,18 @@ title = "1202 Program Alarm"
@puzzleinput(n) @puzzleinput(n)
def parse_input(data): def parse_input(data):
return list(map(int, data.split(","))) return parse(data)
@answer(1, "[intcode-0.1.0] Value of pos 0 is {} at halt signal") @answer(1, "[intcode-0.1.0] Value of pos 0 is {} at halt signal")
def part_1(program): def part_1(program):
state, _ = execute(program, noun=12, verb=2) _code, state, *_unused = execute(program, noun=12, verb=2)
return state[0] return state[0]
@answer(2, "[intcode-0.1.1] 100 * noun + verb = {} for output 19690720") @answer(2, "[intcode-0.1.1] 100 * noun + verb = {} for output 19690720")
def part_2(program, noun=76, verb=21): def part_2(program, noun=76, verb=21):
state, _ = execute(program, noun, verb) _code, state, *_unused = execute(program, noun, verb)
if state[0] == 19690720: if state[0] == 19690720:
return 100 * noun + verb return 100 * noun + verb
return state[0] return state[0]

View file

@ -1,6 +1,6 @@
from output import answer, puzzleinput from output import answer, puzzleinput
from output.intcode_computer import execute from output.intcode_computer import execute, parse
n = 5 n = 5
title = "Sunny with a Chance of Asteroids" title = "Sunny with a Chance of Asteroids"
@ -8,18 +8,18 @@ title = "Sunny with a Chance of Asteroids"
@puzzleinput(n) @puzzleinput(n)
def parse_input(data): def parse_input(data):
return list(map(int, data.split(","))) return parse(data)
@answer(1, "[intcode-0.2.0] Program diagnostic code, ID 1: {}") @answer(1, "[intcode-0.2.0] Program diagnostic code, ID 1: {}")
def part_1(program): def part_1(program):
_, stdout = execute(program, stdin=1) _code, _state, _cursorpos, stdout = execute(program, stdin=1)
return max(stdout) return max(stdout)
@answer(2, "[intcode-0.2.1] Program diagnostic code, ID 5: {}") @answer(2, "[intcode-0.2.1] Program diagnostic code, ID 5: {}")
def part_2(program): def part_2(program):
_, stdout = execute(program, stdin=5) _code, _state, _cursorpos, stdout = execute(program, stdin=5)
return stdout[0] return stdout[0]

View file

@ -0,0 +1,65 @@
from collections import defaultdict
from itertools import permutations
from output import answer, puzzleinput
from output.intcode_computer import execute, parse
n = 7
title = "Amplification Circuit"
@puzzleinput(n)
def parse_input(data):
return parse(data)
@answer(
1,
"[intcode 0.3.0] Given the phase settings [0, 3, 1, 2, 4], the highest achievable signal to the thruster is {}",
)
def part_1(program):
thruster_signals = []
for settings in map(list, permutations(range(5))):
o = 0
for ps in settings:
_code, _state, _n, so = execute(program, stdin=[ps, o])
o = so.pop(0)
thruster_signals.append(o)
return max(thruster_signals)
@answer(
2,
"[intcode 0.3.0] Given the phase settings [7, 8, 5, 9, 6] and creating feedback loop, the highest achievable signal to the thruster is {}",
)
def part_2(program):
thruster_signals = []
for settings in map(list, permutations(range(5, 10))):
o = [0]
finished = set()
paused = defaultdict(tuple)
while len(finished) < 5:
for amp, ps in enumerate(settings):
if paused[amp]:
program, resume_at = paused[amp]
del paused[amp]
code, state, n, so = execute(program, stdin=o, n=resume_at)
else:
code, state, n, so = execute(program, stdin=[ps, *o])
if code == 3:
paused[amp] = (
list(state.values()),
n,
)
o = so
if code == 99:
finished.add(amp)
o = so
thruster_signals.append(o[-1])
return max(thruster_signals)
if __name__ == "__main__":
parsed = parse_input()
part_1(parsed)
part_2(parsed)

View file

@ -1,13 +1,28 @@
from collections import defaultdict from collections import defaultdict
def execute(program, noun=None, verb=None, stdin=0, debug=False):
""" """
intcode computer, AoC 2019 intcode computer, AoC 2019
Changelog Changelog
========= =========
0.3.0
-----
Minor release (day 7 part 1-2).
BREAKING CHANGE: execute() now returns 4 values.
- now: exit code, state at halt, instruction position at halt, and captured stdout.
- before: final state, and captured stdout
Changes:
- Add support for a sequence of stdins
- Add interactive param to ask for manual (interactive) input on input opcode
- Add verbose param to show more output in interactive input mode
- Will now halt with code 3 (input) when input is required, stdin is empty and interactive input mode is not enabled
0.2.1 0.2.1
----- -----
@ -48,14 +63,37 @@ def execute(program, noun=None, verb=None, stdin=0, debug=False):
- Add operation 1: adds parameter 1 to parameter 2, store to parameter 3 position - Add operation 1: adds parameter 1 to parameter 2, store to parameter 3 position
- Add operation 2: multiply parameter 1 with parameter 2, store to parameter 3 position - Add operation 2: multiply parameter 1 with parameter 2, store to parameter 3 position
""" """
v = "0.2.3"
def parse(data):
return list(map(int, data.split(",")))
def execute(
program,
noun=None,
verb=None,
stdin=[],
debug=False,
interactive=False,
verbose=False,
n=0,
):
if verbose:
title = f"intcode computer, version {v}"
print("".join("=" for _ in title))
print(title)
print("".join("=" for _ in title))
state = dict(zip(range(len(program)), program)) state = dict(zip(range(len(program)), program))
if noun: if noun:
state[1] = noun state[1] = noun
if verb: if verb:
state[2] = verb state[2] = verb
n = 0
c = 0 c = 0
stdout = [] stdout = []
if not isinstance(stdin, list):
stdin = [stdin]
while True: while True:
instruction = state[n] instruction = state[n]
@ -83,7 +121,13 @@ def execute(program, noun=None, verb=None, stdin=0, debug=False):
print(f"{n}:{opcode} | {x} * {y} to {p}") print(f"{n}:{opcode} | {x} * {y} to {p}")
if opcode == 3: if opcode == 3:
p = state[n + 1] p = state[n + 1]
state[p] = stdin if stdin:
state[p] = stdin.pop(0)
else:
if interactive:
state[p] = int(input("> "))
else:
return 3, state, n, stdout
n += 2 n += 2
if debug: if debug:
print(f"{n}:{opcode} | {i} to {p}") print(f"{n}:{opcode} | {i} to {p}")
@ -92,6 +136,8 @@ def execute(program, noun=None, verb=None, stdin=0, debug=False):
x = a if modes[1] == "1" else state[a] x = a if modes[1] == "1" else state[a]
n += 2 n += 2
stdout.append(x) stdout.append(x)
if verbose:
print(x)
if debug: if debug:
print(f"{n}:{opcode} | {stdout}") print(f"{n}:{opcode} | {stdout}")
if opcode == 5: if opcode == 5:
@ -143,4 +189,6 @@ def execute(program, noun=None, verb=None, stdin=0, debug=False):
print(f"{c} instructions done, current pos: {n}") print(f"{c} instructions done, current pos: {n}")
# if c == 3: # if c == 3:
# break # break
return state, stdout if verbose:
title = f"intcode computer received SIGTERM"
return 99, state, n, stdout