This commit is contained in:
cupcakearmy 2020-12-08 16:41:03 +01:00
parent 791b94827e
commit 3a302d71c9
2 changed files with 78 additions and 0 deletions

15
solutions/8/README.md Normal file
View File

@ -0,0 +1,15 @@
# 8
Keep getting better! Today we write a little state machine, love it.
So firstly we remember what `oc` (Operation Counter) we have already visited and if so we simply stop and return the accumulator.
For I basically run the code many times, inverting `nop` to `jmp` and vice versa until i found a working instruction set.
<details>
<summary>Solutions</summary>
<ol>
<li>1087</li>
<li>780</li>
</ol>
</details>

View File

@ -0,0 +1,63 @@
from os.path import join, dirname
from typing import List, Optional, Set, Tuple
Instructions = List[Tuple[str, int]]
class VM:
def __init__(self, code: str) -> None:
instructionsRaw = code.strip().split('\n')
self.acc = 0
self.oc = 0
self.invert: Optional[int] = None
self.instructions: Instructions = []
for instruction in instructionsRaw:
op, value = instruction.split(' ')
self.instructions.append((op, int(value)))
def reset(self):
self.acc = 0
self.oc = 0
def exec(self):
op, value = self.instructions[self.oc]
if self.oc == self.invert:
op = 'jmp' if op == 'nop' else 'nop'
if op == 'nop':
self.oc += 1
elif op == 'acc':
self.acc += value
self.oc += 1
elif op == 'jmp':
self.oc += value
def run(self) -> Tuple[int, bool]:
self.reset()
already_visited: Set[int] = set()
m = len(self.instructions)
while True:
if self.oc in already_visited:
return (self.acc, True)
if not self.oc < m:
return (self.acc, False)
already_visited.add(self.oc)
self.exec()
def fix(self):
for i, instruction in enumerate(self.instructions):
op, _ = instruction
if op == 'nop' or op == 'jmp':
self.invert = i
acc, error = self.run()
if not error:
return acc
data = join(dirname(__file__), '../data.txt')
with open(data) as f:
vm = VM(f.read())
acc, err = vm.run()
print(acc)
print(vm.fix())