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:
|
else:
|
||||||
formatted = fmt_string.format(answer)
|
formatted = fmt_string.format(answer)
|
||||||
print(f"[part {part_index}] {formatted}")
|
print(f"[part {part_index}] {formatted}")
|
||||||
|
return answer
|
||||||
|
|
||||||
return wrapper_aoc
|
return wrapper_aoc
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ def parse_input(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):
|
||||||
_code, _state, _cursorpos, stdout = execute(program, stdin=1)
|
_code, _state, _cursorpos, rb, 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):
|
||||||
_code, _state, _cursorpos, stdout = execute(program, stdin=5)
|
_code, _state, _cursorpos, rb, stdout = execute(program, stdin=[5])
|
||||||
return stdout[0]
|
return stdout[0]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ def part_1(program):
|
||||||
for settings in map(list, permutations(range(5))):
|
for settings in map(list, permutations(range(5))):
|
||||||
o = 0
|
o = 0
|
||||||
for ps in settings:
|
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)
|
o = so.pop(0)
|
||||||
thruster_signals.append(o)
|
thruster_signals.append(o)
|
||||||
return max(thruster_signals)
|
return max(thruster_signals)
|
||||||
|
|
@ -43,9 +43,9 @@ def part_2(program):
|
||||||
if paused[amp]:
|
if paused[amp]:
|
||||||
program, resume_at = paused[amp]
|
program, resume_at = paused[amp]
|
||||||
del 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:
|
else:
|
||||||
code, state, n, so = execute(program, stdin=[ps, *o])
|
code, state, n, _rb, so = execute(program, stdin=[ps, *o])
|
||||||
if code == 3:
|
if code == 3:
|
||||||
paused[amp] = (
|
paused[amp] = (
|
||||||
list(state.values()),
|
list(state.values()),
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,13 @@ def parse_input(data):
|
||||||
|
|
||||||
@answer(1, "[intcode 0.3.1] BOOST keycode: {}")
|
@answer(1, "[intcode 0.3.1] BOOST keycode: {}")
|
||||||
def part_1(program):
|
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)
|
return outputs.pop(0)
|
||||||
|
|
||||||
|
|
||||||
@answer(2, "[intcode 0.3.1] Distress signal coordinates: {}")
|
@answer(2, "[intcode 0.3.1] Distress signal coordinates: {}")
|
||||||
def part_2(program):
|
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)
|
return outputs.pop(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ if __name__ == "__main__":
|
||||||
0,
|
0,
|
||||||
99,
|
99,
|
||||||
]
|
]
|
||||||
)[3] == [
|
)[4] == [
|
||||||
109,
|
109,
|
||||||
1,
|
1,
|
||||||
204,
|
204,
|
||||||
|
|
@ -60,20 +60,20 @@ if __name__ == "__main__":
|
||||||
0,
|
0,
|
||||||
99,
|
99,
|
||||||
]
|
]
|
||||||
assert len(str(execute([1102, 34915192, 34915192, 7, 4, 7, 99, 0])[3][0])) == 16
|
assert len(str(execute([1102, 34915192, 34915192, 7, 4, 7, 99, 0])[4][0])) == 16
|
||||||
assert 1125899906842624 in execute([104, 1125899906842624, 99])[3]
|
assert 1125899906842624 in execute([104, 1125899906842624, 99])[4]
|
||||||
assert execute([109, -1, 4, 1, 99])[3][0] == -1
|
assert execute([109, -1, 4, 1, 99])[4][0] == -1
|
||||||
assert execute([109, -1, 104, 1, 99])[3][0] == 1
|
assert execute([109, -1, 104, 1, 99])[4][0] == 1
|
||||||
assert execute([109, -1, 204, 1, 99])[3][0] == 109
|
assert execute([109, -1, 204, 1, 99])[4][0] == 109
|
||||||
assert execute([109, 1, 9, 2, 204, -6, 99])[3][0] == 204
|
assert execute([109, 1, 9, 2, 204, -6, 99])[4][0] == 204
|
||||||
assert execute([109, 1, 109, 9, 204, -6, 99])[3][0] == 204
|
assert execute([109, 1, 109, 9, 204, -6, 99])[4][0] == 204
|
||||||
assert execute([109, 1, 209, -1, 204, -106, 99])[3][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])[3][0] == 666
|
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])[3][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])[3][0] == 74
|
assert execute([109, 6, 21001, 9, 25, 1, 104, 0, 99, 49])[4][0] == 74
|
||||||
|
|
||||||
parsed = parse_input()
|
parsed = parse_input()
|
||||||
assert execute(parsed, stdin=[1])[3][0] == 2351176124
|
assert execute(parsed, stdin=[1])[4][0] == 2351176124
|
||||||
|
|
||||||
part_1(parsed)
|
part_1(parsed)
|
||||||
part_2(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
|
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
|
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 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
|
||||||
"""
|
"""
|
||||||
__version__ = "0.3.1"
|
__version__ = "0.3.2"
|
||||||
|
|
||||||
|
|
||||||
def parse(data):
|
def parse(data):
|
||||||
|
|
@ -87,61 +96,42 @@ def execute(
|
||||||
interactive=False,
|
interactive=False,
|
||||||
verbose=False,
|
verbose=False,
|
||||||
n=0,
|
n=0,
|
||||||
|
rb=0,
|
||||||
):
|
):
|
||||||
if verbose:
|
if verbose:
|
||||||
title = f"intcode computer, version {v}"
|
title = f"intcode computer, version {__version__}"
|
||||||
print("".join("=" for _ in title))
|
print("".join("=" for _ in title))
|
||||||
print(title)
|
print(title)
|
||||||
print("".join("=" for _ in title))
|
print("".join("=" for _ in title))
|
||||||
state = defaultdict(int)
|
state = defaultdict(int)
|
||||||
for k, v in zip(range(len(program)), program):
|
if isinstance(program, list):
|
||||||
state[k] = v
|
for k, v in zip(range(len(program)), program):
|
||||||
|
state[k] = v
|
||||||
|
else:
|
||||||
|
state = program.copy()
|
||||||
if noun:
|
if noun:
|
||||||
state[1] = noun
|
state[1] = noun
|
||||||
if verb:
|
if verb:
|
||||||
state[2] = verb
|
state[2] = verb
|
||||||
c = 0
|
|
||||||
rb = 0
|
|
||||||
stdout = []
|
stdout = []
|
||||||
if not isinstance(stdin, list):
|
|
||||||
stdin = [stdin]
|
|
||||||
|
|
||||||
def halt(code):
|
def halt(code):
|
||||||
return code, state, n, stdout
|
return code, state, n, rb, 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])
|
|
||||||
|
|
||||||
|
if debug and n > 0:
|
||||||
|
print(f"@{str(n).zfill(4)} [resuming program, stdin={stdin}]")
|
||||||
while True:
|
while True:
|
||||||
instruction = state[n]
|
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
|
opcode = instruction % 100
|
||||||
modes = str(instruction // 100).zfill(3)[::-1]
|
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:
|
if opcode == 1:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
c = n + 3
|
c = n + 3
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
p = state[c]
|
p = state[c]
|
||||||
if modes[2] == "2":
|
if modes[2] == "2":
|
||||||
p += rb
|
p += rb
|
||||||
|
|
@ -153,7 +143,7 @@ def execute(
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
c = n + 3
|
c = n + 3
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
p = state[c]
|
p = state[c]
|
||||||
if modes[2] == "2":
|
if modes[2] == "2":
|
||||||
p += rb
|
p += rb
|
||||||
|
|
@ -174,15 +164,17 @@ def execute(
|
||||||
state[p] = stdin.pop(0)
|
state[p] = stdin.pop(0)
|
||||||
else:
|
else:
|
||||||
if interactive:
|
if interactive:
|
||||||
state[p] = int(input("> "))
|
manual = int(input("> "))
|
||||||
|
state[p] = manual
|
||||||
|
print(f"set STDIN to {manual} at pos {p}")
|
||||||
else:
|
else:
|
||||||
if debug:
|
if debug:
|
||||||
print(f"@{str(n).zfill(4)} [suspended, awaiting input]")
|
print(f"@{str(n).zfill(4)} [suspended, awaiting input ...]")
|
||||||
return halt(3)
|
return halt(3)
|
||||||
n += 2
|
n += 2
|
||||||
if opcode == 4:
|
if opcode == 4:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
x = values(modes, a)
|
x = _values(state, modes, rb, a)
|
||||||
stdout.append(x)
|
stdout.append(x)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(x)
|
print(x)
|
||||||
|
|
@ -192,7 +184,7 @@ def execute(
|
||||||
if opcode == 5:
|
if opcode == 5:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
if x != 0:
|
if x != 0:
|
||||||
if debug:
|
if debug:
|
||||||
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-1 | {x} != 0, n={y}")
|
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-1 | {x} != 0, n={y}")
|
||||||
|
|
@ -204,18 +196,20 @@ def execute(
|
||||||
if opcode == 6:
|
if opcode == 6:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
if x == 0:
|
if x == 0:
|
||||||
|
if debug:
|
||||||
|
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-0 | {x} == 0, n={y}")
|
||||||
n = y
|
n = y
|
||||||
else:
|
else:
|
||||||
|
if debug:
|
||||||
|
print(f"@{str(n).zfill(4)} {opcode}_JMP-IF-0 | {x} == 0, ignoring")
|
||||||
n += 3
|
n += 3
|
||||||
if debug:
|
|
||||||
print(f"{n}:{opcode} | {n}")
|
|
||||||
if opcode == 7:
|
if opcode == 7:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
c = n + 3
|
c = n + 3
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
p = state[c]
|
p = state[c]
|
||||||
if modes[2] == "2":
|
if modes[2] == "2":
|
||||||
p += rb
|
p += rb
|
||||||
|
|
@ -227,7 +221,7 @@ def execute(
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
b = state[n + 2]
|
b = state[n + 2]
|
||||||
c = n + 3
|
c = n + 3
|
||||||
x, y = values(modes, a, b)
|
x, y = _values(state, modes, rb, a, b)
|
||||||
p = state[c]
|
p = state[c]
|
||||||
if modes[2] == "2":
|
if modes[2] == "2":
|
||||||
p += rb
|
p += rb
|
||||||
|
|
@ -237,18 +231,35 @@ def execute(
|
||||||
n += 4
|
n += 4
|
||||||
if opcode == 9:
|
if opcode == 9:
|
||||||
a = state[n + 1]
|
a = state[n + 1]
|
||||||
x = values(modes, a)
|
x = _values(state, modes, rb, a)
|
||||||
if debug:
|
if debug:
|
||||||
print(f"@{str(n).zfill(4)} {opcode}_RELBASE | {rb} + {x}")
|
print(f"@{str(n).zfill(4)} {opcode}_RELBASE | {rb} + {x}")
|
||||||
rb += x
|
rb += x
|
||||||
n += 2
|
n += 2
|
||||||
if opcode == 99:
|
if opcode == 99:
|
||||||
break
|
if debug:
|
||||||
c += 1
|
print(f"@{str(n).zfill(4)} {opcode}_HALT | n={n}")
|
||||||
if debug and c % 1000 == 0:
|
return halt(99)
|
||||||
print(f"{c} instructions done, current pos: {n}")
|
return halt(-1)
|
||||||
if c == 33:
|
|
||||||
break
|
|
||||||
if verbose:
|
def _values(state, modes, rb, *parameters):
|
||||||
title = f"intcode computer received SIGTERM"
|
# for i, v in enumerate(parameters):
|
||||||
return halt(99)
|
# 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