Skip to content

Instantly share code, notes, and snippets.

@jcinnamond
Created December 24, 2020 11:28
Show Gist options
  • Save jcinnamond/497f5da12da912f83dcc797b740bce4b to your computer and use it in GitHub Desktop.
Save jcinnamond/497f5da12da912f83dcc797b740bce4b to your computer and use it in GitHub Desktop.
aoc23 in haskell
module Crabs
( Cup, Current, Position
, simulate
, readCircle
) where
import Data.Tuple ( swap )
import Data.List (elemIndex )
-- Everything is an int, so create some type aliases to make the argument lists
-- more meaningful
type Cup = Int
type Current = Int
type Position = Int
{-|
simulate takes a starting circle and runs a given number of moves,
returning the state of the circle after those moves.
-}
simulate :: Int -> [Cup] -> [Cup]
simulate turns cups = foldl (\xs _ -> move xs) cups [1..turns]
{-|
`move` simulates a single move by the crab. It takes a list of cups with
the current cup at the start and returns a new list of cups shuffled by
the crab. The shuffling works as follows:
- the list is split into three parts -- the current cup, the cups picked
up by the crab, and the remaining cups. E.g., given the list [1,2,3,4,5,6,7,8,9]
this is split into the triple (1, [2,3,4], [5,6,7,8,9])
- the destination cup is found in the remaining cups list
- the picked up cups as spliced into the list after the destination, and the
current cup is added to the end to "rotate"
-}
move :: [Cup] -> [Cup]
move cups = splice rest d held ++ [c]
where (c, held, rest) = split cups
d = destination (c - 1) rest
split :: [Cup] -> (Current, [Cup], [Cup])
split xs = (current, held, rest)
where current = head xs
held = take 3 $ tail xs
rest = drop 3 $ tail xs
splice :: [Cup] -> Position -> [Cup] -> [Cup]
splice into pos from = head ++ from ++ tail
where (head, tail) = splitAt (pos + 1) into
destination :: Cup -> [Cup] -> Cup
destination c xs = case elemIndex c xs of
Just i -> i
Nothing -> destination newC xs
where newC = if c > 1 then c - 1 else 9
{-|
readCircle finds the cup with the value 1 and returns the values of the
other cups in the order that they appear in the ciricle.
-}
readCircle :: [Cup] -> [Cup]
readCircle cups = case elemIndex 1 cups of
Just x -> tail $ uncurry (++) $ swap $ splitAt x cups
module Main where
import Crabs ( readCircle, simulate )
import Data.Char (digitToInt)
-- this doesn't handle newlines, so use something like "echo -n 123456789 | stack run :aoc23-exe"
main :: IO ()
main = interact $ concatMap show . readCircle . simulate 100 . map digitToInt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment