3 | import Data.List.Lazy
7 | import Control.Eff.Except
8 | import Control.Eff.Choose
9 | import Control.Eff.State
11 | import Derive.Prelude
16 | %language ElabReflection
18 | data ErrorL = LParse | LSolve
21 | show LParse = "parsing"
22 | show LSolve = "solving"
24 | ParseError : Type -> Type
25 | ParseError = ExceptL LParse String
27 | SolveError : Type -> Type
28 | SolveError = ExceptL LSolve String
30 | data Cell = Wall | Start | End | Empty
31 | %runElab derive "Cell" [Eq]
33 | charToCell : Char -> Cell
34 | charToCell '#' = Wall
35 | charToCell 'S' = Start
36 | charToCell 'E' = End
37 | charToCell _ = Empty
42 | room : Grid rows cols Cell
44 | parseInput : Has ParseError fs => String -> Eff fs Input
46 | (
rows ** cols ** input)
<- noteAt LParse "Error gridfying input" $
48 | let room = map (map charToCell) input
49 | pure $
MkInput rows cols room
51 | startPos : (i : Input) -> Maybe (Coord i.rows i.cols)
52 | startPos i = map fst . head' . filter ((== Start) . snd) . flat $
i.room
54 | endPos : (i : Input) -> Maybe (Coord i.rows i.cols)
55 | endPos i = map fst . head' . filter ((== End) . snd) . flat $
i.room
57 | NodeWeight : (rows, cols : Nat) -> Type
58 | NodeWeight rows cols = (Coord rows cols, Direction)
61 | EdgeWeight = Integer
63 | GraphT : (rows, cols : Nat) -> Type
64 | GraphT rows cols = Graph (Tpe (NodeWeight rows cols) EdgeWeight)
67 | Has SolveError fs =>
68 | (i : Input) -> Eff fs (GraphT i.rows i.cols)
70 | start <- noteAt LSolve "No Start position" $
startPos i
71 | let initialState : GraphT i.rows i.cols = empty
73 | extract . runState initialState . runChoose {f = List} $
toGraph (start, Right)
77 | (i : Input) -> (weight : NodeWeight i.rows i.cols)
78 | -> Eff [Choose, (State (GraphT i.rows i.cols))] (NodeWeight i.rows i.cols, Integer)
79 | nextWeights i (coord, dir) = do
81 | turn <- oneOf $
Nothing :: map Just (turns dir)
84 | Just next <- pure $
step coord (directionToStep dir)
86 | case next `index` i.room of
88 | _ => pure $
((next, dir), 1)
89 | Just turn => pure $
((coord, turn), 1000)
91 | (weight : NodeWeight i.rows i.cols)
92 | -> Eff [Choose, (State (GraphT i.rows i.cols))] NodeId
97 | pure . head' . filter (\x => Just weight == node_weight x graph) . nodes $
graph
98 | | Just id => pure id
100 | let (id, graph) = insert_node weight graph
103 | (next_weight, cost) <- nextWeights i weight
105 | next_id <- toGraph next_weight
108 | put $
insert_edge (id, next_id) cost graph
113 | part1 : String -> Eff [IO, Except String] (Integer, Input)
115 | input <- tagAt LParse $
parseInput str
116 | graph <- tagAt LSolve $
inputToGraph input
117 | putStrLn $
"Converted to graph"
122 | part2 : Input -> Eff [IO, Except String] Integer