Skip to content

Commit 5acdb4a

Browse files
committed
Split into vis and non-vis solutions
1 parent b122759 commit 5acdb4a

File tree

2 files changed

+141
-43
lines changed

2 files changed

+141
-43
lines changed

17.wip.hs renamed to 17.hs

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Data.Set qualified as S
33
import Data.Maybe (fromJust, fromMaybe)
44
import Data.List (find)
55

6+
-- A variation of 17.hs that shows the discovered path
7+
68
main :: IO ()
79
main = interact $ unlines . (\grid -> concat [p1 grid, p2 grid]) . parse
810

@@ -26,51 +28,27 @@ enum :: [a] -> [(Int, a)]
2628
enum = zip [0..]
2729

2830
neighbours :: Grid Int -> [Int] -> Cell -> [Neighbour]
29-
neighbours Grid { items } range = adjacent
31+
neighbours Grid { items } range = filter inRange . adjacent
3032
where
31-
toNeighbour :: Cell -> Int -> [Neighbour] -> (Int, [Neighbour])
33+
adjacent Cell { node = (x, y), direction, moves } = case direction of
34+
L -> concat [cells (\m -> Cell (x + m, y) L (moves + m)),
35+
cells (\m -> Cell (x, y - m) U m),
36+
cells (\m -> Cell (x, y + m) D m)]
37+
R -> concat [cells (\m -> Cell (x - m, y) R (moves + m)),
38+
cells (\m -> Cell (x, y - m) U m),
39+
cells (\m -> Cell (x, y + m) D m)]
40+
U -> concat [cells (\m -> Cell (x, y - m) U (moves + m)),
41+
cells (\m -> Cell (x - m, y) R m),
42+
cells (\m -> Cell (x + m, y) L m)]
43+
D -> concat [cells (\m -> Cell (x, y + m) D (moves + m)),
44+
cells (\m -> Cell (x - m, y) R m),
45+
cells (\m -> Cell (x + m, y) L m)]
46+
cells c = snd (foldl (\(d, xs) m -> toNeighbour (c m) d xs) (0, []) extent)
47+
extent = [1..maximum range]
3248
toNeighbour cell d xs = case M.lookup (node cell) items of
33-
Just d2 | moves cell `elem` range -> (d + d2, Neighbour cell (d + d2) : xs)
34-
Just d2 -> (d + d2, xs)
49+
Just d2 -> (d + d2, Neighbour cell (d + d2) : xs)
3550
_ -> (d, xs)
36-
adjacent :: Cell -> [Neighbour]
37-
adjacent Cell { node = (x, y), direction, moves } =
38-
let rng = [1..maximum range] in case direction of
39-
L -> concat [
40-
snd (foldl (\(d, xs) m -> let cell = Cell (x + m, y) L (moves + m)
41-
in toNeighbour cell d xs) (0, []) rng),
42-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y - m) U m
43-
in toNeighbour cell d xs) (0, []) rng),
44-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y + m) D m
45-
in toNeighbour cell d xs) (0, []) rng)
46-
]
47-
48-
R -> concat [
49-
snd (foldl (\(d, xs) m -> let cell = Cell (x - m, y) R (moves + m)
50-
in toNeighbour cell d xs) (0, []) rng),
51-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y - m) U m
52-
in toNeighbour cell d xs) (0, []) rng),
53-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y + m) D m
54-
in toNeighbour cell d xs) (0, []) rng)
55-
]
56-
57-
U -> concat [
58-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y - m) U (moves + m)
59-
in toNeighbour cell d xs) (0, []) rng),
60-
snd (foldl (\(d, xs) m -> let cell = Cell (x - m, y) R m
61-
in toNeighbour cell d xs) (0, []) rng),
62-
snd (foldl (\(d, xs) m -> let cell = Cell (x + m, y) L m
63-
in toNeighbour cell d xs) (0, []) rng)
64-
]
65-
66-
D -> concat [
67-
snd (foldl (\(d, xs) m -> let cell = Cell (x, y + m) D (moves + m)
68-
in toNeighbour cell d xs) (0, []) rng),
69-
snd (foldl (\(d, xs) m -> let cell = Cell (x - m, y) R m
70-
in toNeighbour cell d xs) (0, []) rng),
71-
snd (foldl (\(d, xs) m -> let cell = Cell (x + m, y) L m
72-
in toNeighbour cell d xs) (0, []) rng)
73-
]
51+
inRange Neighbour { cell } = moves cell `elem` range
7452

7553
-- Find the shortest path from start to an end using Dijkstra's algorithm.
7654
dijkstra :: Grid Int -> Node -> (Cell -> Bool) -> [Int] -> (Maybe Int, [String])
@@ -84,7 +62,7 @@ dijkstra grid@Grid { items } start isEnd range =
8462
go ds parent seen q = case extractMin q of
8563
Nothing -> (Nothing, [])
8664
Just ((du, u), q')
87-
| isEnd u -> (Just du, [])-- showDistanceMap grid ds parent u range)
65+
| isEnd u -> (Just du, showDistanceMap grid ds parent u range)
8866
| u `S.member` seen -> go ds parent seen q'
8967
| otherwise ->
9068
let adj = neighbours grid range u

17.vis.hs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import Data.Map qualified as M
2+
import Data.Set qualified as S
3+
import Data.Maybe (fromJust, fromMaybe)
4+
import Data.List (find)
5+
6+
main :: IO ()
7+
main = interact $ unlines . (\grid -> concat [p1 grid, p2 grid]) . parse
8+
9+
type Node = (Int, Int)
10+
data Grid a = Grid { items :: M.Map Node a, lastNode :: Node }
11+
12+
data Direction = L | R | U | D deriving (Eq, Ord)
13+
data Cell = Cell {
14+
node :: Node, direction :: Direction,
15+
-- The number of blocks that we have already moved in this direction.
16+
moves :: Int }
17+
deriving (Eq, Ord)
18+
19+
data Neighbour = Neighbour { cell :: Cell, distance :: Int }
20+
21+
parse :: String -> Grid Int
22+
parse s = Grid { items = M.fromList xs, lastNode = fst (last xs) }
23+
where xs = [((x, y), read [c]) | (y, l) <- enum (lines s), (x, c) <- enum l]
24+
25+
enum :: [a] -> [(Int, a)]
26+
enum = zip [0..]
27+
28+
neighbours :: Grid Int -> [Int] -> Cell -> [Neighbour]
29+
neighbours Grid { items } range = filter inRange . adjacent
30+
where
31+
adjacent Cell { node = (x, y), direction, moves } = case direction of
32+
L -> concat [cells (\m -> Cell (x + m, y) L (moves + m)),
33+
cells (\m -> Cell (x, y - m) U m),
34+
cells (\m -> Cell (x, y + m) D m)]
35+
R -> concat [cells (\m -> Cell (x - m, y) R (moves + m)),
36+
cells (\m -> Cell (x, y - m) U m),
37+
cells (\m -> Cell (x, y + m) D m)]
38+
U -> concat [cells (\m -> Cell (x, y - m) U (moves + m)),
39+
cells (\m -> Cell (x - m, y) R m),
40+
cells (\m -> Cell (x + m, y) L m)]
41+
D -> concat [cells (\m -> Cell (x, y + m) D (moves + m)),
42+
cells (\m -> Cell (x - m, y) R m),
43+
cells (\m -> Cell (x + m, y) L m)]
44+
cells c = snd (foldl (\(d, xs) m -> toNeighbour (c m) d xs) (0, []) extent)
45+
extent = [1..maximum range]
46+
toNeighbour cell d xs = case M.lookup (node cell) items of
47+
Just d2 -> (d + d2, Neighbour cell (d + d2) : xs)
48+
_ -> (d, xs)
49+
inRange Neighbour { cell } = moves cell `elem` range
50+
51+
-- Find the shortest path from start to an end using Dijkstra's algorithm.
52+
dijkstra :: Grid Int -> Node -> (Cell -> Bool) -> [Int] -> (Maybe Int, [String])
53+
dijkstra grid@Grid { items } start isEnd range =
54+
go (M.singleton startCell 0) M.empty S.empty (singleton (0, startCell))
55+
where
56+
-- By setting moves to 0, the starting cell's considers both the left and
57+
-- down neighbours as equivalent (which is what we want).
58+
startCell = Cell { node = start, direction = L, moves = 0 }
59+
60+
go ds parent seen q = case extractMin q of
61+
Nothing -> (Nothing, [])
62+
Just ((du, u), q')
63+
| isEnd u -> (Just du, showDistanceMap grid ds parent u range)
64+
| u `S.member` seen -> go ds parent seen q'
65+
| otherwise ->
66+
let adj = neighbours grid range u
67+
(ds', parent', q'') = foldl (relax u du) (ds, parent, q') adj
68+
in go ds' parent' (S.insert u seen) q''
69+
70+
relax u du (ds, parent, q) Neighbour { cell = v, distance = d } =
71+
let d' = du + d in case M.lookup v ds of
72+
Just dv | dv < d' -> (ds, parent, q)
73+
_ -> (M.insert v d' ds, M.insert v u parent, insert (d', v) q)
74+
75+
data Heap a = Empty | Heap a (Heap a) (Heap a)
76+
77+
union :: Ord a => Heap a -> Heap a -> Heap a
78+
union Empty h = h
79+
union h Empty = h
80+
union hl@(Heap l ll lr) hr@(Heap r _ _)
81+
| l <= r = Heap l (union hr lr) ll
82+
| otherwise = union hr hl
83+
84+
extractMin :: Ord a => Heap a -> Maybe (a, Heap a)
85+
extractMin Empty = Nothing
86+
extractMin (Heap x l r) = Just (x, union l r)
87+
88+
singleton :: a -> Heap a
89+
singleton x = Heap x Empty Empty
90+
91+
insert :: Ord a => a -> Heap a -> Heap a
92+
insert x h = singleton x `union` h
93+
94+
showDistanceMap :: Grid a -> M.Map Cell Int -> M.Map Cell Cell -> Cell -> [Int] -> [String]
95+
showDistanceMap Grid { lastNode = (mx, my) } ds parent end range = map line [0..my]
96+
where
97+
path = retrace S.empty end
98+
where retrace s n = let s' = S.insert n s in case M.lookup n parent of
99+
Nothing -> s'
100+
Just p -> retrace s' p
101+
isOnPath cell = S.member cell path
102+
line y = unwords $ map dist [0..mx]
103+
where dist x = showCell $ find isOnPath [
104+
Cell {node = (x, y), direction = d, moves }
105+
| d <- [L, R, U, D], moves <- range]
106+
showCell Nothing = " . "
107+
showCell (Just cell@Cell { node, moves }) =
108+
" " ++ d ++ " " ++ show moves ++ " "
109+
where d = pad3 $ show $ fromJust $ M.lookup cell ds
110+
pad3 s = reverse $ take 3 (reverse (" " ++ s))
111+
112+
p1, p2 :: Grid Int -> [String]
113+
p1 grid = runP grid [1..3]
114+
p2 grid = runP grid [4..10]
115+
116+
runP :: Grid Int -> [Int] -> [String]
117+
runP grid range = let (r, zs) = dijkstra grid (0, 0) isEnd range
118+
in zs ++ ["shortest-path result " ++ (show $ fromMaybe (-1) r)]
119+
where
120+
isEnd Cell { node } = node == (lastNode grid)

0 commit comments

Comments
 (0)