import Data.List (transpose, delete) import Data.List.Split (chunksOf, splitOn) import Data.Char (isSpace) data Command = Move Int Int Int type State = [[Char]] parseInit :: [String] -> State parseInit s = map (dropWhile isSpace . init . (!!1)) (chunksOf 4 $ transpose s) parseCmds :: [String] -> [Command] parseCmds s = map readCmd s where readCmd s = let w = words s in Move (read (w !! 1)) (read (w !! 3) - 1) (read (w !! 5) - 1) listApp :: Int -> (a -> a) -> [a] -> [a] listApp 0 f (x:xs) = f x : xs listApp n f (x:xs) = x : listApp (n-1) f xs moveN :: Command -> State -> State moveN (Move 0 _ _) = id moveN (Move n f t) = moveN (Move (n-1) f t) . move (Move 1 f t) move :: Command -> State -> State move (Move n f t) state = addTo $ popFrom state where popFrom = listApp f (drop n) elems = take n (state !! f) addTo = listApp t (elems ++ ) main :: IO () main = do [init', cmds'] <- splitOn [""] . lines <$> getContents let init = parseInit init' let cmds = parseCmds cmds' putStr "part 1: " print $ map head $ foldl (flip moveN) init cmds putStr "part 2: " print $ map head $ foldl (flip move) init cmds