Skip to content

Commit 06b6d8c

Browse files
committed
feat(2024/Day20)
1 parent e7c325f commit 06b6d8c

File tree

6 files changed

+287
-2
lines changed

6 files changed

+287
-2
lines changed

2024/Day20/Day20.hs

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
module Main where
2+
3+
import Control.Parallel.Strategies
4+
import Data.Bits
5+
import Data.List
6+
import Data.List.Split
7+
import Data.List.Unique
8+
import Data.Map (Map)
9+
import Data.Map qualified as M
10+
import Data.Matrix (Matrix, (!))
11+
import Data.Matrix qualified as Mat
12+
import Data.Set (Set)
13+
import Data.Set qualified as S
14+
import Data.Tuple.Extra
15+
import Debug.Trace
16+
import System.Environment
17+
import Text.Regex.TDFA ((=~))
18+
19+
-- TODO: Cleanup imports after day done
20+
21+
type Input = (Matrix Char, ((Int, Int), (Int, Int)))
22+
23+
type Output = Int
24+
25+
data Dir = UP | LEFT | RIGHT | DOWN deriving (Show, Eq, Ord)
26+
27+
parseInput :: String -> Input
28+
parseInput input = (grid, (start, finish))
29+
where
30+
grid = Mat.fromLists . lines $ input
31+
start = head [(y, x) | y <- [1 .. Mat.nrows grid], x <- [1 .. Mat.ncols grid], grid ! (y, x) == 'S']
32+
finish = head [(y, x) | y <- [1 .. Mat.nrows grid], x <- [1 .. Mat.ncols grid], grid ! (y, x) == 'E']
33+
34+
move :: (Int, Int) -> Dir -> (Int, Int)
35+
move (y, x) UP = (y - 1, x)
36+
move (y, x) DOWN = (y + 1, x)
37+
move (y, x) LEFT = (y, x - 1)
38+
move (y, x) RIGHT = (y, x + 1)
39+
40+
isOut :: (Int, Int) -> (Int, Int) -> Bool
41+
isOut (width, height) (y, x) = x <= 0 || y <= 0 || x > width || y > height
42+
43+
dfs :: Matrix Char -> (Int, Int) -> Set (Int, Int) -> (Int, Int) -> [(Int, Int)]
44+
dfs grid target seen yx
45+
| yx `S.member` seen = []
46+
| yx == target = [yx]
47+
| isOut (Mat.ncols grid, Mat.nrows grid) yx = []
48+
| grid ! yx == '#' = []
49+
| res == [] = []
50+
| otherwise = yx : (head res)
51+
where
52+
seen' = S.insert yx seen
53+
explore = map (\yx' -> dfs grid target seen' yx') $ map (move yx) $ [LEFT, DOWN, RIGHT, UP]
54+
res = filter (/= []) explore
55+
56+
dist :: (Int, Int) -> (Int, Int) -> Int
57+
dist (y, x) (y', x') = abs (y - y') + abs (x - x')
58+
59+
findShortCuts :: Int -> Int -> [(Int, Int)] -> [Int]
60+
findShortCuts minCheat cheatTime path = ({-# SCC filtering #-} withStrategy (parList rseq) . filter (>= minCheat)) $ ({-# SCC mapTimeDiff #-} parMap rseq ((\(i, j) -> j - i - dist (path !! i) (path !! j)))) pairIndices
61+
where
62+
pathLen = length path
63+
pairIndices = {-# SCC generateIndices #-} [(i, j) | i <- [0 .. pathLen - 1], j <- [i + minCheat + 1 .. pathLen - 1], dist (path !! i) (path !! j) <= cheatTime]
64+
65+
part1 :: Input -> Output
66+
part1 (grid, (start, finish)) = length $ findShortCuts 0 2 $ dfs grid finish S.empty start
67+
68+
part2 :: Input -> Output
69+
part2 (grid, (start, finish)) = length $ findShortCuts 100 20 $ dfs grid finish S.empty start
70+
71+
displayPath :: Matrix Char -> Set (Int, Int) -> [String]
72+
displayPath grid path = map (map (\yx -> if yx `S.member` path then 'O' else grid ! yx)) $ [[(y, x) | x <- [1 .. Mat.ncols grid]] | y <- [1 .. Mat.nrows grid]]
73+
74+
main :: IO ()
75+
main = do
76+
args <- getArgs
77+
content <- readFile (last args)
78+
let input = parseInput content
79+
80+
-- print $ first Mat.toLists $ input
81+
82+
print $ part1 input
83+
print $ part2 input

2024/Day20/Makefile

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
CONTAINER_NAME=haskell-aoc
2+
SRC=./Day20.hs
3+
TARGET=Day20
4+
all: $(TARGET)
5+
6+
$(TARGET): $(SRC)
7+
ghc -O3 $(SRC)
8+
9+
profile: $(SRC)
10+
11+
12+
clean:
13+
$(RM) ./Day20 ./Day20.o ./Day20.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)