Skip to content

Latest commit

 

History

History
51 lines (39 loc) · 2.05 KB

day21.md

File metadata and controls

51 lines (39 loc) · 2.05 KB

Everything reveals itself if we imagine a lookup table of "best path from A to B". For my own purposes I've made the functions parameterized by button pad, using Maybe a, where Nothing is the A key and Just x is the x key.

type LookupTable a b = Map (Maybe a) (Map (Maybe a) [Maybe b])

type LookupTableLengths a = Map (Maybe a) (Map (Maybe a) Int)

toLengths :: LookupTable a b -> LookupTableLengths a
toLengths = fmap (fmap length)

The key is that now these maps are composable:

spellDirPathLengths :: Ord a => LookupTableLengths a -> [Maybe a] -> Int
spellDirPathLengths mp xs = sum $ zipWith (\x y -> (mp M.! x) M.! y) xs (drop 1 xs)

composeDirPathLengths :: Ord b => LookupTableLengths b -> LookupTable a b -> LookupTableLengths a
composeDirPathLengths mp = (fmap . fmap) (spellDirPathLengths mp . (Nothing :))

That is, if you have the lookup table for two layers, you can compose them to create one big lookup table.

data Dir = North | East | West | South
data NumButton = Finite 10

dirPathChain :: [LookupTableLengths NumButton]
dirPathChain = iterate (`composeDirPathLengths` dirPath @Dir) (dirPathCosts @Dir)

solveCode :: Int -> [Maybe NumButton] -> Int
solveCode n = spellDirPathLengths mp . (Nothing :)
  where
    lengthChain = dirPathChain !! (n - 1)
    mp = lengthChain `composeDirPathLengths` dirPath @NumButton

The nice thing is that you only need to compute dirPathChain once, to get the final LookupTableLengths for a given n, and you can re-use it for everything.

Generating the actual LookupTable NumButton Dir and LookupTable Dir Dir is the tricky part. For me I generated it based on the shortest path considering the third bot up the chain from the bottom: I used an fgl graph where the nodes were the state of three bots and the edges were the actions that the fourth "controller" would take, and computed the shortest path in terms of the fourth controller. This seems to be the magic number: anything higher and you get the same answer, anything lower and you get suboptimal final paths.