Skip to content

Commit 1e10249

Browse files
committed
feat(2024/Day16)
1 parent a9a5232 commit 1e10249

File tree

7 files changed

+311
-0
lines changed

7 files changed

+311
-0
lines changed

2024/Day16/Day16.hs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
module Main where
2+
3+
import Data.Bits
4+
import Data.List
5+
import Data.List.Split
6+
import Data.List.Unique
7+
import Data.Map (Map)
8+
import Data.Map qualified as M
9+
import Data.Matrix (Matrix, (!))
10+
import Data.Matrix qualified as Mat
11+
import Data.Set (Set)
12+
import Data.Set qualified as S
13+
import Data.Tuple.Extra
14+
import Debug.Trace
15+
import System.Environment
16+
import Text.Regex.TDFA ((=~))
17+
-- TODO: Cleanup imports after day done
18+
19+
type Input = (Matrix Char, (Int, Int))
20+
type Output = Int
21+
22+
parseInput :: String -> Input
23+
parseInput input = (maze, start)
24+
where
25+
maze = Mat.fromLists $ lines input
26+
start = head [(y, x) | y <-[1..Mat.nrows maze], x <-[1..Mat.ncols maze], maze ! (y, x) == 'S']
27+
28+
29+
data Dir = UP | LEFT | RIGHT | DOWN deriving (Show, Eq, Ord)
30+
31+
move :: (Int, Int) -> Dir -> (Int, Int)
32+
move (y, x) UP = (y - 1, x)
33+
move (y, x) DOWN = (y + 1, x)
34+
move (y, x) LEFT = (y, x - 1)
35+
move (y, x) RIGHT = (y, x + 1)
36+
37+
turn90 :: Dir -> [Dir]
38+
turn90 UP = [LEFT, RIGHT]
39+
turn90 DOWN = [LEFT, RIGHT]
40+
turn90 LEFT = [UP, DOWN]
41+
turn90 RIGHT = [UP, DOWN]
42+
43+
pathFind ::Matrix Char -> Map ((Int, Int), Dir) Int -> Int -> Dir -> (Int, Int) -> (Bool, Map ((Int, Int), Dir) Int, Int, Set (Int, Int))
44+
pathFind maze seen score dir pos
45+
-- | rightPos && trace ("At " ++ show pos) (False ) = (False, seen, -1, S.empty)
46+
| (pos, dir) `M.member` seen && seen M.! (pos, dir) < score = (False, seen, -1, S.empty) -- Lower score ok
47+
-- | rightPos && trace ("At " ++ show pos ++ " has better score") (False ) = (False, seen, -1, S.empty)
48+
| maze ! pos == 'E' = (True, seen, score, S.singleton pos)
49+
-- | rightPos && trace ("At " ++ show pos ++ " not at end") (False ) = (False, seen, -1, S.empty)
50+
| maze ! pos == '#' = (False, seen, -1, S.empty)
51+
-- | rightPos && trace ("At " ++ show pos ++ " not at wall" ++ show bestSols) (False ) = (False, seen, -1, S.empty)
52+
| length bestSols /= 0 = bestSol
53+
| otherwise = (False, s2seen, -1, S.empty)
54+
where
55+
rightPos = (pos == (5, 4) || (pos == (4, 4) && dir == UP))
56+
57+
58+
59+
currSeen = (M.insert (pos, dir) score seen)
60+
(fbool, fseen, fscore, fseats) = pathFind maze currSeen (score + 1) dir (move pos dir)
61+
[d1, d2] = turn90 dir
62+
(s1bool, s1seen, s1score, s1seats) = pathFind maze fseen (score + 1001) d1 (move pos d1)
63+
(s2bool, s2seen, s2score, s2seats) = pathFind maze s1seen (score + 1001) d2 (move pos d2)
64+
65+
bestSols :: [[(Bool, Set (Int, Int), Int)]]
66+
bestSols = groupBy (\a b -> thd3 a == thd3 b) . sortOn thd3 $ filter (fst3) [(fbool, fseats, fscore), (s1bool, s1seats, s1score), (s2bool, s2seats, s2score)]
67+
68+
seats = S.unions $ map snd3 $ head bestSols
69+
70+
bestSol = (True, s2seen, thd3 . head $ head bestSols, S.insert pos seats)
71+
72+
part :: Input -> (Output, Output)
73+
part (maze, pos) = (\(_,_,p1,p2) -> (p1, S.size p2)) $ pathFind maze M.empty 0 RIGHT pos
74+
75+
showMaze :: Matrix Char -> Set (Int, Int) -> [String]
76+
showMaze maze path = map (map (\yx -> if yx `S.member` path then 'O' else maze ! yx)) [[(y, x) | x<-[1..Mat.ncols maze]] | y<-[1..Mat.nrows maze]]
77+
78+
79+
80+
main :: IO ()
81+
main = do
82+
args <- getArgs
83+
content <- readFile (last args)
84+
let input = parseInput content
85+
86+
-- print $ first Mat.toLists input
87+
88+
let (part1, part2) = part input
89+
90+
print $ (== 85480) $ part1
91+
print $ (== 518) $ part2
92+
93+
-- putStrLn $ unlines . showMaze (fst input) $ (\(_,_,_,e) -> e) $ pathFind (fst input) M.empty 0 RIGHT (snd input)

2024/Day16/Makefile

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
CONTAINER_NAME=haskell-aoc
2+
SRC=./Day16.hs
3+
TARGET=Day16
4+
all: $(TARGET)
5+
6+
$(TARGET): $(SRC)
7+
ghc -O3 $(SRC)
8+
9+
profile: $(SRC)
10+
11+
12+
clean:
13+
$(RM) ./Day16 ./Day16.o ./Day16.hi
14+
15+
setup: $(SRC)
16+
docker cp $(SRC) $(CONTAINER_NAME):/home/haskell/Main.hs
17+
docker cp input.txt $(CONTAINER_NAME):/home/haskell/input.txt
18+
docker cp shortinput.txt $(CONTAINER_NAME):/home/haskell/shortinput.txt
19+
20+
profiling: setup
21+
docker exec -it $(CONTAINER_NAME) cabal build --enable-profiling
22+
docker exec -it $(CONTAINER_NAME) ./profile input.txt
23+
24+
run: setup
25+
docker exec -it $(CONTAINER_NAME) cabal build
26+
docker exec -it $(CONTAINER_NAME) ./run input.txt
27+
28+
.PHONY: all $(TARGET) clean setup profiling run

0 commit comments

Comments
 (0)