Guest User

Untitled

a guest
Dec 13th, 2018
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.34 KB | None | 0 0
  1. {-# LANGUAGE LambdaCase, TupleSections, ViewPatterns #-}
  2. module Solve where
  3.  
  4. import System.Console.ANSI
  5. import Control.Concurrent
  6. import Control.Monad
  7.  
  8. import System.IO.Unsafe
  9.  
  10. import Data.Map.Strict (Map(..))
  11. import qualified Data.Map.Strict as M
  12.  
  13. import Data.Maybe
  14. import Data.List
  15.  
  16. type Vec2 = (Int, Int)
  17.  
  18. data Choice = TurnLeft | Straight | TurnRight deriving (Show, Eq, Enum)
  19.  
  20. data Cart = Cart { position :: Vec2
  21. , velocity :: Vec2
  22. , choice :: [Choice] } deriving Eq
  23.  
  24. instance Show Cart where
  25. show (Cart pos velocity (choice:choices)) = "Cart@" ++ show pos ++ " going " ++ show velocity ++ " nextchoice:" ++ show choice
  26.  
  27. type Track = Map (Int, Int) TrackPiece
  28.  
  29. data TrackPiece = Vertical
  30. | Horizontal
  31. | Bidirectional
  32. | LeftDown
  33. | RightUp
  34. deriving Show
  35.  
  36. showPiece :: TrackPiece -> Char
  37. showPiece Vertical = '|'
  38. showPiece Horizontal = '-'
  39. showPiece Bidirectional = '+'
  40. showPiece LeftDown = '\\'
  41. showPiece RightUp = '/'
  42.  
  43. showTrack :: Track -> String
  44. showTrack m = show $ M.toList m
  45.  
  46. showCart :: Cart -> Char
  47. showCart (Cart _ ( 1, 0) _) = '>'
  48. showCart (Cart _ (-1, 0) _) = '<'
  49. showCart (Cart _ ( 0, 1) _) = 'v'
  50. showCart (Cart _ ( 0, -1) _) = '^'
  51.  
  52. data State = State { carts :: [Cart]
  53. , track :: Track } deriving Show
  54.  
  55. parseTrackPiece :: Char -> Maybe TrackPiece
  56. parseTrackPiece '|' = Just Vertical
  57. parseTrackPiece '-' = Just Horizontal
  58. parseTrackPiece '+' = Just Bidirectional
  59. parseTrackPiece '\\' = Just LeftDown
  60. parseTrackPiece '/' = Just RightUp
  61. parseTrackPiece c | c `elem` "<>^v" = Just $ trackFromCart $ cartFromC (0, 0) c
  62. | otherwise = Nothing
  63.  
  64. trackFromCart :: Cart -> TrackPiece
  65. trackFromCart (Cart _ (_, 0) _) = Horizontal
  66. trackFromCart (Cart _ (0, _) _) = Vertical
  67.  
  68. cartFromC :: (Int, Int) -> Char -> Cart
  69. cartFromC pos = \case '^' -> Cart pos ( 0, -1) choices
  70. 'v' -> Cart pos ( 0, 1) choices
  71. '>' -> Cart pos ( 1, 0) choices
  72. '<' -> Cart pos (-1, 0) choices
  73. where choices = cycle $ enumFromTo TurnLeft TurnRight
  74.  
  75. move :: Cart -> Cart
  76. move (Cart (x, y) (xvel, yvel) c) = Cart (x + xvel, y + yvel) (xvel, yvel) c
  77.  
  78. rotLeft (x, y) = (y, -x)
  79. rotRight (x, y) = (-y, x)
  80.  
  81. modifyCart :: TrackPiece -> Cart -> Cart
  82. modifyCart Vertical c = move c
  83. modifyCart Horizontal c = move c
  84. modifyCart Bidirectional (Cart p vel (choice:choices)) = case choice of
  85. TurnLeft -> move (Cart p (rotLeft vel) choices)
  86. Straight -> move (Cart p vel choices)
  87. TurnRight -> move (Cart p (rotRight vel) choices)
  88. modifyCart LeftDown (Cart (x, y) (xv, yv) choice) = move $ Cart (x, y) (yv, xv) choice
  89. modifyCart RightUp (Cart (x, y) (xv, yv) choice) = move $ Cart (x, y) (-yv, -xv) choice
  90.  
  91.  
  92. getTrackUnderCart :: Cart -> Track -> TrackPiece
  93. getTrackUnderCart (Cart (x, y) _ _) track = track M.! (x, y)
  94.  
  95. stepCart :: Cart -> Track -> Cart
  96. stepCart cart track = modifyCart piece cart
  97. where piece = getTrackUnderCart cart track
  98.  
  99. parseInput :: String -> State
  100. parseInput str = State (parseCarts str) $ parseLines str
  101.  
  102. parseCarts :: String -> [Cart]
  103. parseCarts = concatMap (uncurry getCartsLine) . zip [0..] . lines
  104.  
  105. getCartsLine :: Int -> String -> [Cart]
  106. getCartsLine y cs = [ cartFromC (x, y) c
  107. | (x, c) <- zip [0..] cs
  108. , c `elem` "<>^v" ]
  109.  
  110. parseLine :: Int -> String -> Track
  111. parseLine y = M.fromList . mapMaybe (\(x, char) -> ((x, y),) <$> parseTrackPiece char) . zip [0..]
  112.  
  113. parseLines :: String -> Track
  114. parseLines = foldr M.union M.empty . zipWith parseLine [0 ..] . lines
  115.  
  116. printTrack :: (Int, Int) -> Track -> IO ()
  117. printTrack (xo, yo) track = forM_ (M.assocs track) $ \((x, y), piece) -> do
  118. setCursorPosition (y + yo) (x + xo)
  119. putChar $ showPiece piece
  120.  
  121. printCarts :: (Int, Int) -> [Cart] -> IO ()
  122. printCarts (xo, yo) carts = forM_ carts $ \cart@(Cart (x, y) (_, _) _) -> do
  123. setCursorPosition (y + yo) (x + xo)
  124. putChar $ showCart cart
  125.  
  126.  
  127. printTrackSubset :: (Int, Int) -> Int -> (Int, Int) -> Track -> IO ()
  128. printTrackSubset (xo, yo) sz (tx, ty) track = forM_ (M.assocs track) $ \((x, y), piece) -> do
  129. guard (x > (tx + sz) || x < (tx - sz) || y > (ty + sz) || y < (ty - sz))
  130. setCursorPosition (y + yo) (x + xo)
  131. putChar $ showPiece piece
  132.  
  133. printState :: (Int, Int) -> State -> IO ()
  134. printState (x, y) (State c t) = printTrack (x, y) t >> printCarts (x, y) c
  135.  
  136. hasCollided :: Cart -> [Cart] -> Bool
  137. hasCollided c = isJust . getCollision c
  138.  
  139.  
  140. getCollision :: Cart -> [Cart] -> Maybe Cart
  141. getCollision c = find (collide c)
  142.  
  143. collide :: Cart -> Cart -> Bool
  144. collide a b = position a == position b
  145.  
  146. -- step' :: ([Cart], State) -> ([Cart], State)
  147. -- step' (collisions, State (sortPositions position -> carts) track) = (newCollisions, State newCarts track)
  148. -- where (newCollisions, newCartsUnfiltered) = foldr (reductor' track) (collisions, []) $ tails carts
  149. -- newCarts = filter (`notElem` newCollisions) newCartsUnfiltered
  150.  
  151. stepMe :: ([Cart], State) -> ([Cart], State)
  152. stepMe (collisions, State (sortPositions position -> carts) track) = (newCollisions, State newCarts track)
  153. where (newCollisions, newCarts) = go track carts (collisions, [])
  154. go track [] s = s
  155. go track (((`stepCart` track) -> sCart):carts) (currCollisions, newCarts)
  156. | hasCollided sCart newCarts =
  157. go track carts (sCart : currCollisions, filter (not . collide sCart) newCarts)
  158. | otherwise = case getCollision sCart carts of
  159. Nothing -> go track carts (currCollisions, sCart : newCarts)
  160. Just other -> go track (filter (not . collide sCart) carts) (other : sCart : collisions, newCarts)
  161. -- Nothing -> go track carts (collisions, sCart : newCarts)
  162.  
  163.  
  164. -- step'' :: ([Cart], State) -> ([Cart], State)
  165. -- step'' (collisions, State (sortPositions position -> carts) track) = (newCollisions, State newCarts track)
  166. -- where (newCollisions, newCarts) = reductor'' track carts (collisions, [])
  167.  
  168. -- reductor'' :: Track -> [Cart] -> ([Cart], [Cart]) -> ([Cart], [Cart])
  169. -- reductor'' track [] (collisions, newCarts) = (collisions, newCarts)
  170. -- reductor'' track (cart:carts) (collisions, newCarts)
  171. -- | hasCollided (stepCart cart track) newCarts =
  172. -- reductor'' track carts (stepCart cart track : collisions, filter (not . collide (stepCart cart track)) newCarts)
  173. -- | hasCollided (stepCart cart track) carts =
  174. -- case getCollision (stepCart cart track) carts of
  175. -- Just other -> reductor'' track carts (other : stepCart cart track : collisions, newCarts)
  176. -- | otherwise = reductor'' track carts (collisions, stepCart cart track : newCarts)
  177.  
  178. -- reductor' :: Track -> [Cart] -> ([Cart], [Cart]) -> ([Cart], [Cart])
  179. -- reductor' track [] (collisions, newCarts) = (collisions, newCarts)
  180. -- reductor' track (cart:carts) (collisions, newCarts) | hasCollided (stepCart cart track) newCarts =
  181. -- (stepCart cart track : collisions, filter (not . collide cart) newCarts)
  182. -- | hasCollided (stepCart cart track) carts =
  183. -- case getCollision (stepCart cart track) carts of
  184. -- Just other -> (other : stepCart cart track : collisions, newCarts)
  185. -- | otherwise = (collisions, stepCart cart track : newCarts)
  186.  
  187.  
  188. -- reductor :: Track -> [Cart] -> Cart -> ([Cart], [Cart]) -> ([Cart], [Cart])
  189. -- reductor track carts v (collisions, newCarts) | hasCollided (stepCart v track) carts =
  190. -- (stepCart v track : collisions, filter (not . collide v) $ filter (not . collide (stepCart v track)) newCarts)
  191. -- | otherwise = (collisions, stepCart v track : newCarts)
  192.  
  193. -- step :: ([Cart], State) -> ([Cart], State)
  194. -- step (collisions, State (sortPositions position -> carts) track) = (newCollisions, State newCarts track)
  195. -- where (newCollisions, newCarts) = foldr (reductor track carts) (collisions, []) carts
  196.  
  197.  
  198. sortPositions :: (a -> Vec2) -> [a] -> [a]
  199. sortPositions f = concat
  200. . sortOn ((snd . f) . head)
  201. . groupBy (\a b -> (fst . f) a == (fst . f) b)
  202. . sortOn (fst . f)
  203.  
  204. solve :: String -> IO ()
  205. solve path = do
  206. f <- readFile path
  207.  
  208. clearScreen
  209.  
  210. let s = parseInput f
  211.  
  212. let start = ([], s) :: ([Cart], State)
  213.  
  214. let loop (coll, st) i c = do
  215. -- when (i == 100) $ do
  216. -- clearScreen
  217. -- printState (0, 8) st
  218. -- setCursorPosition 500 0
  219.  
  220. -- putStr $ show (length . carts $ st) ++ "; "
  221.  
  222. -- print coll
  223. -- print $ head $ carts st
  224. -- threadDelay 1000000
  225.  
  226. when (c /= length coll) $ do
  227. let collision = head coll
  228.  
  229. printTrackSubset (10, 10) 5 (position collision) (track st)
  230.  
  231. threadDelay 1000000
  232.  
  233.  
  234.  
  235.  
  236. -- when (not . null $ ) $
  237. -- print coll
  238.  
  239. if length (carts st) > 1
  240. then
  241. loop (stepMe (coll, st)) (succ i) (length coll)
  242. else print (fst . stepMe $ (coll, st))
  243.  
  244.  
  245. loop ([], s) 0 0
  246.  
  247. pure ()
Add Comment
Please, Sign In to add comment