advent-of-code/2020/src/day8.nim

75 lines
2.4 KiB
Nim
Raw Normal View History

2020-12-08 06:55:34 -06:00
import streams, strutils, sequtils, sets, options, strformat, tables
2020-12-07 23:17:17 -06:00
type
InstructionType = enum nop acc jmp
2020-12-07 23:35:16 -06:00
Instruction = object
2020-12-07 23:17:17 -06:00
instruction: InstructionType
arg: int
2020-12-07 23:35:16 -06:00
HandheldState = object
bootcode: seq[Instruction]
acc: int
pointer: int
2020-12-08 06:55:34 -06:00
proc `$`(i: Instruction): string = return fmt"{i.instruction} {i.arg}"
proc `$`(h: HandheldState): string = return fmt"@{h.pointer} ({h.acc}): {h.bootcode}"
proc statusString(h: HandheldState): string =
let i = h.bootcode[h.pointer]
fmt"{h.pointer}: {i.instruction} {i.arg} ({h.acc})"
proc newHandheld(bootcode: seq[Instruction], acc = 0, pointer = 0): HandheldState =
HandheldState(bootcode: bootcode, acc: acc, pointer: pointer)
2020-12-07 23:17:17 -06:00
proc instructions(s: Stream): seq[Instruction] =
toSeq(s.lines).mapIt(it.split).mapIt(Instruction(instruction: parseEnum[InstructionType](it[0]), arg: parseInt(it[1].replace("+"))))
2020-12-08 06:55:34 -06:00
proc stepHandheld(state: var HandheldState): bool =
if state.pointer >= state.bootcode.len: return true
2020-12-07 23:35:16 -06:00
let i = state.bootcode[state.pointer]
case i.instruction:
of acc: inc state.acc, i.arg
2020-12-08 06:55:34 -06:00
of jmp: inc state.pointer, i.arg; return false
2020-12-07 23:35:16 -06:00
else: discard
inc state.pointer
2020-12-08 06:55:34 -06:00
proc bootHandheld(h: var HandheldState): bool =
2020-12-07 23:17:17 -06:00
var hasRun = initHashSet[int]()
2020-12-08 06:55:34 -06:00
while h.pointer <= h.bootcode.len:
if h.stepHandheld(): return true
if hasRun.contains h.pointer: return false
hasRun.incl h.pointer
true
proc part1*(s: Stream): int =
var h = s.instructions.newHandheld
if not h.bootHandheld: return h.acc
proc flipped(h: var HandheldState): HandheldState =
var nbc = h.bootcode.deepCopy
case h.bootcode[h.pointer].instruction:
of nop: nbc[h.pointer].instruction = jmp
of jmp: nbc[h.pointer].instruction = nop
2020-12-07 23:35:16 -06:00
else: discard
2020-12-08 06:55:34 -06:00
nbc.newHandheld
proc altHandheld(h: var HandheldState): Option[HandheldState] =
case h.bootcode[h.pointer].instruction:
of acc: return none(HandheldState)
2020-12-11 23:29:49 -06:00
of jmp, nop: return some(h.flipped)
2020-12-07 23:17:17 -06:00
proc part2*(s: Stream): int =
2020-12-08 06:55:34 -06:00
var alts = initTable[int, HandheldState]()
var h = s.instructions.newHandheld
2020-12-07 23:35:16 -06:00
var hasRun = initHashSet[int]()
2020-12-08 06:55:34 -06:00
while h.pointer <= h.bootcode.len:
var alt = h.altHandheld
if alt.isSome: alts[h.pointer] = alt.get
discard h.stepHandheld()
if hasRun.contains h.pointer: break
hasRun.incl h.pointer
#for i in 1..<alts.len:
var c = 0
for k,v in alts.pairs:
var ah = alts[k]
if ah.bootHandheld: return ah.acc
inc c