Broken 2023 Day 20
This commit is contained in:
parent
577b747c74
commit
3feb0134ee
1 changed files with 165 additions and 0 deletions
165
2023/day20.nim
Normal file
165
2023/day20.nim
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
import std/algorithm
|
||||||
|
import std/bitops
|
||||||
|
import std/deques
|
||||||
|
import std/enumerate
|
||||||
|
import std/heapqueue
|
||||||
|
import std/math
|
||||||
|
import std/options
|
||||||
|
import std/sequtils
|
||||||
|
import std/sets
|
||||||
|
import std/strscans
|
||||||
|
import std/strutils
|
||||||
|
import std/sugar
|
||||||
|
import std/tables
|
||||||
|
import std/terminal
|
||||||
|
import std/times
|
||||||
|
|
||||||
|
proc dbg[T](v: T): T = (echo(v); v)
|
||||||
|
|
||||||
|
func empty[T](v: seq[T]): bool = v.len == 0
|
||||||
|
|
||||||
|
proc split[T](v: seq[T], pred: proc(elt: T): bool {.noSideEffect.}): seq[seq[T]] =
|
||||||
|
var current: seq[T]
|
||||||
|
for elt in v:
|
||||||
|
if pred(elt):
|
||||||
|
result.add current
|
||||||
|
current = @[]
|
||||||
|
else:
|
||||||
|
current.add elt
|
||||||
|
result.add current
|
||||||
|
|
||||||
|
func join[T](parts: seq[seq[T]], sep: T): seq[T] =
|
||||||
|
if parts.len > 0:
|
||||||
|
result &= parts[0]
|
||||||
|
|
||||||
|
for part in parts[1..^1]:
|
||||||
|
result.add sep
|
||||||
|
result &= part
|
||||||
|
|
||||||
|
###################
|
||||||
|
|
||||||
|
type Pulse = enum
|
||||||
|
High
|
||||||
|
Low
|
||||||
|
|
||||||
|
# Something about how I'm defining these objects and methods is very wrong.
|
||||||
|
#
|
||||||
|
# Depending on how much of `pushButton` I implement, I either get a type
|
||||||
|
# mismatch when trying to resolve `mm.send()` below or an error message from
|
||||||
|
# `gcc` about `Sup` in something that is not a structure or a union.
|
||||||
|
#
|
||||||
|
# Neither of these seem like fun to debug right now.
|
||||||
|
|
||||||
|
type
|
||||||
|
Module = ref object of RootObj
|
||||||
|
name: string
|
||||||
|
dests: seq[string]
|
||||||
|
Broadcaster = ref object of Module
|
||||||
|
FlipFlop = ref object of Module
|
||||||
|
state: Pulse
|
||||||
|
Conjunction = ref object of Module
|
||||||
|
state: Table[string, Pulse]
|
||||||
|
|
||||||
|
func parseModule(line: string): Module =
|
||||||
|
let parts = line.strip.split(" -> ", 1)
|
||||||
|
let (name, dests) = (parts[0], parts[1])
|
||||||
|
|
||||||
|
result.dests = dests.split(", ")
|
||||||
|
|
||||||
|
if name[0] == '%':
|
||||||
|
result = FlipFlop(name: name[1..^1], state: Low)
|
||||||
|
elif name[0] == '&':
|
||||||
|
result = Conjunction(name: name[1..^1])
|
||||||
|
elif name == "broadcaster":
|
||||||
|
result = Broadcaster(name: name)
|
||||||
|
else:
|
||||||
|
raise newException(ValueError, line)
|
||||||
|
|
||||||
|
type Machine = tuple
|
||||||
|
modules: Table[string, Module]
|
||||||
|
|
||||||
|
func newMachine(text: string): Machine =
|
||||||
|
for m in text.strip.splitLines.map(parseModule):
|
||||||
|
result.modules[m.name] = m
|
||||||
|
|
||||||
|
for (srcName, srcMod) in result.modules.pairs:
|
||||||
|
for dstName in srcMod.dests:
|
||||||
|
let dstMod = result.modules[dstName]
|
||||||
|
if typeof(dstMod) is Conjunction:
|
||||||
|
Conjunction(dstMod).state[srcName] = Low
|
||||||
|
|
||||||
|
type Wire = tuple
|
||||||
|
src: string
|
||||||
|
dest: string
|
||||||
|
value: Pulse
|
||||||
|
|
||||||
|
method send(m: ref var Module, source: string, p: Pulse): seq[Wire] {.base.} =
|
||||||
|
raise newException(CatchableError, "abstract method")
|
||||||
|
|
||||||
|
method send(b: ref var Broadcaster, _: string, p: Pulse): seq[Wire] =
|
||||||
|
let src = b.name
|
||||||
|
for dst in b.dests:
|
||||||
|
result.add (src, dst, p)
|
||||||
|
|
||||||
|
method send(c: ref var Conjunction, source: string, p: Pulse): seq[Wire] =
|
||||||
|
c.state[source] = p
|
||||||
|
|
||||||
|
var output = Low
|
||||||
|
for v in c.state.values:
|
||||||
|
if v == Low:
|
||||||
|
output = High
|
||||||
|
break
|
||||||
|
|
||||||
|
let src = c.name
|
||||||
|
for dst in c.dests:
|
||||||
|
result.add (src, dst, output)
|
||||||
|
|
||||||
|
method send(f: ref var FlipFlop, source: string, p: Pulse): seq[Wire] =
|
||||||
|
if p == High:
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
var output = Low
|
||||||
|
case f.state:
|
||||||
|
of High:
|
||||||
|
f.state = Low
|
||||||
|
output = Low
|
||||||
|
of Low:
|
||||||
|
f.state = High
|
||||||
|
output = High
|
||||||
|
|
||||||
|
let src = f.name
|
||||||
|
for dst in f.dests:
|
||||||
|
result.add (src, dst, output)
|
||||||
|
|
||||||
|
proc pushButton(m: var Machine): CountTable[Pulse] =
|
||||||
|
var queue: Deque[Wire]
|
||||||
|
|
||||||
|
queue.addLast ("button", "broadcaster", Low)
|
||||||
|
|
||||||
|
while queue.len > 0:
|
||||||
|
let (src, name, pulse) = queue.popFirst
|
||||||
|
result.inc pulse
|
||||||
|
|
||||||
|
let mm = m.modules[name]
|
||||||
|
echo typeof(mm)
|
||||||
|
for output in mm.send(src, pulse):
|
||||||
|
queue.addLast output
|
||||||
|
|
||||||
|
proc part1(input: string): int =
|
||||||
|
let text = readFile(input)
|
||||||
|
var machine = newMachine(text)
|
||||||
|
|
||||||
|
let pulses = machine.pushButton
|
||||||
|
pulses[High] * pulses[Low]
|
||||||
|
|
||||||
|
###################
|
||||||
|
|
||||||
|
proc timed[T](f: () -> T): T =
|
||||||
|
let start = cpuTime()
|
||||||
|
result = f()
|
||||||
|
echo "Time :", cpuTime() - start
|
||||||
|
|
||||||
|
echo timed(proc(): int = part1("input/test.txt"))
|
||||||
|
# echo timed(proc(): int = part1("input/day20.txt"))
|
||||||
|
# echo timed(proc(): int = part2("input/test.txt"))
|
||||||
|
# echo timed(proc(): int = part2("input/day20.txt"))
|
||||||
Loading…
Reference in a new issue