@@ -14,15 +14,17 @@ where
14
14
15
15
import AOC.Common (digitToIntSafe , (!!!) )
16
16
import AOC.Common.Point (Dir (.. ), Point , V2 (V2 ), dirPoint )
17
- import AOC.Common.Search (bfsActions )
18
17
import AOC.Solver (noFail , type (:~> ) (.. ))
18
+ import Control.Applicative (liftA3 )
19
19
import Control.Monad (mfilter , (<=<) )
20
20
import Data.Char (intToDigit , isDigit )
21
21
import Data.Finite (Finite , finites )
22
+ import Data.Functor ((<&>) )
23
+ import qualified Data.Graph.Inductive as G
22
24
import Data.Map (Map )
23
25
import qualified Data.Map as M
24
- import Data.Maybe (fromJust , mapMaybe , maybeToList )
25
- import qualified Data.Set as S
26
+ import Data.Maybe (mapMaybe , maybeToList )
27
+ import Data.Tuple ( swap )
26
28
27
29
type NumPad = Maybe (Finite 10 )
28
30
type DirPad = Maybe Dir
@@ -82,32 +84,50 @@ instance Pushable (Finite 10) where
82
84
allPushable = finites
83
85
pushMap = pushMapFromLayout numPad
84
86
87
+ buttonGraph ::
88
+ forall a .
89
+ Pushable a =>
90
+ (G. Gr (Either (Maybe a , DirPad , DirPad ) (Maybe a )) DirPad , Map (Maybe a ) Int , Map (Maybe a ) Int )
91
+ buttonGraph = (G. mkGraph (swap <$> M. toList nodes) edges, startMap, endMap)
92
+ where
93
+ nodes :: Map (Either (Maybe a , DirPad , DirPad ) (Maybe a )) Int
94
+ nodes =
95
+ M. fromList . flip zip [0 .. ] $
96
+ (Left <$> liftA3 (,,) allPushable' allPushable' allPushable')
97
+ ++ (Right <$> allPushable')
98
+ startMap =
99
+ M. fromList
100
+ [ (n, i)
101
+ | (Left (n, Nothing , Nothing ), i) <- M. toList nodes
102
+ ]
103
+ endMap =
104
+ M. fromList
105
+ [ (n, i)
106
+ | (Right n, i) <- M. toList nodes
107
+ ]
108
+ edges :: [(Int , Int , DirPad )]
109
+ edges = do
110
+ (Left (b, d, e), node) <- M. toList nodes
111
+ push <- reverse allPushable'
112
+ (e', eout) <- maybeToList $ applyPush push e
113
+ (d', dout) <- case eout of
114
+ Nothing -> pure (d, Nothing )
115
+ Just push' -> maybeToList $ applyPush push' d
116
+ (b', bout) <- case dout of
117
+ Nothing -> pure (b, Nothing )
118
+ Just push' -> maybeToList $ applyPush push' b
119
+ pure case bout of
120
+ Nothing -> (node, nodes M. ! Left (b', d', e'), push)
121
+ Just o -> (node, nodes M. ! Right o, push)
122
+
85
123
-- | Best way to get from button to button. penalize motion two bots down
86
124
dirPath :: forall a . Pushable a => Map (Maybe a ) (Map (Maybe a ) [DirPad ])
87
- dirPath = M. fromSet ((`M.fromSet` S. fromList allPushable') . go) (S. fromList allPushable')
125
+ dirPath =
126
+ st <&> \ i ->
127
+ en <&> \ j ->
128
+ runPath Nothing . runPath Nothing . drop 1 . map snd . G. unLPath $ G. lesp i j bg
88
129
where
89
- go :: Maybe a -> Maybe a -> [DirPad ]
90
- go x y =
91
- runPath Nothing . runPath Nothing . fromJust $
92
- bfsActions step (Left (x, Nothing , Nothing )) (== Right y)
93
- where
94
- step (Left (b, d, e)) =
95
- reverse
96
- [ ( push
97
- , case bout of
98
- Nothing -> Left (b', d', e')
99
- Just o -> Right o
100
- )
101
- | push <- allPushable'
102
- , (e', eout) <- maybeToList $ applyPush push e
103
- , (d', dout) <- case eout of
104
- Nothing -> pure (d, Nothing )
105
- Just push' -> maybeToList $ applyPush push' d
106
- , (b', bout) <- case dout of
107
- Nothing -> pure (b, Nothing )
108
- Just push' -> maybeToList $ applyPush push' b
109
- ]
110
- step (Right _) = []
130
+ (bg, st, en) = buttonGraph
111
131
112
132
dirPathCosts :: Pushable a => Map (Maybe a ) (Map (Maybe a ) Int )
113
133
dirPathCosts = (fmap . fmap ) length dirPath
0 commit comments