Watch
1
0
Fork
You've already forked advent-of-code
0
advent-of-code/2023/day19.nim
2023-12-18 22:54:16 -08:00

150 lines
3.3 KiB
Nim

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 Op = enum
None
Lt
Gt
func parseOp(c: char): Op =
case c:
of '<': Lt
of '>': Gt
else: raise newException(ValueError, $c)
type Step = tuple
attr: char
op: Op
val: int
dest: string
func parseStep(text: string): Step =
var op: char
if scanf(text, "$c$c$i:$+$.", result.attr, op, result.val, result.dest):
result.op = op.parseOp
return
if scanf(text, "$w$.", result.dest):
result.op = None
return
raise newException(ValueError, text)
type Workflow = tuple
name: string
steps: seq[Step]
func parseWorkflow(text: string): Workflow =
var steps: string
if not scanf(text, "$+{$+}$.", result.name, steps):
raise newException(ValueError, text)
result.steps = steps.split(',').map(parseStep)
type Part = tuple
attrs: Table[char, int]
func parseAttr(text: string): (char, int) =
if not scanf(text, "$c=$i$.", result[0], result[1]):
raise newException(ValueError, text)
func parseAttrs(text: string): Table[char, int] =
for (a, v) in text.split(',').map(parseAttr):
result[a] = v
func parsePart(line: string): Part =
var attrs: string
if not scanf(line, "{$+}$.", attrs):
raise newException(ValueError, line)
result.attrs = attrs.parseAttrs
type System = tuple
workflows: Table[string, Workflow]
parts: seq[Part]
func parseSystem(text: string): System =
let sections = text.split("\n\n")
assert sections.len == 2
for w in sections[0].strip.splitLines.map(parseWorkflow):
result.workflows[w.name] = w
result.parts = sections[1].strip.splitLines.map(parsePart)
func apply(w: Workflow, p: Part): string =
for s in w.steps:
case s.op:
of None:
return s.dest
of Lt:
if p.attrs[s.attr] < s.val:
return s.dest
of Gt:
if p.attrs[s.attr] > s.val:
return s.dest
func accepted(sys: System, part: Part): bool =
var w = "in"
while w != "R" and w != "A":
w = sys.workflows[w].apply(part)
w == "A"
func rating(p: Part): int =
for v in p.attrs.values:
result.inc v
proc part1(input: string): int =
let text = readFile(input)
let system = parseSystem(text)
for part in system.parts:
if system.accepted(part):
result.inc part.rating
###################
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/day19.txt"))
# echo timed(proc(): int = part2("input/test.txt"))
# echo timed(proc(): int = part2("input/day19.txt"))