Compare commits

..

7 commits

Author SHA1 Message Date
Kiana Sheibani 3826a13244
feat: part 7-2 2024-12-09 00:46:19 -05:00
Kiana Sheibani b4391bec86
refactor: remove totality assertion 2024-12-09 00:44:40 -05:00
Kiana Sheibani 2196df1811
feat: part 7-1 2024-12-09 00:34:47 -05:00
Kiana Sheibani d87cb7d7ee
fix: remove unnecessary module list from ipkg
This is apparently only necessary for libraries, not for executables.
Good to know!
2024-12-09 00:33:28 -05:00
Kiana Sheibani cda9060ab3
feat: part 6-2 2024-12-08 18:01:22 -05:00
Kiana Sheibani dd51ad5d96
feat: part 6-1 2024-12-08 00:21:18 -05:00
Kiana Sheibani d47a964c47
refactor: factor out grid code into Utils 2024-12-08 00:20:53 -05:00
10 changed files with 256 additions and 23 deletions

View file

@ -13,10 +13,3 @@ depends = contrib
executable = advent-of-code-2024 executable = advent-of-code-2024
main = Main main = Main
modules = Main, Utils, AllDays,
Data.Problem,
Day1.Part1, Day1.Part2,
Day2.Part1, Day2.Part2,
Day3.Part1, Day3.Part2,
Day4.Part1, Day4.Part2,
Day5.Part1, Day5.Part2

View file

@ -10,3 +10,7 @@ import public Day4.Part1
import public Day4.Part2 import public Day4.Part2
import public Day5.Part1 import public Day5.Part1
import public Day5.Part2 import public Day5.Part2
import public Day6.Part1
import public Day6.Part2
import public Day7.Part1
import public Day7.Part2

View file

@ -3,17 +3,15 @@ module Day4.Part1
import Data.String import Data.String
import Data.Vect import Data.Vect
import Utils
%default total %default total
--- TYPES --- TYPES
public export public export
Board : Nat -> Nat -> Type Board : Nat -> Nat -> Type
Board h w = Vect h (Vect w Char) Board h w = Grid h w Char
public export
Pos : Nat -> Nat -> Type
Pos h w = (Fin h, Fin w)
public export public export
@ -27,19 +25,10 @@ directions = [U, UR, R, DR, D, DL, L, UL]
export export
parseInput : String -> Maybe (h ** w ** Board h w) parseInput : String -> Maybe (h ** w ** Board h w)
parseInput inp = parseInput = parseGrid
let ls@(row :: _) = unpack <$> lines inp
| [] => Just (0 ** 0 ** [])
width = length row
in map (\l => (length l ** width ** fromList l))
(traverse (toVect width) ls)
--- DATA --- DATA
export
index : Pos h w -> Board h w -> Char
index (i, j) = index j . index i
predFin : Fin n -> Maybe (Fin n) predFin : Fin n -> Maybe (Fin n)
predFin FZ = Nothing predFin FZ = Nothing
predFin (FS x) = Just $ weaken x predFin (FS x) = Just $ weaken x

View file

@ -4,6 +4,7 @@ import Data.String
import Data.Vect import Data.Vect
import Day4.Part1 import Day4.Part1
import Utils
%default total %default total

95
src/Day6/Part1.idr Normal file
View file

@ -0,0 +1,95 @@
module Day6.Part1
import Data.Colist
import Data.List
import Data.Maybe
import Data.Vect
import Data.Vect.Quantifiers
import Utils
%default total
--- TYPES
public export
data Direction = U | R | D | L
export
Eq Direction where
U == U = True
D == D = True
L == L = True
R == R = True
_ == _ = False
-- True if there is an obstacle
public export
Map : Nat -> Nat -> Type
Map h w = Grid h w Bool
--- PARSING
parseDir : Char -> Maybe Direction
parseDir '^' = Just U
parseDir '>' = Just R
parseDir 'v' = Just D
parseDir '<' = Just L
parseDir _ = Nothing
export
parseInput : String -> Maybe (h ** w ** (Map h w, Pos h w, Direction))
parseInput inp = do
(h ** w ** grid) <- parseGrid inp
g <- findGuard grid
pure (h ** w ** ((map . map) (=='#') grid, g))
where
findGuard : Vect h (Vect w Char) -> Maybe (Pos h w, Direction)
findGuard [] = Nothing
findGuard (row :: vs) =
case any (\c => isItJust (parseDir c)) row of
Yes p => Just ((FZ, cast $ anyToFin p), fromJust _ @{anyToFinCorrect p})
No _ => map (mapFst (mapFst FS)) $ findGuard vs
--- DATA
predFin : Fin n -> Maybe (Fin n)
predFin FZ = Nothing
predFin (FS x) = Just $ weaken x
export
moveDir : {h, w : _} -> Direction -> Pos h w -> Maybe (Pos h w)
moveDir U (i, j) = (,j) <$> predFin i
moveDir R (i, j) = (i,) <$> strengthen (FS j)
moveDir D (i, j) = (,j) <$> strengthen (FS i)
moveDir L (i, j) = (i,) <$> predFin j
export
rotate : Direction -> Direction
rotate U = R
rotate R = D
rotate D = L
rotate L = U
getRoute : {h, w : _} -> (Pos h w, Direction) -> Map h w
-> Colist (Pos h w, Direction)
getRoute (pos, dir) mp =
let Just next = moveDir dir pos
| Nothing => [(pos, dir)]
in (pos, dir) ::
if index next mp
then getRoute (pos, rotate dir) mp
else getRoute (next, dir) mp
--- SOLUTION
covering
forceList : Colist a -> List a
forceList [] = []
forceList (x :: xs) = x :: forceList xs
export covering
solution : String -> Maybe Nat
solution inp = do
(h ** w ** (mp, g)) <- parseInput inp
pure $ length $ nub $ map fst $ forceList $ getRoute g mp

64
src/Day6/Part2.idr Normal file
View file

@ -0,0 +1,64 @@
module Day6.Part2
import Data.Colist
import Data.List
import Data.Maybe
import Data.Vect
import Day6.Part1
import Utils
%default total
--- DATA
getCollisions : {h, w : _} -> (Pos h w, Direction) -> Map h w
-> Colist (Pos h w, Direction)
getCollisions (pos, dir) mp =
let Just next = moveDir dir pos
| Nothing => []
in if index next mp
then (next, dir) :: getCollisions (pos, rotate dir) mp
else assert_total $ getCollisions (next, dir) mp
insertObs : Pos h w -> Map h w -> Map h w
insertObs (i, j) = updateAt i (replaceAt j True)
-- Must be total, as element type is finite
checkRepeated : Colist (Pos h w, Direction) -> Bool
checkRepeated = assert_total $ go []
where
covering
go : Eq a => List a -> Colist a -> Bool
go _ [] = False
go seen (x :: xs) =
(x `elem` seen) || go (x :: seen) xs
covering
loopPos : {h, w : _} -> (Pos h w, Direction) -> Map h w
-> List (Pos h w)
loopPos g mp = do
i <- toList $ range {len=h}
j <- toList $ range {len=w}
let obs = (i,j)
guard (obs /= fst g && not (index obs mp)) -- must be empty space
let cols = getCollisions g $ insertObs obs mp
guard (collides obs cols) -- guard must collide with obstacle
guard (checkRepeated cols) -- must cause a loop
pure obs
where
-- Total in practice because routes that don't hit the new obstacle should
-- be finite, but we can't assume that from user input, so mark as covering
covering
collides : Pos h w -> Colist (Pos h w, Direction) -> Bool
collides _ [] = False
collides obs ((pos, _) :: cols) =
pos == obs || collides obs cols
--- SOLUTION
export covering
solution : String -> Maybe Nat
solution inp = do
(h ** w ** (mp, g)) <- parseInput inp
pure $ length $ loopPos g mp

43
src/Day7/Part1.idr Normal file
View file

@ -0,0 +1,43 @@
module Day7.Part1
import Data.List1
import Data.String
import Utils
%default total
--- TYPES
public export
Op : Type
Op = Nat -> Nat -> Nat
--- PARSING
parseLine : String -> Maybe (Nat, List1 Nat)
parseLine inp =
let (part1 ::: [part2]) = split (==':') inp
| _ => Nothing
in (,) <$> parseNat part1
<*> (traverse parseNat =<< fromList (words part2))
export
parseInput : String -> Maybe (List (Nat, List1 Nat))
parseInput = traverse parseLine . lines
--- DATA
export
search : List Op -> (tg, tot : Nat) -> List Nat -> Bool
search _ tg tot [] = tg == tot
search ops tg tot (x :: xs) =
-- heuristic: abandon if running total is larger than target
tot <= tg && any (\op => search ops tg (op tot x) xs) ops
--- SOLUTION
export
solution : String -> Maybe Nat
solution = map (sum . map fst . filter (\(tg,x:::xs) => search [(+),(*)] tg x xs))
. parseInput

21
src/Day7/Part2.idr Normal file
View file

@ -0,0 +1,21 @@
module Day7.Part2
import Data.List1
import Day7.Part1
import Utils
%default total
--- DATA
concat : Nat -> Nat -> Nat
concat x y = cast $ show x ++ show y
--- SOLUTION
export
solution : String -> Maybe Nat
solution = map (sum . map fst
. filter (\(tg,x:::xs) => search [(+),(*),concat] tg x xs))
. parseInput

View file

@ -13,7 +13,7 @@ import AllDays
||| The latest problem that has been solved. ||| The latest problem that has been solved.
-- NOTE: UPDATE AFTER EACH SOLUTION -- NOTE: UPDATE AFTER EACH SOLUTION
latest : Problem latest : Problem
latest = Pr 5 Part2 latest = Pr 7 Part2
solMap : SortedMap Problem (String -> String) solMap : SortedMap Problem (String -> String)

View file

@ -3,6 +3,7 @@ module Utils
import Data.Maybe import Data.Maybe
import Data.String import Data.String
import Data.String.Parser import Data.String.Parser
import Data.Vect
%default total %default total
@ -28,3 +29,25 @@ scan p = until p *> p
export covering export covering
scanWhile : Monad m => ParseT m a -> ParseT m b -> ParseT m b scanWhile : Monad m => ParseT m a -> ParseT m b -> ParseT m b
scanWhile w p = many (lookahead w *> requireFailure p *> skip (satisfy (const True))) *> p scanWhile w p = many (lookahead w *> requireFailure p *> skip (satisfy (const True))) *> p
public export
Grid : (h, w : Nat) -> Type -> Type
Grid h w a = Vect h (Vect w a)
public export
Pos : (h, w : Nat) -> Type
Pos h w = (Fin h, Fin w)
export
parseGrid : String -> Maybe (h ** w ** Grid h w Char)
parseGrid str =
let ls@(row :: _) = unpack <$> lines str
| [] => Just (0 ** 0 ** [])
width = length row
in map (\l => (length l ** width ** fromList l))
(traverse (toVect width) ls)
export
index : Pos h w -> Grid h w a -> a
index (i, j) = index j . index i