Skip to content
This repository was archived by the owner on Nov 17, 2024. It is now read-only.

Commit db8e52c

Browse files
committed
cleaner types for day 12 before refactor algorithm
1 parent a6c275f commit db8e52c

File tree

1 file changed

+97
-28
lines changed

1 file changed

+97
-28
lines changed

src/AOC/Challenge/Day12.hs

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ module AOC.Challenge.Day12 (
2828

2929
import AOC.Prelude
3030

31+
import Data.Bitraversable
32+
import Data.Finitary
33+
import qualified AOC.Common.FinitarySet as FS
3134
import qualified Data.Graph.Inductive as G
3235
import qualified Data.IntMap as IM
3336
import qualified Data.IntSet as IS
@@ -45,48 +48,114 @@ import qualified Text.Megaparsec as P
4548
import qualified Text.Megaparsec.Char as P
4649
import qualified Text.Megaparsec.Char.Lexer as PP
4750

48-
-- False: small
49-
-- True: large
50-
toAdjMatrix :: [(String, String)] -> Map String [(Bool, String)]
51-
toAdjMatrix = fmap (mapMaybe postProcess)
52-
. M.fromListWith (++)
51+
data SrcNode = StartNode
52+
| SrcCave Cave
53+
deriving stock (Generic, Eq, Ord, Show)
54+
deriving anyclass (Finitary)
55+
56+
data DestNode = DestCave Cave
57+
| EndNode
58+
deriving stock (Generic, Eq, Ord, Show)
59+
deriving anyclass (Finitary)
60+
61+
data FullNode = FullStart
62+
| FullCave Cave
63+
| FullEnd
64+
deriving stock (Generic, Eq, Ord, Show)
65+
deriving anyclass (Finitary)
66+
67+
data Ident = Ident (Finite 26) (Maybe (Finite 26))
68+
deriving stock (Generic, Eq, Ord, Show)
69+
deriving anyclass (Finitary)
70+
71+
data Cave = Big Ident
72+
| Small Ident
73+
deriving stock (Generic, Eq, Ord, Show)
74+
deriving anyclass (Finitary)
75+
76+
classify :: String -> Maybe FullNode
77+
classify "start" = Just FullStart
78+
classify "end" = Just FullEnd
79+
classify [a] = charFinite a <&> \case
80+
(False, x) -> FullCave $ Small (Ident x Nothing)
81+
(True , x) -> FullCave $ Big (Ident x Nothing)
82+
classify [a,b] = do
83+
(cx, x) <- charFinite a
84+
(cy, y) <- charFinite b
85+
let ident = Ident x (Just y)
86+
case (cx, cy) of
87+
(False, False) -> Just . FullCave $ Small ident
88+
(True , True ) -> Just . FullCave $ Big ident
89+
_ -> Nothing
90+
classify _ = Nothing
91+
92+
srcDest :: FullNode -> (Maybe SrcNode, Maybe DestNode)
93+
srcDest = \case
94+
FullStart -> (Just StartNode, Nothing)
95+
FullCave c -> (Just (SrcCave c), Just (DestCave c))
96+
FullEnd -> (Nothing, Just EndNode)
97+
98+
toAdjMatrix :: [(FullNode, FullNode)] -> Map SrcNode [DestNode]
99+
toAdjMatrix = M.fromListWith (++)
53100
. concatMap (uncurry buildLinks)
54101
where
55-
buildLinks a b = [(a, [b]), (b, [a])]
56-
postProcess str = (all isUpper str, str) <$ guard (str /= "start")
102+
toLink a b = (a, [b])
103+
buildLinks a b = catMaybes
104+
[ toLink <$> srcA <*> destB
105+
, toLink <$> srcB <*> destA
106+
]
107+
where
108+
(srcA, destA) = srcDest a
109+
(srcB, destB) = srcDest b
57110

58-
day12a :: [(String, String)] :~> Int
111+
day12a :: [(FullNode, FullNode)] :~> Int
59112
day12a = MkSol
60-
{ sParse = traverseLines $ listTup . splitOn "-"
113+
{ sParse = traverseLines $ bitraverse classify classify <=< listTup . splitOn "-"
61114
, sShow = show
62115
, sSolve = Just . length . findPaths . toAdjMatrix
63116
}
64117

65-
findPaths :: Map String [(Bool, String)] -> [[String]]
66-
findPaths mp = go S.empty "start"
118+
findPaths :: Map SrcNode [DestNode] -> [[Cave]]
119+
findPaths mp = do
120+
nextBranch <- mp M.! StartNode
121+
case nextBranch of
122+
EndNode -> pure []
123+
DestCave v@(Big _) -> go FS.empty v
124+
DestCave v@(Small c) -> go (FS.singleton c) v
67125
where
68-
go seen currPos
69-
| currPos == "end" = pure ["end"]
70-
| otherwise = do
71-
(isLarge, nextBranch) <- mp M.! currPos
72-
guard $ isLarge || (nextBranch `S.notMember` seen)
73-
(currPos:) <$> go (S.insert nextBranch seen) nextBranch
74-
75-
day12b :: [(String, String)] :~> Int
126+
go :: FS.FinitarySet Ident -> Cave -> [[Cave]]
127+
go seen currPos = do
128+
nextBranch <- mp M.! SrcCave currPos
129+
case nextBranch of
130+
EndNode -> pure [currPos]
131+
DestCave v@(Big _) -> (currPos:) <$> go seen v
132+
DestCave v@(Small c) -> do
133+
guard $ c `FS.notMember` seen
134+
(currPos:) <$> go (c `FS.insert` seen) v
135+
136+
day12b :: [(FullNode, FullNode)] :~> Int
76137
day12b = MkSol
77138
{ sParse = sParse day12a
78139
, sShow = show
79140
, sSolve = Just . length . findPaths2 . toAdjMatrix
80141
}
81142

82-
findPaths2 :: Map String [(Bool, String)] -> [[String]]
83-
findPaths2 mp = go S.empty Nothing "start"
143+
findPaths2 :: Map SrcNode [DestNode] -> [[Cave]]
144+
findPaths2 mp = do
145+
nextBranch <- mp M.! StartNode
146+
case nextBranch of
147+
EndNode -> pure []
148+
DestCave v@(Big _) -> go FS.empty Nothing v
149+
DestCave v@(Small c) -> go (FS.singleton c) Nothing v
84150
where
85-
go seen seenTwice currPos
86-
| currPos == "end" = pure ["end"]
87-
| otherwise = do
88-
(isLarge, nextBranch) <- mp M.! currPos
89-
newSeenTwice <- if not isLarge && (nextBranch `S.member` seen)
90-
then Just nextBranch <$ guard (isNothing seenTwice)
151+
go :: FS.FinitarySet Ident -> Maybe Ident -> Cave -> [[Cave]]
152+
go seen seenTwice currPos = do
153+
nextBranch <- mp M.! SrcCave currPos
154+
case nextBranch of
155+
EndNode -> pure [currPos]
156+
DestCave v@(Big _) -> (currPos:) <$> go seen seenTwice v
157+
DestCave v@(Small c) -> do
158+
newSeenTwice <- if c `FS.member` seen
159+
then Just c <$ guard (isNothing seenTwice)
91160
else pure seenTwice
92-
(currPos:) <$> go (S.insert nextBranch seen) newSeenTwice nextBranch
161+
(currPos:) <$> go (c `FS.insert` seen) newSeenTwice v

0 commit comments

Comments
 (0)