Solve 2019:11 "Space Police"
Bugs discovered in intcode: - Relative base was reset on await input suspend. - No handling for incorrect intcodes. - State was sometimes corrupted when resumed after suspend. Fixed and Patched in 0.3.2
This commit is contained in:
parent
262ad34c51
commit
f98545ae5a
6 changed files with 168 additions and 74 deletions
|
|
@ -33,6 +33,7 @@ def answer(part_index, fmt_string):
|
|||
else:
|
||||
formatted = fmt_string.format(answer)
|
||||
print(f"[part {part_index}] {formatted}")
|
||||
return answer
|
||||
|
||||
return wrapper_aoc
|
||||
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ def parse_input(data):
|
|||
|
||||
@answer(1, "[intcode-0.2.0] Program diagnostic code, ID 1: {}")
|
||||
def part_1(program):
|
||||
_code, _state, _cursorpos, stdout = execute(program, stdin=1)
|
||||
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[1])
|
||||
return max(stdout)
|
||||
|
||||
|
||||
@answer(2, "[intcode-0.2.1] Program diagnostic code, ID 5: {}")
|
||||
def part_2(program):
|
||||
_code, _state, _cursorpos, stdout = execute(program, stdin=5)
|
||||
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[5])
|
||||
return stdout[0]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def part_1(program):
|
|||
for settings in map(list, permutations(range(5))):
|
||||
o = 0
|
||||
for ps in settings:
|
||||
_code, _state, _n, so = execute(program, stdin=[ps, o])
|
||||
_code, _state, _n, _rb, so = execute(program, stdin=[ps, o])
|
||||
o = so.pop(0)
|
||||
thruster_signals.append(o)
|
||||
return max(thruster_signals)
|
||||
|
|
@ -43,9 +43,9 @@ def part_2(program):
|
|||
if paused[amp]:
|
||||
program, resume_at = paused[amp]
|
||||
del paused[amp]
|
||||
code, state, n, so = execute(program, stdin=o, n=resume_at)
|
||||
code, state, n, _rb, so = execute(program, stdin=o, n=resume_at)
|
||||
else:
|
||||
code, state, n, so = execute(program, stdin=[ps, *o])
|
||||
code, state, n, _rb, so = execute(program, stdin=[ps, *o])
|
||||
if code == 3:
|
||||
paused[amp] = (
|
||||
list(state.values()),
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ def parse_input(data):
|
|||
|
||||
@answer(1, "[intcode 0.3.1] BOOST keycode: {}")
|
||||
def part_1(program):
|
||||
_c, _s, _n, outputs = execute(program, stdin=[1])
|
||||
_c, _s, _n, _rb, outputs = execute(program, stdin=[1])
|
||||
return outputs.pop(0)
|
||||
|
||||
|
||||
@answer(2, "[intcode 0.3.1] Distress signal coordinates: {}")
|
||||
def part_2(program):
|
||||
_c, _s, _n, outputs = execute(program, stdin=[2])
|
||||
_c, _s, _n, _rb, outputs = execute(program, stdin=[2])
|
||||
return outputs.pop(0)
|
||||
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ if __name__ == "__main__":
|
|||
0,
|
||||
99,
|
||||
]
|
||||
)[3] == [
|
||||
)[4] == [
|
||||
109,
|
||||
1,
|
||||
204,
|
||||
|
|
@ -60,20 +60,20 @@ if __name__ == "__main__":
|
|||
0,
|
||||
99,
|
||||
]
|
||||
assert len(str(execute([1102, 34915192, 34915192, 7, 4, 7, 99, 0])[3][0])) == 16
|
||||
assert 1125899906842624 in execute([104, 1125899906842624, 99])[3]
|
||||
assert execute([109, -1, 4, 1, 99])[3][0] == -1
|
||||
assert execute([109, -1, 104, 1, 99])[3][0] == 1
|
||||
assert execute([109, -1, 204, 1, 99])[3][0] == 109
|
||||
assert execute([109, 1, 9, 2, 204, -6, 99])[3][0] == 204
|
||||
assert execute([109, 1, 109, 9, 204, -6, 99])[3][0] == 204
|
||||
assert execute([109, 1, 209, -1, 204, -106, 99])[3][0] == 204
|
||||
assert execute([109, 1, 3, 3, 204, 2, 99], stdin=[666])[3][0] == 666
|
||||
assert execute([109, 1, 203, 2, 204, 2, 99], stdin=[666])[3][0] == 666
|
||||
assert execute([109, 6, 21001, 9, 25, 1, 104, 0, 99, 49])[3][0] == 74
|
||||
assert len(str(execute([1102, 34915192, 34915192, 7, 4, 7, 99, 0])[4][0])) == 16
|
||||
assert 1125899906842624 in execute([104, 1125899906842624, 99])[4]
|
||||
assert execute([109, -1, 4, 1, 99])[4][0] == -1
|
||||
assert execute([109, -1, 104, 1, 99])[4][0] == 1
|
||||
assert execute([109, -1, 204, 1, 99])[4][0] == 109
|
||||
assert execute([109, 1, 9, 2, 204, -6, 99])[4][0] == 204
|
||||
assert execute([109, 1, 109, 9, 204, -6, 99])[4][0] == 204
|
||||
assert execute([109, 1, 209, -1, 204, -106, 99])[4][0] == 204
|
||||
assert execute([109, 1, 3, 3, 204, 2, 99], stdin=[666])[4][0] == 666
|
||||
assert execute([109, 1, 203, 2, 204, 2, 99], stdin=[666])[4][0] == 666
|
||||
assert execute([109, 6, 21001, 9, 25, 1, 104, 0, 99, 49])[4][0] == 74
|
||||
|
||||
parsed = parse_input()
|
||||
assert execute(parsed, stdin=[1])[3][0] == 2351176124
|
||||
assert execute(parsed, stdin=[1])[4][0] == 2351176124
|
||||
|
||||
part_1(parsed)
|
||||
part_2(parsed)
|
||||
|
|
|
|||
82
2019-python/output/day_11.py
Normal file
82
2019-python/output/day_11.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
from collections import defaultdict
|
||||
from output.intcode_computer import execute, parse
|
||||
from output import answer, puzzleinput
|
||||
|
||||
n = 11
|
||||
title = "Space Police"
|
||||
|
||||
|
||||
@puzzleinput(n)
|
||||
def parse_input(data):
|
||||
return parse(data)
|
||||
|
||||
|
||||
DIRS = [
|
||||
(-1, 0),
|
||||
(0, -1),
|
||||
(1, 0),
|
||||
(0, 1),
|
||||
]
|
||||
|
||||
COLORS = [".", "#"]
|
||||
|
||||
CL = ["black", "white"]
|
||||
DL = ["UP", "LEFT", "BOTTOM", "RIGHT"]
|
||||
TL = ["RIGHT", "LEFT"]
|
||||
|
||||
|
||||
@answer(1, "[intcode 0.3.2] Robot paints {} panes at least once")
|
||||
def part_1(program):
|
||||
path, pos, d = _paint(program)
|
||||
return len(path)
|
||||
|
||||
|
||||
@answer(
|
||||
2,
|
||||
'[intcode 0.3.2] The hull has registration identifier "JZPJRAGJ" freshly painted, see below: \n\n{}',
|
||||
)
|
||||
def part_2(program):
|
||||
path, pos, d = _paint(program, 1)
|
||||
return _inspect(path.copy(), pos, d)
|
||||
|
||||
|
||||
def _paint(program, initial=0):
|
||||
pos = (0, 0)
|
||||
d = 0
|
||||
path = defaultdict(int)
|
||||
path[pos] = initial
|
||||
n = 0
|
||||
rb = 0
|
||||
code = 0
|
||||
while True:
|
||||
code, program, n, rb, outputs = execute(program, n=n, rb=rb, stdin=[path[pos]])
|
||||
if code == 99:
|
||||
break
|
||||
if outputs:
|
||||
paint, turn_to = outputs
|
||||
path[pos] = paint
|
||||
d = (d - 1 if turn_to == 1 else d + 1) % 4
|
||||
pos = (pos[0] + DIRS[d][0], pos[1] + DIRS[d][1])
|
||||
return path, pos, d
|
||||
|
||||
|
||||
def _inspect(path, p, d):
|
||||
pk = path.keys()
|
||||
startx = min(map(lambda yx: yx[1], pk)) - 1
|
||||
endx = max(map(lambda yx: yx[1], pk)) + 2
|
||||
starty = min(map(lambda yx: yx[0], pk)) - 1
|
||||
endy = max(map(lambda yx: yx[0], pk)) + 2
|
||||
|
||||
matrix = [
|
||||
[COLORS[path[(y, x)]] for x in range(startx, endx)] for y in range(starty, endy)
|
||||
]
|
||||
y, x = p
|
||||
matrix[abs(starty) + y][abs(startx) + x] = "^<v>"[d]
|
||||
|
||||
return "\n".join(["".join(line) for line in matrix])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parsed = parse_input()
|
||||
part_1(parsed)
|
||||
part_2(parsed) # JZPJRAGJ
|
||||
|
|
@ -7,6 +7,15 @@ intcode computer, AoC 2019
|
|||
Changelog
|
||||
=========
|
||||
|
||||
0.3.2
|
||||
-----
|
||||
|
||||
Patch release (day 9 part 1-2, day 11 part 1-2).
|
||||
|
||||
- Return relative base upon input suspension
|
||||
- Improve intcode debugger
|
||||
- Fix errorous state restoration upon resuming upon input
|
||||
|
||||
0.3.1
|
||||
-----
|
||||
|
||||
|
|
@ -71,7 +80,7 @@ Initial version (day 2 part 1).
|
|||
- 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
|
||||
"""
|
||||
__version__ = "0.3.1"
|
||||
__version__ = "0.3.2"
|
||||
|
||||
|
||||
def parse(data):
|
||||
|
|
@ -87,61 +96,42 @@ def execute(
|
|||
interactive=False,
|
||||
verbose=False,
|
||||
n=0,
|
||||
rb=0,
|
||||
):
|
||||
if verbose:
|
||||
title = f"intcode computer, version {v}"
|
||||
title = f"intcode computer, version {__version__}"
|
||||
print("".join("=" for _ in title))
|
||||
print(title)
|
||||
print("".join("=" for _ in title))
|
||||
state = defaultdict(int)
|
||||
for k, v in zip(range(len(program)), program):
|
||||
state[k] = v
|
||||
if isinstance(program, list):
|
||||
for k, v in zip(range(len(program)), program):
|
||||
state[k] = v
|
||||
else:
|
||||
state = program.copy()
|
||||
if noun:
|
||||
state[1] = noun
|
||||
if verb:
|
||||
state[2] = verb
|
||||
c = 0
|
||||
rb = 0
|
||||
stdout = []
|
||||
if not isinstance(stdin, list):
|
||||
stdin = [stdin]
|
||||
|
||||
def halt(code):
|
||||
return code, state, n, stdout
|
||||
|
||||
def values(modes, *parameters):
|
||||
for i, v in enumerate(parameters):
|
||||
if modes[i] == "0" and v < 0:
|
||||
print("================ ERROR =================")
|
||||
print("Negative index provided to position mode")
|
||||
if modes[i] == "2" and rb + v < 0:
|
||||
print("================ ERROR =================")
|
||||
print("Negative index provided to relative mode")
|
||||
|
||||
def value(i, v):
|
||||
if modes[i] == "1":
|
||||
return v
|
||||
if modes[i] == "2":
|
||||
return state[v + rb]
|
||||
return state[v]
|
||||
|
||||
if len(parameters) > 1:
|
||||
return [value(i, v) for i, v in enumerate(parameters)]
|
||||
return value(0, parameters[0])
|
||||
return code, state, n, rb, stdout
|
||||
|
||||
if debug and n > 0:
|
||||
print(f"@{str(n).zfill(4)} [resuming program, stdin={stdin}]")
|
||||
while True:
|
||||
instruction = state[n]
|
||||
# if instruction > 200 and instruction < 1000:
|
||||
# print("")
|
||||
# spn = 2 if instruction % 100 % 3 == 0 else 4
|
||||
# print(list(state.values())[n : n + spn])
|
||||
opcode = instruction % 100
|
||||
modes = str(instruction // 100).zfill(3)[::-1]
|
||||
if opcode not in (1, 2, 3, 4, 5, 6, 7, 8, 9, 99):
|
||||
print("opcode={opcode} not implemented, halting")
|
||||
return halt(-2)
|
||||
if opcode == 1:
|
||||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
c = n + 3
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
p = state[c]
|
||||
if modes[2] == "2":
|
||||
p += rb
|
||||
|
|
@ -153,7 +143,7 @@ def execute(
|
|||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
c = n + 3
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
p = state[c]
|
||||
if modes[2] == "2":
|
||||
p += rb
|
||||
|
|
@ -174,15 +164,17 @@ def execute(
|
|||
state[p] = stdin.pop(0)
|
||||
else:
|
||||
if interactive:
|
||||
state[p] = int(input("> "))
|
||||
manual = int(input("> "))
|
||||
state[p] = manual
|
||||
print(f"set STDIN to {manual} at pos {p}")
|
||||
else:
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} [suspended, awaiting input]")
|
||||
print(f"@{str(n).zfill(4)} [suspended, awaiting input ...]")
|
||||
return halt(3)
|
||||
n += 2
|
||||
if opcode == 4:
|
||||
a = state[n + 1]
|
||||
x = values(modes, a)
|
||||
x = _values(state, modes, rb, a)
|
||||
stdout.append(x)
|
||||
if verbose:
|
||||
print(x)
|
||||
|
|
@ -192,7 +184,7 @@ def execute(
|
|||
if opcode == 5:
|
||||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
if x != 0:
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-1 | {x} != 0, n={y}")
|
||||
|
|
@ -204,18 +196,20 @@ def execute(
|
|||
if opcode == 6:
|
||||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
if x == 0:
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-0 | {x} == 0, n={y}")
|
||||
n = y
|
||||
else:
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-0 | {x} == 0, ignoring")
|
||||
n += 3
|
||||
if debug:
|
||||
print(f"{n}:{opcode} | {n}")
|
||||
if opcode == 7:
|
||||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
c = n + 3
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
p = state[c]
|
||||
if modes[2] == "2":
|
||||
p += rb
|
||||
|
|
@ -227,7 +221,7 @@ def execute(
|
|||
a = state[n + 1]
|
||||
b = state[n + 2]
|
||||
c = n + 3
|
||||
x, y = values(modes, a, b)
|
||||
x, y = _values(state, modes, rb, a, b)
|
||||
p = state[c]
|
||||
if modes[2] == "2":
|
||||
p += rb
|
||||
|
|
@ -237,18 +231,35 @@ def execute(
|
|||
n += 4
|
||||
if opcode == 9:
|
||||
a = state[n + 1]
|
||||
x = values(modes, a)
|
||||
x = _values(state, modes, rb, a)
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} {opcode}_RELBASE | {rb} + {x}")
|
||||
rb += x
|
||||
n += 2
|
||||
if opcode == 99:
|
||||
break
|
||||
c += 1
|
||||
if debug and c % 1000 == 0:
|
||||
print(f"{c} instructions done, current pos: {n}")
|
||||
if c == 33:
|
||||
break
|
||||
if verbose:
|
||||
title = f"intcode computer received SIGTERM"
|
||||
return halt(99)
|
||||
if debug:
|
||||
print(f"@{str(n).zfill(4)} {opcode}_HALT | n={n}")
|
||||
return halt(99)
|
||||
return halt(-1)
|
||||
|
||||
|
||||
def _values(state, modes, rb, *parameters):
|
||||
# for i, v in enumerate(parameters):
|
||||
# if modes[i] == "0" and v < 0:
|
||||
# print("================ ERROR =================")
|
||||
# print("Negative index provided to position mode")
|
||||
# if modes[i] == "2" and rb + v < 0:
|
||||
# print("================ ERROR =================")
|
||||
# print("Negative index provided to relative mode")
|
||||
|
||||
if len(parameters) > 1:
|
||||
return [_value(state, modes, rb, k, v) for k, v in enumerate(parameters)]
|
||||
return _value(state, modes, rb, 0, parameters[0])
|
||||
|
||||
|
||||
def _value(state, modes, rb, m, s):
|
||||
if modes[m] == "1":
|
||||
return s
|
||||
if modes[m] == "2":
|
||||
return state[s + rb]
|
||||
return state[s]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue