Advent of Code solutions

Merge branch 'main' of github.com:foxfriends/advent-of-code

+100 -89
-60
2025/10/p1-copy.tri
··· 1 - import "trilogy:io" use readlines 2 - import "trilogy:debug" use dbg 3 - import "trilogy:core" use to_array, length 4 - import "trilogy:bits" as bits 5 - import "trilogy:record" use collect, merge_by, contains_key 6 - import "trilogy:compare" use min 7 - import "trilogy:parsec" use parse, apply, between, many_1, char_of, char, integer, sep_by_1 8 - import "trilogy:array" use map, fold, filter 9 - import "trilogy:iterator" as it 10 - 11 - func target_state '.' = false 12 - func target_state '#' = true 13 - 14 - func set_bit bb index = bb | (0bb1 ~~> index) 15 - 16 - proc machine!() { 17 - let target = bits::from_array 18 - <| map target_state 19 - <| apply 20 - <| between (char '[') (char ']') 21 - <| many_1 22 - <| char_of ".#" 23 - apply <| char ' ' 24 - let buttons = map (fold set_bit (target ^ target)) 25 - <| apply 26 - <| sep_by_1 (char ' ') 27 - <| between (char '(') (char ')') 28 - <| sep_by_1 (char ',') integer 29 - apply <| char ' ' 30 - let _joltage = apply 31 - <| between (char '{') (char '}') 32 - <| sep_by_1 (char ',') integer 33 - return target:buttons 34 - } 35 - 36 - func press_button round states button = states 37 - |> to_array 38 - |> filter (fn state:presses. presses == round) 39 - |> map (fn state:presses. state ^ button : presses + 1) 40 - |> it::from 41 - |> collect 42 - 43 - proc solve!(target:buttons) { 44 - let mut states = {| target ^ target => 0 |} 45 - let mut i = 0 46 - while !(contains_key target states) { 47 - states = map (press_button i states) buttons 48 - |> fold (merge_by (fn k a b. min a b)) states 49 - i += 1 50 - } 51 - return states.target 52 - } 53 - 54 - proc main!() { 55 - readlines 56 - |> it::map (parse machine) 57 - |> it::map solve 58 - |> it::fold (+) 0 59 - |> dbg 60 - }
+3 -4
2025/10/p1.tri
··· 33 33 return target:buttons 34 34 } 35 35 36 - 37 36 proc solve!(target:buttons) { 38 37 let mut visited = [| target ^ target |] 39 38 let mut states = [| target ^ target |] 40 39 let mut i = 0 41 40 while !(contains target states) { 42 - states = states 41 + let new_states = states 43 42 |> it::from 44 43 |> it::flat_map (fn state. it::from <| map ((^) state) buttons) 45 44 |> collect 46 - visited union= states 47 - states = difference states visited 45 + states = difference new_states visited 46 + visited union= new_states 48 47 i += 1 49 48 } 50 49 return i
+57
2025/10/p2.hs
··· 1 + import Debug.Trace 2 + import Text.Parsec 3 + import Data.List (sortBy, sort, foldl1, find, nub, sum) 4 + import Control.Monad (guard) 5 + import Data.Ord (comparing) 6 + 7 + integer = read <$> many digit 8 + 9 + machine = do 10 + _ :: [Char] <- between (char '[') (char ']') $ many1 (char '.' <|> char '#') 11 + char ' ' 12 + buttons :: [[Int]] <- (between (char '(') (char ')') $ integer `sepBy1` char ',') `sepEndBy` char ' ' 13 + joltage :: [Int] <- between (char '{') (char '}') $ integer `sepBy1` char ',' 14 + return $ (joltage, buttons) 15 + 16 + limitWithin target button = foldl1 min $ fmap (target !!) button 17 + 18 + subAt 0 n (m:ms) = m - n:ms 19 + subAt i n (m:ms) = m:subAt (i - 1) n ms 20 + 21 + applyButton _ [] target = target 22 + applyButton n (i:rest) target = applyButton n rest $ subAt i n $ target 23 + 24 + covers target coverage = 25 + all (\ i -> target !! i == 0 || i `elem` coverage) [0..length target - 1] 26 + 27 + solvable _ _ [] = False 28 + solvable remaining target allButtons@(button:buttons) = 29 + if remaining < foldl1 max target || not (covers target $ nub $ concat allButtons) 30 + then False 31 + else 32 + let limit = min remaining $ limitWithin target button in any pressAndSolve [limit, limit-1..0] 33 + where 34 + pressAndSolve times = 35 + let newTarget = applyButton times button target in 36 + if all ((==) 0) newTarget 37 + then True 38 + else solvable (remaining - times) newTarget (prioritize newTarget buttons) 39 + 40 + rangeSize target buttons button = 41 + let 42 + others = nub $ concat $ filter ((/=) button) buttons 43 + upper = limitWithin target button 44 + in if covers target others then 1 else upper 45 + 46 + prioritize target buttons = 47 + sortBy (comparing $ rangeSize target buttons) buttons 48 + 49 + solve (target, buttons) = ans 50 + where 51 + solveIn i = solvable (traceShowId i) target $ prioritize target buttons 52 + Just ans = find solveIn [foldl1 max target..] 53 + 54 + answer input = sum $ (traceShowId . solve . traceShowId) <$> machines 55 + where 56 + Right machines = parse (machine `sepEndBy` char '\n') "" input 57 + main = getContents >>= print . answer
+40 -25
2025/10/p2.tri
··· 1 1 import "trilogy:io" use readlines 2 2 import "trilogy:debug" use dbg 3 - import "trilogy:core" use to_array, length 4 - import "trilogy:bits" as bits 5 - import "trilogy:record" use collect, merge_by, contains_key 6 - import "trilogy:compare" use min 3 + import "trilogy:compare" use min, max, asc 7 4 import "trilogy:parsec" use parse, apply, between, many_1, char_of, char, integer, sep_by_1 8 - import "trilogy:array" use map, fold, filter 5 + import "trilogy:array" use map, fold, filter, reverse, sort_by, reduce, all, flatten 9 6 import "trilogy:iterator" as it 7 + import "trilogy:set" as set use contains 10 8 11 9 proc machine!() { 12 10 let _target = apply ··· 25 23 return joltage:buttons 26 24 } 27 25 28 - proc update_state!(state, n) { 29 - state.n += 1 26 + func limit_within target button = reduce min <| map ((.) target) button 27 + 28 + func sub_at 0 n [m, ..arr] = [m - n, ..arr] 29 + func sub_at i n [m, ..arr] = [m, ..sub_at (i - 1) n arr] 30 + 31 + func apply_button _ [] target = target 32 + func apply_button n [i, ..rest] target = apply_button n rest <| sub_at i n <| target 33 + 34 + func covers target coverage = 35 + it::from target 36 + |> it::enumerate 37 + |> it::all (fn i:v. v == 0 || contains i coverage) 38 + 39 + proc solvable!(remaining, target, all_buttons and [button, ..buttons]) { 40 + if remaining < reduce max target || !(covers target <| set::collect <| it::from <| flatten all_buttons) { 41 + return false 42 + } 43 + let limit = min remaining <| limit_within target button 44 + return it::range limit 0 45 + |> it::any (fn times. 46 + let new_target = apply_button times button target, 47 + if all ((==) 0) new_target 48 + then true 49 + else buttons != [] && solvable!(remaining - times, new_target, prioritize new_target buttons) 50 + ) 30 51 } 31 52 32 - func apply_button state [] = state 33 - func apply_button state [n, ..rest] = apply_button update_state!(state, n) rest 34 - 35 - func press_button round states button = states 36 - |> to_array 37 - |> filter (fn state:presses. presses == round) 38 - |> map (fn state:presses. apply_button state button : presses + 1) 39 - |> it::from 40 - |> collect 53 + func range_size target buttons button = 54 + let others = set::collect <| it::from <| flatten <| filter ((!=) button) buttons, 55 + let upper = limit_within target button, 56 + let lower = if covers target others then 0 else upper, 57 + upper - lower 41 58 42 - func below [] [] = true 43 - func below [a, ..ra] [b, ..rb] = if b <= a then below ra rb else false 59 + func prioritize target buttons = 60 + sort_by (asc <| range_size target buttons) buttons 44 61 45 62 proc solve!(target:buttons) { 46 - let mut states = {| map (fn _. 0) target => 0 |} 47 - let mut i = 0 48 - while !(contains_key target states) { 49 - states = map (press_button i states) buttons 50 - |> filter (fn state:_. below target state) 51 - |> fold (merge_by (fn k a b. min a b)) states 63 + let mut i = reduce max target 64 + let buttons_ordered = prioritize target buttons 65 + while !solvable!(i, target, buttons_ordered) { 52 66 i += 1 67 + dbg!('try(i)) 53 68 } 54 - return states.target 69 + return i 55 70 } 56 71 57 72 proc main!() {