Day 9 Part 1
This commit is contained in:
parent
e7c7a3fc9d
commit
755b570063
|
@ -0,0 +1,159 @@
|
||||||
|
import Data.String
|
||||||
|
import Data.Vect
|
||||||
|
import Data.List1
|
||||||
|
import System.File.ReadWrite
|
||||||
|
|
||||||
|
%default total
|
||||||
|
|
||||||
|
data Direction = Up | Right | Left | Down
|
||||||
|
%name Direction direction, direction2, direction3
|
||||||
|
|
||||||
|
Show Direction where
|
||||||
|
show Up = "Up"
|
||||||
|
show Right = "Right"
|
||||||
|
show Left = "Left"
|
||||||
|
show Down = "Down"
|
||||||
|
|
||||||
|
parseDirection : String -> Maybe Direction
|
||||||
|
parseDirection input =
|
||||||
|
case trim input of
|
||||||
|
"U" => Just Up
|
||||||
|
"R" => Just Right
|
||||||
|
"L" => Just Left
|
||||||
|
"D" => Just Down
|
||||||
|
x => Nothing
|
||||||
|
|
||||||
|
invert : Direction -> Direction
|
||||||
|
invert Up = Down
|
||||||
|
invert Right = Left
|
||||||
|
invert Left = Right
|
||||||
|
invert Down = Up
|
||||||
|
|
||||||
|
-- Apply a direction to a pair of Ints
|
||||||
|
applyDirection : Direction -> (Int, Int) -> (Int, Int)
|
||||||
|
applyDirection Up (x, y) = (x, y + 1)
|
||||||
|
applyDirection Right (x, y) = (x + 1, y)
|
||||||
|
applyDirection Left (x, y) = (x - 1, y)
|
||||||
|
applyDirection Down (x, y) = (x, y - 1)
|
||||||
|
|
||||||
|
data Motion = Move Direction Nat
|
||||||
|
%name Motion motion, motion2, motion3
|
||||||
|
|
||||||
|
Show Motion where
|
||||||
|
show (Move direction count) = show direction ++ " " ++ show count
|
||||||
|
|
||||||
|
parseMotion : String -> Maybe Motion
|
||||||
|
parseMotion input =
|
||||||
|
let components = split (== ' ') input in
|
||||||
|
case forget components of
|
||||||
|
[x, y] => do direction <- parseDirection x
|
||||||
|
ammount <- parsePositive y
|
||||||
|
pure (Move direction ammount)
|
||||||
|
_ => Nothing
|
||||||
|
|
||||||
|
parseMotions : String -> Maybe (List Motion)
|
||||||
|
parseMotions input =
|
||||||
|
let inputLines = lines input
|
||||||
|
in traverse parseMotion inputLines
|
||||||
|
|
||||||
|
-- Get the distance moved by a motion
|
||||||
|
distance : Motion -> Nat
|
||||||
|
distance (Move _ i) = i
|
||||||
|
|
||||||
|
-- Break a motion down into a list of moves-by-one
|
||||||
|
breakdown : (motion : Motion) -> Vect (distance motion) Direction
|
||||||
|
breakdown (Move direction 0) = []
|
||||||
|
breakdown input@(Move direction (S k)) = direction :: breakdown (assert_smaller input (Move direction k))
|
||||||
|
|
||||||
|
-- The state of a head and tail
|
||||||
|
data State: Type where
|
||||||
|
MkState : (head : (Int, Int)) -> (tail : (Int, Int)) -> State
|
||||||
|
%name State state, state1, state2
|
||||||
|
|
||||||
|
Show State where
|
||||||
|
show (MkState head tail) = "Head: " ++ show head ++ " Tail: " ++ show tail
|
||||||
|
|
||||||
|
emptyState : State
|
||||||
|
emptyState = MkState (0,0) (0,0)
|
||||||
|
|
||||||
|
tail : State -> (Int, Int)
|
||||||
|
tail (MkState head x) = x
|
||||||
|
|
||||||
|
touching : (Int, Int) -> (Int, Int) -> Bool
|
||||||
|
touching (x, y) (z, w) =
|
||||||
|
let (u, v) = (abs (x - z), abs (y - w)) in
|
||||||
|
u <= 1 && v <= 1
|
||||||
|
|
||||||
|
-- Move the head in a particular direction, causing the tail to follow if needed
|
||||||
|
moveHead : Direction -> State -> State
|
||||||
|
moveHead direction (MkState head tail) =
|
||||||
|
let newHead = applyDirection direction head in
|
||||||
|
if touching newHead tail
|
||||||
|
then MkState newHead tail
|
||||||
|
else let newTail = applyDirection (invert direction) newHead in
|
||||||
|
MkState newHead newTail
|
||||||
|
|
||||||
|
-- Apply a movement to the head, returning the sequence of tail positions, including the starting
|
||||||
|
-- position
|
||||||
|
applyMotion : (motion : Motion) -> State -> (State, Vect (S (distance motion)) State)
|
||||||
|
applyMotion motion state = helper (breakdown motion) state
|
||||||
|
where helper : (directions : Vect n Direction) -> State -> (State, Vect (S n) State)
|
||||||
|
helper [] state = (state, [state])
|
||||||
|
helper (x :: xs) state =
|
||||||
|
let newState = moveHead x state
|
||||||
|
(resState, rest) = helper xs newState
|
||||||
|
in (resState, state :: rest)
|
||||||
|
|
||||||
|
-- Apply all the motions in a list to the head, returning the full sequence of positions
|
||||||
|
applyMotions : (motions : List Motion) -> State -> (State, List State)
|
||||||
|
applyMotions [] state = (state, [state])
|
||||||
|
applyMotions (x :: xs) state =
|
||||||
|
let (newState, motions) = applyMotion x state
|
||||||
|
(outputState, rest) = applyMotions xs newState
|
||||||
|
in (outputState, (toList motions) ++ rest)
|
||||||
|
|
||||||
|
simple = """
|
||||||
|
R 4
|
||||||
|
U 4
|
||||||
|
L 3
|
||||||
|
D 1
|
||||||
|
R 4
|
||||||
|
D 1
|
||||||
|
L 5
|
||||||
|
R 2
|
||||||
|
"""
|
||||||
|
|
||||||
|
testPart1 : IO ()
|
||||||
|
testPart1 =
|
||||||
|
case parseMotions simple of
|
||||||
|
Nothing => putStrLn "Failed to parse motions"
|
||||||
|
Just motions =>
|
||||||
|
let (state, states) = applyMotions motions emptyState
|
||||||
|
tails = map tail states
|
||||||
|
uniqueTails = nub tails
|
||||||
|
in do putStrLn "Movements:"
|
||||||
|
traverse_ printLn motions
|
||||||
|
putStrLn "\nSteps:"
|
||||||
|
traverse_ printLn states
|
||||||
|
putStrLn "\nUnique Tails:"
|
||||||
|
printLn $ length uniqueTails
|
||||||
|
|
||||||
|
part1 : String -> Maybe Nat
|
||||||
|
part1 input =
|
||||||
|
case parseMotions input of
|
||||||
|
Nothing => Nothing
|
||||||
|
Just motions =>
|
||||||
|
let (state, states) = applyMotions motions emptyState
|
||||||
|
tails = map tail states
|
||||||
|
in Just . length . nub $ tails
|
||||||
|
|
||||||
|
partial main : IO ()
|
||||||
|
main =
|
||||||
|
do file <- readFile "input"
|
||||||
|
case file of
|
||||||
|
Left err => printLn err
|
||||||
|
Right contents =>
|
||||||
|
case part1 contents of
|
||||||
|
Nothing => printLn "Error in part 1"
|
||||||
|
Just part1Count =>
|
||||||
|
putStrLn ("Part 1: " ++ show part1Count)
|
Loading…
Reference in New Issue