2017-12-17 19:55:59 +00:00
|
|
|
import Data.List (foldl', elemIndex)
|
2017-12-16 19:09:58 +00:00
|
|
|
import Data.List.Split (splitOn)
|
|
|
|
import Data.Function ((&))
|
2017-12-17 19:55:59 +00:00
|
|
|
import Data.Map.Strict (Map, (!), insert, fromList, toList, toAscList)
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 19:55:59 +00:00
|
|
|
type Positions = Map Int Int
|
|
|
|
type Swaps = Map Char Char
|
|
|
|
type State = (Int, Positions, Swaps)
|
|
|
|
(%) = mod
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 06:30:06 +00:00
|
|
|
exchange :: Int -> Int -> State -> State
|
2017-12-17 19:55:59 +00:00
|
|
|
exchange x y (s, positions, swaps) =
|
|
|
|
let spunX = (x + 16 - s) % 16
|
|
|
|
spunY = (y + 16 - s) % 16
|
|
|
|
in (s, insert spunX (positions ! spunY) . insert spunY (positions ! spunX) $ positions, swaps)
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 06:30:06 +00:00
|
|
|
partner :: Char -> Char -> State -> State
|
2017-12-17 19:55:59 +00:00
|
|
|
partner p q (s, positions, swaps) =
|
|
|
|
(s, positions, insert p (swaps ! q) . insert q (swaps ! p) $ swaps)
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 19:55:59 +00:00
|
|
|
spin :: Int -> State -> State
|
|
|
|
spin s' (s, positions, swaps) = ((s + s') % 16, positions, swaps)
|
2017-12-17 06:30:06 +00:00
|
|
|
|
|
|
|
parseMove :: String -> State -> State
|
2017-12-16 19:09:58 +00:00
|
|
|
parseMove str =
|
2017-12-17 06:30:06 +00:00
|
|
|
case head str of
|
2017-12-17 19:55:59 +00:00
|
|
|
's' -> spin . read $ tail str
|
2017-12-17 06:30:06 +00:00
|
|
|
'x' -> let x : y : [] = splitOn "/" $ tail str
|
|
|
|
in exchange (read x) (read y)
|
2017-12-16 19:09:58 +00:00
|
|
|
'p' -> let p : '/' : q : [] = tail str
|
2017-12-17 06:30:06 +00:00
|
|
|
in partner p q
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 06:30:06 +00:00
|
|
|
dance :: [State -> State] -> State -> State
|
|
|
|
dance moves state = foldl' (&) state moves
|
2017-12-16 19:09:58 +00:00
|
|
|
|
2017-12-17 19:55:59 +00:00
|
|
|
applyDance :: State -> String -> String
|
|
|
|
applyDance (s, positions, swaps) str =
|
|
|
|
let positionsList = snd . unzip . toAscList $ positions
|
|
|
|
swapsReversed = fromList . (uncurry $ flip zip) . unzip . toList $ swaps
|
|
|
|
in map (swapsReversed !) . (drop (16 - s) <++> take (16 - s)) . map (str !!) $ positionsList
|
|
|
|
where (f <++> g) p = f p ++ g p
|
2017-12-16 19:09:58 +00:00
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
main = do
|
|
|
|
moves <- fmap (map parseMove . splitOn ",") $ readFile "16.txt"
|
2017-12-17 19:55:59 +00:00
|
|
|
let ip = [0..15]; ap = ['a'..'p']
|
|
|
|
state = dance moves (0, fromList $ zip ip ip, fromList $ zip ap ap)
|
|
|
|
dances = iterate (applyDance state) ap
|
|
|
|
Just cycleSize = (+ 1) <$> (elemIndex ap $ tail dances)
|
|
|
|
print $ dances !! 1
|
|
|
|
print $ dances !! (1000000000 % cycleSize)
|