Skip to content

Commit deffab2

Browse files
committed
feat(2024/Day13)
1 parent 7f89ee7 commit deffab2

File tree

5 files changed

+1424
-1
lines changed

5 files changed

+1424
-1
lines changed

2024/Day13/Day13.hs

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
module Main where
2+
3+
import Data.Bits
4+
import Data.Either
5+
import Data.List
6+
import Data.List.Split
7+
import Data.List.Unique
8+
import Data.Matrix (Matrix, (!))
9+
import Data.Matrix qualified as Mat
10+
import Data.Set (Set)
11+
import Data.Set qualified as S
12+
import Data.Tuple.Extra
13+
import Debug.Trace
14+
import System.Environment
15+
import Text.Regex.TDFA ((=~))
16+
-- TODO: Cleanup imports after day done
17+
18+
type Input = [((Double, Double), (Double, Double), (Double, Double))]
19+
type Output = Int
20+
21+
parseInput :: String -> Input
22+
parseInput input = res
23+
where
24+
res = map (\[sb1, sb2, sprize] -> (getPos sb1, getPos sb2, getPos sprize)) . map lines $ splitOn "\n\n" input
25+
26+
t :: String -> [[String]]
27+
t s = s =~ ".* X.(.*), Y.(.*)" :: [[String]]
28+
getPos :: String -> (Double, Double)
29+
getPos s = (read x, read y)
30+
where
31+
[[_, x, y]] = t s
32+
33+
34+
part1 :: Input -> Output
35+
part1 = sum . map (\(nx, ny) -> 3*nx+ny) . map fst . filter snd . map (uncurry3 solveArcade)
36+
where
37+
-- Old version checking for valid combinations => Waayyyy too sloww for part2
38+
-- solveArcade pos seen b1 b2 prize
39+
-- | pos == prize = ((0, 0), (seen, True))
40+
-- | pos `S.member` seen = ((-1, -1), (seen, False))
41+
-- | fst pos >= fst prize = ((-1, -1), (S.insert pos seen, False))
42+
-- | snd pos >= snd prize = ((-1, -1), (S.insert pos seen, False))
43+
-- -- | trace (show (pos, prize)) (False) = ((0, 0), False)
44+
-- | not succced1 && not succced2 = ((-1, -1), (S.insert pos seen2, False))
45+
-- | succced1 && not succced2 = (res1, (S.insert pos seen2, True))
46+
-- | not succced1 && succced2 = (res2, (S.insert pos seen2, True))
47+
-- | fst res1 * 3 + snd res1 < fst res2 * 3 + snd res2 = (res1, (S.insert pos seen2, True))
48+
-- | otherwise = (res1, (S.insert pos seen2, True))
49+
-- where
50+
-- (res1, (seen1, succced1)) = first (first ((+)1)) $ solveArcade (fst pos + fst b1, snd pos + snd b1) seen b1 b2 prize
51+
-- (res2, (seen2, succced2)) = first (second ((+)1)) $ solveArcade (fst pos + fst b2, snd pos + snd b2) seen1 b1 b2 prize
52+
53+
isAlmostInt :: Double -> Bool
54+
isAlmostInt x = abs (x - fromInteger (round x)) < eps
55+
where eps = 1e-4 --- REALLY sketchy : doubles are not precise enough to have a good eps (1e-10 or something close) so had to guess it and get 0.01 since 0.1 is too big and 0.0001 is too small
56+
57+
solveArcade (xb1, yb1) (xb2, yb2) (xp, yp)
58+
| isLeft inva = trace (show (fromLeft "" inva)) ((-1, -1), False)
59+
| isAlmostInt nb1 && isAlmostInt nb2 = ((round nb1, round nb2), True)
60+
| otherwise = ((-1, -1), False)
61+
where
62+
a :: Matrix Double
63+
a = Mat.fromLists [[xb1, xb2], [yb1, yb2]]
64+
b :: Matrix Double
65+
b = Mat.fromLists [[xp], [yp]]
66+
inva :: Either String (Matrix Double)
67+
inva = (Mat.inverse a)
68+
res :: Matrix Double
69+
res = Mat.multStd (fromRight (Mat.zero 1 1) inva) b
70+
(nb1, nb2) = (res ! (1, 1), res ! (2, 1))
71+
72+
73+
part2 :: Input -> Output
74+
part2 = part1 . map (\(b1, b2, p) -> (b1, b2, both ((+) 10000000000000) p))
75+
76+
main :: IO ()
77+
main = do
78+
args <- getArgs
79+
content <- readFile (last args)
80+
let input = parseInput content
81+
82+
-- print input
83+
84+
print $ part1 input
85+
print $ part2 input

2024/Day13/Makefile

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