tangled
alpha
login
or
join now
eldridge.cam
/
advent-of-code
2
fork
atom
Advent of Code solutions
2
fork
atom
overview
issues
pulls
pipelines
solved by translating to haskell :) 2025 is done
eldridge.cam
2 months ago
25b8570c
02aa4c16
+53
-39
2 changed files
expand all
collapse all
unified
split
2025
10
p2.hs
p2.tri
+51
-34
2025/10/p2.hs
···
1
1
-
import Debug.Trace
2
2
-
import Text.Parsec
3
3
-
import Data.List (sortBy, sort, foldl1, find, nub, sum)
4
1
import Control.Monad (guard)
2
2
+
import Control.Monad.State
3
3
+
import Data.Bits
4
4
+
import Data.Bool
5
5
+
import Data.Function ((&))
6
6
+
import Data.List (find, foldl1, nub, sort, sortBy, sum)
7
7
+
import Data.Map (Map, insert)
8
8
+
import qualified Data.Map as Map
5
9
import Data.Ord (comparing)
10
10
+
import Text.Parsec (between, char, digit, many, many1, parse, sepBy1, sepEndBy, (<|>))
6
11
7
12
integer = read <$> many digit
8
13
···
13
18
joltage :: [Int] <- between (char '{') (char '}') $ integer `sepBy1` char ','
14
19
return $ (joltage, buttons)
15
20
16
16
-
limitWithin target button = foldl1 min $ fmap (target !!) button
21
21
+
targetState '.' = False
22
22
+
targetState '#' = True
17
23
18
18
-
subAt 0 n (m:ms) = m - n:ms
19
19
-
subAt i n (m:ms) = m:subAt (i - 1) n ms
24
24
+
buttonBits len button = foldl setBit 0 $ map (\n -> len - n - 1) button
20
25
21
21
-
applyButton _ [] target = target
22
22
-
applyButton n (i:rest) target = applyButton n rest $ subAt i n $ target
26
26
+
decrAt 0 (m : ms) = m - 1 : ms
27
27
+
decrAt i (m : ms) = m : decrAt (i - 1) ms
23
28
24
24
-
covers target coverage =
25
25
-
all (\ i -> target !! i == 0 || i `elem` coverage) [0..length target - 1]
29
29
+
applyButton target [] = target
30
30
+
applyButton target (i : rest) = applyButton (decrAt i target) rest
26
31
27
27
-
solvable _ _ [] = False
28
28
-
solvable remaining target allButtons@(button:buttons) =
29
29
-
if remaining < foldl1 max target || not (covers target $ nub $ concat allButtons)
30
30
-
then False
31
31
-
else
32
32
-
let limit = min remaining $ limitWithin target button in any pressAndSolve [limit, limit-1..0]
33
33
-
where
34
34
-
pressAndSolve times =
35
35
-
let newTarget = applyButton times button target in
36
36
-
if all ((==) 0) newTarget
37
37
-
then True
38
38
-
else solvable (remaining - times) newTarget (prioritize newTarget buttons)
32
32
+
choose :: Int -> [a] -> [[a]]
33
33
+
choose 0 _ = [[]]
34
34
+
choose n [] = []
35
35
+
choose n (x : xs) = ((x :) <$> choose (n - 1) xs) ++ choose n xs
39
36
40
40
-
rangeSize target buttons button =
41
41
-
let
42
42
-
others = nub $ concat $ filter ((/=) button) buttons
43
43
-
upper = limitWithin target button
44
44
-
in if covers target others then 1 else upper
37
37
+
solveBits :: [[Int]] -> Int -> Int -> [[[Int]]]
38
38
+
solveBits buttons len target =
39
39
+
[option | n <- [0 .. length buttons], option <- choose n buttons, target == (foldl xor 0 $ fmap (buttonBits len) option)]
45
40
46
46
-
prioritize target buttons =
47
47
-
sortBy (comparing $ rangeSize target buttons) buttons
48
48
-
49
49
-
solve (target, buttons) = ans
41
41
+
solve buttons joltage = evalState (solve_ joltage) Map.empty
50
42
where
51
51
-
solveIn i = solvable (traceShowId i) target $ prioritize target buttons
52
52
-
Just ans = find solveIn [foldl1 max target..]
43
43
+
solve_ :: [Int] -> State (Map [Int] Int) Int
44
44
+
solve_ joltage = do
45
45
+
cached <- gets (Map.lookup joltage)
46
46
+
case cached of
47
47
+
Nothing -> do
48
48
+
ans <- compute joltage
49
49
+
modify $ insert joltage ans
50
50
+
return ans
51
51
+
Just answer -> return answer
52
52
+
compute :: [Int] -> State (Map [Int] Int) Int
53
53
+
compute joltage =
54
54
+
if all (== 0) joltage
55
55
+
then return 0
56
56
+
else
57
57
+
joltage
58
58
+
& fmap (\n -> n `mod` 2)
59
59
+
& foldl (\joltage bit -> bit .|. joltage `shift` 1) 0
60
60
+
& solveBits buttons (length joltage)
61
61
+
& fmap (\sol -> (foldl applyButton joltage sol, length sol))
62
62
+
& filter (\(remaining, _) -> all (>= 0) remaining)
63
63
+
& mapM
64
64
+
( \(remaining, score) -> do
65
65
+
sub <- solve_ (fmap (`div` 2) remaining)
66
66
+
return $ sub * 2 + score
67
67
+
)
68
68
+
& fmap (foldl min 10000000)
53
69
54
54
-
answer input = sum $ (traceShowId . solve . traceShowId) <$> machines
70
70
+
answer input = sum $ fmap (\(j, b) -> solve b j) machines
55
71
where
56
72
Right machines = parse (machine `sepEndBy` char '\n') "" input
73
73
+
57
74
main = getContents >>= print . answer
+2
-5
2025/10/p2.tri
···
42
42
func apply_button target [i, ..rest] = apply_button (decr_at i target) rest
43
43
44
44
func solve_bits buttons target =
45
45
-
it::range 1 (length buttons)
45
45
+
it::range 0 (length buttons)
46
46
|> it::flat_map (fn n. it::choose n buttons)
47
47
-
|> it::filter ((==) target << reduce (^) << map (button_bits (length target)))
47
47
+
|> it::filter ((==) target << fold (^) (target ^ target) << map (button_bits (length target)))
48
48
49
49
proc solver!(buttons) {
50
50
let cache = {||}
···
55
55
}
56
56
if all ((==) 0) joltage {
57
57
return 0
58
58
-
}
59
59
-
if all (fn n. n % 2 == 0) joltage {
60
60
-
return solve!(map (fn n. n // 2) joltage) * 2
61
58
}
62
59
let best = joltage
63
60
|> map (fn n. n % 2 == 1)