2023-12-06 21:47:23 -05:00
|
|
|
|
-- introducing: let expressions!!!
|
|
|
|
|
-- i implemented them yesterday because this was just too annoying otherwise
|
|
|
|
|
|
|
|
|
|
load "list.quox"
|
|
|
|
|
load "string.quox"
|
|
|
|
|
load "io.quox"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def0 Line : ★ = List ℕ × List ℕ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- i still don't have char literals. quox has no idea what "a char" is
|
|
|
|
|
def colon = char.from-ℕ 0x3A
|
|
|
|
|
def bar = char.from-ℕ 0x7C
|
|
|
|
|
|
|
|
|
|
def split-line : ω.String → Line =
|
|
|
|
|
λ line ⇒
|
|
|
|
|
letω line = snd (string.break (char.eq colon) line);
|
|
|
|
|
pair = string.break (char.eq bar) line;
|
|
|
|
|
got = fst pair; want = snd pair;
|
|
|
|
|
got = list.filter String string.not-null (string.split char.ws? got);
|
|
|
|
|
want = list.filter String string.not-null (string.split char.ws? want);
|
|
|
|
|
got = list.tail-or-nil String got;
|
|
|
|
|
want = list.tail-or-nil String want;
|
|
|
|
|
to-ℕs = list.map String ℕ
|
|
|
|
|
(λ s ⇒ maybe.fold ℕ ℕ 0 (λ n ⇒ n) (string.to-ℕ s)) in
|
|
|
|
|
(to-ℕs got, to-ℕs want)
|
|
|
|
|
|
|
|
|
|
def mem : ω.ℕ → ω.(List ℕ) → Bool =
|
|
|
|
|
λ n ⇒ list.foldlω ℕ Bool 'false (λ b n' ⇒ bool.or b (nat.eq n n'))
|
|
|
|
|
|
2023-12-09 09:15:31 -05:00
|
|
|
|
def all-members : ω.Line → List ℕ =
|
|
|
|
|
λ ln ⇒ list.filter ℕ (λ n ⇒ mem n (snd ln)) (fst ln)
|
2023-12-06 21:47:23 -05:00
|
|
|
|
|
|
|
|
|
def score-from-len : ω.(List ℕ) → ℕ =
|
|
|
|
|
λ xs ⇒
|
|
|
|
|
maybe.foldω (ℕ × List ℕ) ℕ 0
|
|
|
|
|
(λ xxs ⇒ list.foldlω ℕ ℕ 1 (λ c _ ⇒ nat.times 2 c) (snd xxs))
|
|
|
|
|
(list.uncons ℕ xs)
|
|
|
|
|
|
|
|
|
|
def score : ω.Line → ℕ =
|
2023-12-09 09:15:31 -05:00
|
|
|
|
λ ln ⇒ score-from-len (all-members ln)
|
2023-12-06 21:47:23 -05:00
|
|
|
|
|
|
|
|
|
def total-score : ω.(List Line) → ℕ =
|
|
|
|
|
list.foldlω Line ℕ 0 (λ n l ⇒ nat.plus n (score l))
|
|
|
|
|
|
2023-12-09 09:15:31 -05:00
|
|
|
|
def part1 =
|
|
|
|
|
io.bindω String True
|
|
|
|
|
(io.read-fileω "in/day4")
|
|
|
|
|
(λ s ⇒ io.dump (List Line)
|
|
|
|
|
(letω lines = string.split (char.eq char.newline) s;
|
|
|
|
|
lines = list.mapω String Line split-line lines in
|
|
|
|
|
lines))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def0 Copies : ★ = List ℕ
|
|
|
|
|
|
|
|
|
|
def CNil = list.Nil ℕ
|
|
|
|
|
def CCons = list.Cons ℕ
|
|
|
|
|
|
|
|
|
|
def decr-copies : Copies → ℕ × Copies =
|
|
|
|
|
let0 Ret : ★ = ℕ × Copies in
|
|
|
|
|
list.foldr ℕ Ret (1, CNil)
|
|
|
|
|
(λ cur nrest ⇒
|
|
|
|
|
case nrest return Ret of { (n, rest) ⇒
|
|
|
|
|
case cur return Ret of {
|
|
|
|
|
0 ⇒ (n, rest);
|
|
|
|
|
succ cur ⇒ (succ n, CCons cur rest)
|
|
|
|
|
}})
|
|
|
|
|
|
|
|
|
|
def new-copies : ℕ → ω.ℕ → Copies → Copies =
|
|
|
|
|
λ count value cs ⇒
|
|
|
|
|
case count return Copies of {
|
|
|
|
|
0 ⇒ cs;
|
|
|
|
|
succ _, cs' ⇒ CCons value cs'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def total-cards : ω.(List Line) → ℕ =
|
|
|
|
|
λ lines ⇒
|
|
|
|
|
let 0.State : ★ = ℕ × Copies;
|
|
|
|
|
ω.start : State = (0, CNil);
|
|
|
|
|
ω.next : ω.State → ω.Line → State =
|
|
|
|
|
λ st ln ⇒
|
|
|
|
|
letω total = fst st;
|
|
|
|
|
nc = decr-copies (snd st);
|
|
|
|
|
copies-this = fst nc;
|
|
|
|
|
copies-rest = snd nc;
|
|
|
|
|
score1 = list.length ℕ (all-members ln);
|
|
|
|
|
copies-out = new-copies copies-this score1 copies-rest;
|
|
|
|
|
total' = nat.plus total copies-this in
|
|
|
|
|
(total', copies-out) in
|
|
|
|
|
fst (list.foldlω Line State start next lines)
|
|
|
|
|
|
2023-12-06 21:47:23 -05:00
|
|
|
|
#[main]
|
2023-12-09 09:15:31 -05:00
|
|
|
|
def part2 =
|
2023-12-06 21:47:23 -05:00
|
|
|
|
io.bindω String True
|
|
|
|
|
(io.read-fileω "in/day4")
|
|
|
|
|
(λ s ⇒ io.dump ℕ
|
|
|
|
|
(letω lines = string.split (char.eq char.newline) s;
|
|
|
|
|
lines = list.mapω String Line split-line lines in
|
2023-12-09 09:15:31 -05:00
|
|
|
|
total-cards lines))
|