-- 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')) def all-members : ω.Line → List ℕ = λ ln ⇒ list.filter ℕ (λ n ⇒ mem n (snd ln)) (fst ln) 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 → ℕ = λ ln ⇒ score-from-len (all-members ln) def total-score : ω.(List Line) → ℕ = list.foldlω Line ℕ 0 (λ n l ⇒ nat.plus n (score l)) 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) #[main] def part2 = 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 total-cards lines))