-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandheld.py
83 lines (70 loc) · 1.67 KB
/
handheld.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
import click
import io
import copy
from typing import List, Tuple
@click.command()
@click.argument('src', type=click.File('r'))
def main(src: io.TextIOBase):
# Read program
prog = []
for line in src:
line: str = line.strip()
if line == '':
continue
args = line.split(' ')
inst = (args[0], int(args[1]))
prog.append(inst)
print(run(prog))
# Find jmp/nop
inds = [
i
for i, inst
in enumerate(prog)
if inst[0] in {'jmp', 'nop'}
]
# Flip instructions, find first to fix program
for ind in inds:
mprog = copy.copy(prog)
mprog[ind] = (
'jmp' if mprog[ind][0] == 'nop' else 'nop',
mprog[ind][1],
)
term, acc = run(mprog)
if term:
print(term, acc)
exit(0)
exit(1)
def run(prog: List[Tuple[str, int]]) -> (bool, int):
pc = 0
acc = 0
# Instructions
def facc(arg: int):
nonlocal acc
acc += arg
def fjmp(arg: int):
nonlocal pc
pc += (arg - 1)
def fnop(_: int):
pass
isa = {
'acc': facc,
'jmp': fjmp,
'nop': fnop,
}
execs = {}
while True:
if execs.get(pc, 0) == 1: # before exec #2
return False, acc
execs[pc] = execs.get(pc, 0) + 1
inst = prog[pc]
isa[inst[0]](inst[1])
pc += 1
if pc > len(prog):
# OOB
return False, 0
if pc == len(prog):
# Terminates corect by executing first
# instruction after program.
return True, acc
if __name__ == '__main__':
main()