Skip to content

Commit 26095be

Browse files
committed
comments
1 parent 4d0c0b4 commit 26095be

File tree

1 file changed

+49
-24
lines changed

1 file changed

+49
-24
lines changed

solutions/src/2022/22_alt.hs

+49-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# Language QuasiQuotes, TemplateHaskell, ImportQualifiedPost, LambdaCase, ImplicitParams, BangPatterns, DataKinds #-}
1+
{-# Language QuasiQuotes, ConstraintKinds, TemplateHaskell, ImportQualifiedPost, LambdaCase, ImplicitParams, DataKinds #-}
22
{-|
33
Module : Main
44
Description : Day 22 solution
@@ -8,6 +8,10 @@ Maintainer : [email protected]
88
99
<https://adventofcode.com/2022/day/22>
1010
11+
This solution works by first exploring the input file and assigning a cube
12+
location to each flattened location. The path is explored in terms of the cube
13+
coordinates and then is converted back into input file coordinates at the end.
14+
1115
>>> :{
1216
:main + " ...#
1317
.#..
@@ -40,28 +44,41 @@ import Data.Map qualified as Map
4044
import Data.Maybe (isJust)
4145
import Data.Set (Set)
4246
import Data.Set qualified as Set
47+
import qualified Advent.AsmProg as cube
4348

4449
data D = DL | DR
4550

4651
stageTH
4752

53+
type HiVal = ?hiVal :: Int
54+
4855
-- |
4956
-- >>> :main
5057
-- 55267
5158
main :: IO ()
5259
main =
5360
do (rawmap, path) <- [format|2022 22 (( |.|#)*!%n)*%n(%u|@D)*%n|]
61+
62+
-- figure out the side-length of the cube we're working with
63+
-- so that we can handle both examples and regular inputs
5464
let elts = countBy (`elem` ".#") (concat rawmap)
55-
let ?highVal = until (\x -> 6*x*x >= elts) (1 +) 1 - 1
65+
let ?hiVal = until (\x -> 6*x*x >= elts) (1 +) 1 - 1
66+
67+
-- associate cube coordinates with all of the input file coordinates
5668
let maze = explore (Set.fromList [c | (c, '.') <- coordLines rawmap])
57-
(endLoc, endFacing) = foldl (applyCommand maze) (originLoc, 0) path
58-
Just (C y x) = onMaze maze endLoc
59-
endFacing' = fixFacing maze endLoc endFacing
60-
print (1000 * (y + 1) + 4 * (x + 1) + endFacing')
69+
70+
-- figure out the cube coordinate that our path ends on
71+
let S endLoc endFacing = fixFacing maze (foldl (applyCommand maze) (S originLoc 0) path)
72+
73+
-- translate the cube coordinates back into flat coordinates
74+
let C y x = maze Map.! endLoc
75+
76+
-- compute the "password" from the end location
77+
print (1000 * (y + 1) + 4 * (x + 1) + endFacing)
6178

6279
-- | Given the set of flat path coordinates compute the cube-coordinate
6380
-- to flat coordinate map.
64-
explore :: (?highVal :: Int) => Set Coord -> Map Loc Coord
81+
explore :: HiVal => Set Coord -> Map Loc Coord
6582
explore input = Map.fromList (dfsOn snd step (originLoc, Set.findMin input))
6683
where
6784
step (l, c) =
@@ -70,19 +87,24 @@ explore input = Map.fromList (dfsOn snd step (originLoc, Set.findMin input))
7087
[(locUp l, above c) | above c `Set.member` input] ++
7188
[(locDown l, below c) | below c `Set.member` input]
7289

73-
applyCommand :: (?highVal :: Int) => Map Loc Coord -> (Loc, Facing) -> Either Int D -> (Loc, Facing)
74-
applyCommand maze (!here, !dir) = \case
75-
Left n -> (walkN maze n dir here, dir)
76-
Right t -> (here, turn t dir)
90+
-- | A location on the cube and a direction
91+
data S = S !Loc !Facing
92+
93+
-- | Apply a command to the state of the walker on the cube.
94+
-- Each move is either forward a certain number or a turn.
95+
applyCommand :: HiVal => Map Loc Coord -> S -> Either Int D -> S
96+
applyCommand maze (S here dir) = \case
97+
Left n -> S (walkN maze n dir here) dir
98+
Right t -> S here (turn t dir)
7799

78100
-- | Walk a number of steps in the given direction
79-
walkN :: (?highVal :: Int) => Map Loc Coord -> Int -> Facing -> Loc -> Loc
101+
walkN :: HiVal => Map Loc Coord -> Int -> Facing -> Loc -> Loc
80102
walkN maze n dir here = last (takeWhile valid (take (n + 1) (iterate (move dir) here)))
81103
where valid = isJust . onMaze maze
82104

83105
-- | Find the location in the input file corresponding to this
84106
-- cube location if one exists.
85-
onMaze :: (?highVal :: Int) => Map Loc Coord -> Loc -> Maybe Coord
107+
onMaze :: HiVal => Map Loc Coord -> Loc -> Maybe Coord
86108
onMaze maze loc = msum (map (`Map.lookup` maze) (take 4 (iterate locRotate loc)))
87109

88110
-- | Symmetric group S4 corresponds to the symmetries of a cube.
@@ -97,42 +119,45 @@ rotZ = mkPermutation ([2,3,1,0]!!)
97119
data Loc = Loc { locFace :: S4, locCoord :: Coord }
98120
deriving (Show, Ord, Eq)
99121

122+
-- | Initial location on the top-left or a face.
100123
originLoc :: Loc
101124
originLoc = Loc mempty origin
102125

103-
locRight, locLeft, locUp, locDown, locRotate :: (?highVal :: Int) => Loc -> Loc
126+
locRight, locLeft, locUp, locDown, locRotate :: HiVal => Loc -> Loc
104127
locRight (Loc p (C y x))
105-
| x < ?highVal = Loc p (C y (x + 1))
128+
| x < ?hiVal = Loc p (C y (x + 1))
106129
| otherwise = Loc (p <> invert rotY) (C y 0)
107130

108131
locLeft (Loc p (C y x))
109132
| 0 < x = Loc p (C y (x - 1))
110-
| otherwise = Loc (p <> rotY) (C y ?highVal)
133+
| otherwise = Loc (p <> rotY) (C y ?hiVal)
111134

112135
locDown (Loc p (C y x))
113-
| y < ?highVal = Loc p (C (y + 1) x)
136+
| y < ?hiVal = Loc p (C (y + 1) x)
114137
| otherwise = Loc (p <> rotX) (C 0 x)
115138

116139
locUp (Loc p (C y x))
117140
| 0 < y = Loc p (C (y - 1) x)
118-
| otherwise = Loc (p <> invert rotX) (C ?highVal x)
141+
| otherwise = Loc (p <> invert rotX) (C ?hiVal x)
119142

120-
locRotate (Loc p (C y x)) = Loc (p <> rotZ) (C x (?highVal - y))
143+
-- Rotate the representation of the current location 90-degrees
144+
-- clockwise in order to put it onto a symmetric cube-face.
145+
locRotate (Loc p (C y x)) = Loc (p <> rotZ) (C x (?hiVal - y))
121146

122147
-- | Rotate the facing until we're on the cube face as it
123148
-- is oriented on the input text.
124-
fixFacing :: (?highVal :: Int) => Map Loc Coord -> Loc -> Facing -> Facing
125-
fixFacing maze loc n
126-
| Map.member loc maze = n
127-
| otherwise = fixFacing maze (locRotate loc) (turn DR n)
149+
fixFacing :: HiVal => Map Loc Coord -> S -> S
150+
fixFacing maze (S loc n)
151+
| Map.member loc maze = S loc n
152+
| otherwise = fixFacing maze (S (locRotate loc) (turn DR n))
128153

129154
type Facing = Int
130155

131156
turn :: D -> Facing -> Facing
132157
turn DL x = (x - 1) `mod` 4
133158
turn DR x = (x + 1) `mod` 4
134159

135-
move :: (?highVal :: Int) => Facing -> Loc -> Loc
160+
move :: HiVal => Facing -> Loc -> Loc
136161
move 0 = locRight
137162
move 1 = locDown
138163
move 2 = locLeft

0 commit comments

Comments
 (0)