1 {-# LANGUAGE RecordWildCards, NamedFieldPuns #-}
4 import qualified Data.Set as S
8 data Point = Point Int Int -- row, column
9 deriving (Show, Eq, Ord, Ix)
11 type Grid = S.Set Point
13 gridBounds = (Point 1 1, Point 7 7)
18 -- gridBounds = (Point 1 1, Point 2 2)
19 -- pathStart = Point 1 1
20 -- pathEnd = Point 2 1
23 -- gridBounds = (Point 1 1, Point 4 4)
24 -- pathStart = Point 1 1
25 -- pathEnd = Point 4 1
26 -- fullPathLength = 15
28 data Direction = U | R | D | L
29 deriving (Show, Eq, Ord, Enum, Bounded)
31 data DirectionConstraint = CU | CR | CD | CL | Unknown
32 deriving (Show, Eq, Ord, Enum, Bounded)
34 data State = State { visited :: Grid
36 , trail :: [Direction]
37 , constraints :: [DirectionConstraint]
39 deriving (Show, Eq, Ord)
41 initialState :: [DirectionConstraint] -> State
43 State { visited = S.singleton pathStart
52 -- let cs = replicate fullPathLength Unknown
53 let cs = readConstraints "??????R??????U??????????????????????????LD????D?"
54 -- let cs = readConstraints "DRURRRRRDDDLUULDDDLDRRURDDLLLLLURULURRUULDLLDDDD"
55 let paths = allPaths cs
60 -- let nums = unfoldr collatzStep n
61 -- let outStr = intercalate " " $ map show nums
64 readConstraints :: String -> [DirectionConstraint]
65 readConstraints = map readConstraint
67 readConstraint :: Char -> DirectionConstraint
68 readConstraint 'U' = CU
69 readConstraint 'R' = CR
70 readConstraint 'D' = CD
71 readConstraint 'L' = CL
72 readConstraint _ = Unknown
74 delta :: Direction -> Point
75 delta U = Point (-1) 0
78 delta L = Point 0 (-1)
80 (^+^) :: Point -> Point -> Point
81 (Point x1 y1) ^+^ (Point x2 y2) = Point (x1 + x2) (y1 + y2)
83 opposite :: Direction -> Direction -> Bool
91 compatible :: Direction -> DirectionConstraint -> Bool
92 compatible U CU = True
93 compatible R CR = True
94 compatible D CD = True
95 compatible L CL = True
96 compatible _ Unknown = True
97 compatible _ _ = False
100 isComplete :: State -> Bool
101 isComplete (State {..}) =
102 pos == pathEnd && length trail == fullPathLength
104 successors :: State -> [State]
105 successors state@(State {..})
106 | pos == pathEnd = []
107 | isComplete state = []
109 do dir <- [minBound..maxBound]
110 let givenDirection = head constraints
111 guard $ compatible dir givenDirection
112 let nextPos = pos ^+^ (delta dir)
113 guard $ inRange gridBounds nextPos
114 {-# SCC "setNonMember" #-} guard $ S.notMember nextPos visited
115 let nextVisited = S.insert nextPos visited
116 return $ State { visited = nextVisited
118 , constraints = tail constraints
119 , trail = dir : trail
122 allPaths :: [DirectionConstraint] -> [State]
123 allPaths constraints = dfs [initialState constraints] []
125 -- bfs :: [State] -> [State] -> [State]
126 -- bfs [] visited = visited
127 -- bfs (current:agenda) visited
128 -- | isComplete current = bfs agenda (current : visited)
130 -- let succs = successors current
131 -- newAgenda = agenda ++ succs
132 -- in bfs newAgenda visited
134 dfs :: [State] -> [State] -> [State]
135 dfs [] visited = visited
136 dfs (current:agenda) visited
137 | isComplete current = dfs agenda (current : visited)
139 let succs = successors current
140 newAgenda = succs ++ agenda
141 in dfs newAgenda visited