5 | import Data.SortedMap 
   6 | import Data.Primitives.Views 
  11 | import Control.Eff.Except 
  16 |   constructor MkButton 
  18 | %name Button 
b, b2, b3 
  20 | parseButton : Has (ExceptL "parse" String) fs => String -> Eff fs Button 
  21 | parseButton str = do 
  23 |     noteAt "parse" "button: split" . 
  24 |       toVect 4 . forget . split (== ' ') $ 
str 
  26 |     noteAt "parse" "button: x" . 
  27 |      parsePositive . pack . filter isDigit . unpack $ 
x 
  29 |     noteAt "parse" "button: x" . 
  30 |      parsePositive . pack . filter isDigit . unpack $ 
y 
  36 | %name Prize 
p, p2, p3 
  38 | parsePrize : Has (ExceptL "parse" String) fs => String -> Eff fs Prize 
  41 |     noteAt "parse" "prize: split" . 
  42 |       toVect 3 . forget . split (== ' ') $ 
str 
  44 |     noteAt "parse" "prize: x" . 
  45 |      parsePositive . pack . filter isDigit . unpack $ 
x 
  47 |     noteAt "parse" "prize: x" . 
  48 |      parsePositive . pack . filter isDigit . unpack $ 
y 
  51 | record Machine where 
  52 |   constructor MkMachine 
  55 | %name Machine 
m, m2, m3 
  57 | cost : (lower, upper : Integer) -> Machine -> Maybe Integer 
  58 | cost lower upper m = 
  59 |   let xs = mapMaybe cost' $ 
lazyRange' lower upper 
  63 |       Just (foldl1 min $ 
y ::: toList ys) 
  65 |   cost' : Integer -> Maybe Integer 
  67 |     let (a_x, a_y) = (m.a.x * a_count, m.a.y * a_count) 
  68 |         (d_x, d_y) = (m.prize.x - a_x, m.prize.y - a_y) 
  69 |     in if d_x < 0 || d_y < 0 
  71 |       else if d_x == 0 && d_y == 0 
  72 |         then Just (a_count * 3) 
  74 |           let (div_x, rem_x) = (d_x `div` m.b.x, d_x `mod` m.b.x) 
  76 |             then if div_x * m.b.y + a_count * m.a.y == m.prize.y 
  77 |               then Just (a_count * 3 + div_x) 
  81 | costAuto : Machine -> Maybe Integer 
  83 |   let presses : Vect _ _ = 
  85 |           (min (m.prize.x `div` m.a.x) 
  86 |            (m.prize.x `div` m.b.x)) 
  87 |         , (min (m.prize.y `div` m.a.y) 
  88 |            (m.prize.y `div` m.b.y)) 
  90 |       max_presses = foldl1 max . map (+1) $ 
presses 
  91 |   in cost 0 max_presses m 
  94 |   show (MkMachine a b prize) = 
  95 |     "Button A: X+\{show a.x}, Y+\{show a.y}\nButton B: X+\{show b.x}, Y+\{show b.y}\nPrize: X=\{show prize.x}, Y=\{show prize.y}" 
  97 | parseMachine : Has (ExceptL "parse" String) fs => Vect 3 String -> Eff fs Machine 
  98 | parseMachine [a, b, prize] = do 
 101 |   prize <- parsePrize prize 
 102 |   pure $ 
MkMachine a b prize 
 105 |   constructor MkInput 
 107 |   machines : Vect len Machine 
 111 |   show (MkInput len machines) = joinBy "\n\n" . toList . map show $ 
machines 
 113 | parseInput : Has (ExceptL "parse" String) fs => String -> Eff fs Input 
 114 | parseInput str = do 
 115 |   groups <- noteAt "parse" "Grouping machines" . 
 116 |     traverse (toVect 3) . forget . split null . map trim . lines . trim $ 
str 
 117 |   machines <- traverse parseMachine $ 
groups 
 118 |   pure $ 
MkInput (length machines) (fromList machines) 
 121 | part1 : String -> Eff [IO, Except String] (Integer, Input) 
 123 |   input <- tagAt "parse"  $ 
parseInput str 
 124 |   let res = sum . mapMaybe costAuto . toList $ 
input.machines 
 128 | part2 : Input -> Eff [IO, Except String] Integer 
 129 | part2 (MkInput len machines) = do 
 131 |     map (\(MkMachine a b (MkPrize x y)) => 
 132 |             (MkMachine a b (MkPrize (x * 10000000000000) (y * 10000000000000)))) machines 
 133 |   let res = sum . mapMaybe costAuto . toList $ 
machines