2222module Main (main ) where
2323
2424import Advent (format )
25- import Data.Foldable ( for_ )
25+ import Control.Monad ( replicateM )
2626import Data.Maybe (fromJust )
27- import Data.SBV (SInteger , optLexicographic , free , minimize , (.==) , (.>=) , constrain , getModelValue )
28- import Data.Traversable (for )
27+ import Data.SBV (SInteger , optLexicographic , sAll , sAnd , sInteger_ , minimize , (.==) , (.>=) , constrain , getModelValue )
2928
3029-- | >>> :main
3130-- 409
@@ -44,10 +43,7 @@ part1 (goal, btns, _) = fromJust (cost assertion)
4443 foldl conj R1
4544 [ foldl xorRME
4645 (if c == ' #' then R0 else R1 )
47- [ Node b R0 R1
48- | (b,btn) <- zip [0 .. ] btns
49- , i `elem` btn
50- ]
46+ [Node b R0 R1 | (b,btn) <- zip [0 .. ] btns, i `elem` btn]
5147 | (i, c) <- zip [0 .. ] goal
5248 ]
5349
@@ -68,16 +64,17 @@ part2 (_, btns, jolt) =
6864 do
6965 res <- optLexicographic
7066 do -- allocate one, non-zero coefficient per button to press
71- cs <- for [0 .. length btns - 1 ] \ i ->
72- do
73- c <- free (" x" ++ show i)
74- constrain (c .>= 0 )
75- pure (c :: SInteger )
76-
77- -- add a constraint for each element of the joltage
78- for_ (zip [0 .. ] jolt) \ (i, j) ->
79- let j' = sum [c | (c, btn) <- zip cs btns, i `elem` btn]
80- in constrain (j' .== fromIntegral j)
67+ cs <- replicateM (length btns) sInteger_
68+
69+ -- All press counts are non-negative
70+ constrain (sAll (.>= 0 ) cs)
71+
72+ -- All presses generate the correct amount of jolt
73+ constrain (sAnd
74+ [ fromIntegral j .==
75+ sum [c | (c, btn) <- zip cs btns , i `elem` btn]
76+ | (i, j) <- zip [0 .. ] jolt
77+ ])
8178
8279 -- optimize the problem for the smallest number of button presses
8380 minimize " smallest sum" (sum cs)
0 commit comments