From b48d6aaa5f4c51a91cc644b42cc53b6066d1e20c Mon Sep 17 00:00:00 2001 From: Daniel Flanagan Date: Tue, 8 Dec 2020 06:55:34 -0600 Subject: [PATCH] Cleanup and add day 8 part 2 --- 2020/src/aoc2020.nim | 4 +-- 2020/src/day7.nim | 8 ++--- 2020/src/day8.nim | 76 +++++++++++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 36 deletions(-) diff --git a/2020/src/aoc2020.nim b/2020/src/aoc2020.nim index 9908b30..9a16381 100644 --- a/2020/src/aoc2020.nim +++ b/2020/src/aoc2020.nim @@ -8,5 +8,5 @@ proc solve_for_day(n: int) {.used.} = echo solvers[n]() when isMainModule: - # solve_all() - solve_for_day(8) + solve_all() + # solve_for_day(8) diff --git a/2020/src/day7.nim b/2020/src/day7.nim index ed8f139..fa01789 100644 --- a/2020/src/day7.nim +++ b/2020/src/day7.nim @@ -7,6 +7,7 @@ nc <- {\d} ' ' c ' bag' 's'? ', '? c <- {\ident ' ' \ident} """ +let target = "shiny gold" iterator asParsed(s: Stream): (string, seq[string]) = for l in s.lines: if l =~ parser: @@ -17,10 +18,8 @@ iterator asParsed(s: Stream): (string, seq[string]) = proc walkUp(t: TableRef[string, HashSet[string]], tar: string): HashSet[string] = if t.contains(tar): let parents = t[tar] - echo parents result = parents for p in parents: - echo p result = result + t.walkUp(p) proc part1*(s: Stream): int = @@ -30,7 +29,7 @@ proc part1*(s: Stream): int = for p in parents: if t.contains(p): t[p].incl(key) else: t[p] = [key].toHashSet() - t.walkUp("shiny gold").len + t.walkUp(target).len proc walkDown(t: TableRef[string, TableRef[string, int]], tar: string): int = let children = t[tar] @@ -43,9 +42,8 @@ iterator asPairChunks(s: seq[string]): (string, int) = proc part2*(s: Stream): int = var t = newTable[string, TableRef[string, int]]() for (key, parsed) in s.asParsed: - echo key, parsed var innert = newTable[string, int]() for (innerkey, n) in parsed.asPairChunks: innert[innerkey] = n t[key] = innert - t.walkDown "shiny gold" + t.walkDown target diff --git a/2020/src/day8.nim b/2020/src/day8.nim index 5b327ee..da3eb4b 100644 --- a/2020/src/day8.nim +++ b/2020/src/day8.nim @@ -1,4 +1,4 @@ -import streams, strutils, sequtils, sets +import streams, strutils, sequtils, sets, options, strformat, tables type InstructionType = enum nop acc jmp @@ -9,48 +9,66 @@ type bootcode: seq[Instruction] acc: int pointer: int - running: bool -proc newHandheld(bootcode: seq[Instruction], acc = 0, pointer = 0, running = true): HandheldState = - HandheldState(bootcode: bootcode, acc: acc, pointer: pointer, running: running) +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) proc instructions(s: Stream): seq[Instruction] = toSeq(s.lines).mapIt(it.split).mapIt(Instruction(instruction: parseEnum[InstructionType](it[0]), arg: parseInt(it[1].replace("+")))) -proc stepHandheld(state: var HandheldState) = - if state.pointer >= state.bootcode.len: - echo "Reached end of instructions" - state.running = false +proc stepHandheld(state: var HandheldState): bool = + if state.pointer >= state.bootcode.len: return true let i = state.bootcode[state.pointer] case i.instruction: of acc: inc state.acc, i.arg - of jmp: inc state.pointer, i.arg; return + of jmp: inc state.pointer, i.arg; return false else: discard inc state.pointer +proc bootHandheld(h: var HandheldState): bool = + var hasRun = initHashSet[int]() + 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 hasRun = initHashSet[int]() - var handheld = newHandheld(s.instructions) - while handheld.running: - stepHandheld handheld - if hasRun.contains handheld.pointer: return handheld.acc - hasRun.incl handheld.pointer + var h = s.instructions.newHandheld + if not h.bootHandheld: return h.acc -proc correctingHandheld(state: var HandheldState) = - if state.pointer >= state.bootcode.len: - echo "Reached end of instructions" - state.running = false - let i = state.bootcode[state.pointer] - case i.instruction: - of acc: inc state.acc, i.arg - of jmp: inc state.pointer, i.arg; return +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 else: discard - inc state.pointer + nbc.newHandheld + +proc altHandheld(h: var HandheldState): Option[HandheldState] = + case h.bootcode[h.pointer].instruction: + of acc: return none(HandheldState) + of jmp, nop: some(h.flipped) proc part2*(s: Stream): int = + var alts = initTable[int, HandheldState]() + var h = s.instructions.newHandheld var hasRun = initHashSet[int]() - var handheld = newHandheld(s.instructions) - while handheld.running: - stepHandheld handheld - if hasRun.contains handheld.pointer: return handheld.acc - hasRun.incl handheld.pointer + 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..