Skip to content

Commit 7cbe446

Browse files
committed
feat(2024/Day17)
1 parent e46ad8d commit 7cbe446

File tree

6 files changed

+144
-4
lines changed

6 files changed

+144
-4
lines changed

2024/Day17/Day17.hs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
module Main where
2+
3+
import Data.Bits
4+
import Data.Char
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 GHC.Integer (shiftRInteger)
15+
import GHC.Num (integerFromInt, integerToInt)
16+
import System.Environment
17+
import Text.Regex.TDFA ((=~))
18+
19+
-- TODO: Cleanup imports after day done
20+
21+
data Input = Computer {program :: [Integer], programCounter :: Int, registerA :: Integer, registerB :: Integer, registerC :: Integer, output :: [Integer]} deriving (Show, Eq, Ord)
22+
23+
type Output = Integer
24+
25+
parseInput :: String -> Input
26+
parseInput input = Computer pg 0 regA regB regC []
27+
where
28+
[lRegA, lRegB, lRegC, _, lPg] = lines input
29+
readVal = read . dropWhile (not . isDigit)
30+
regA = readVal lRegA
31+
regB = readVal lRegB
32+
regC = readVal lRegC
33+
pg = read . (\l -> "[" ++ l ++ "]") . dropWhile (not . isDigit) $ lPg
34+
35+
getValue :: Input -> Integer -> Integer
36+
getValue (Computer _ _ rA _ _ _) 4 = rA
37+
getValue (Computer _ _ _ rB _ _) 5 = rB
38+
getValue (Computer _ _ _ _ rC _) 6 = rC
39+
getValue (Computer _ _ _ _ _ _) n = n
40+
41+
calculateOp :: Input -> Integer -> Integer -> Input
42+
calculateOp (c@(Computer _ pc rA rB rC out)) 0 n = c {programCounter = pc + 2, registerA = rA `div` (2 ^ (getValue c n))}
43+
calculateOp (c@(Computer _ pc rA rB rC out)) 1 n = c {programCounter = pc + 2, registerB = rB `xor` n}
44+
calculateOp (c@(Computer _ pc rA rB rC out)) 2 n = c {programCounter = pc + 2, registerB = (getValue c n) `mod` 8}
45+
calculateOp (c@(Computer _ pc 00 rB rC out)) 3 n = c {programCounter = pc + 2}
46+
calculateOp (c@(Computer _ pc rA rB rC out)) 3 n = c {programCounter = integerToInt $ getValue c n}
47+
calculateOp (c@(Computer _ pc rA rB rC out)) 4 n = c {programCounter = pc + 2, registerB = rB `xor` rC}
48+
calculateOp (c@(Computer _ pc rA rB rC out)) 5 n = c {programCounter = pc + 2, output = (getValue c n) `mod` 8 : out}
49+
calculateOp (c@(Computer _ pc rA rB rC out)) 6 n = c {programCounter = pc + 2, registerB = rA `div` (2 ^ (getValue c n))}
50+
calculateOp (c@(Computer _ pc rA rB rC out)) 7 n = c {programCounter = pc + 2, registerC = rA `div` (2 ^ (getValue c n))}
51+
52+
performOps :: Input -> [Output]
53+
performOps (c@(Computer pg pc _ _ _ out))
54+
| pc >= length pg = reverse out
55+
| otherwise = performOps $ calculateOp c op comboOp
56+
where
57+
op = pg !! pc
58+
comboOp = pg !! (pc + 1)
59+
60+
part1 :: Input -> [Output]
61+
part1 = performOps
62+
63+
part2 :: Input -> Output
64+
part2 input = head $ sub' 1 0
65+
where
66+
sub' p v
67+
| (== p) . length $ program input = currIt
68+
| otherwise = concat $ map (sub' (p + 1)) currIt
69+
where
70+
currIt = filter (\i -> (`isSuffixOf` program input) . performOps $ input {registerA = i}) [8 * v .. 8 * v + 7]
71+
72+
main :: IO ()
73+
main = do
74+
args <- getArgs
75+
content <- readFile (last args)
76+
let input = parseInput content
77+
print input
78+
79+
print $ part1 input
80+
print $ part2 input

2024/Day17/Makefile

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

2024/Day17/input.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 66171486
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 2,4,1,6,7,5,4,6,1,4,5,5,0,3,3,0

2024/Day17/shortinput.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 729
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

2024/Day17/shortinput2.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,3,5,4,3,0

2024/README.md

+21-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ This year will do it in Haskell, but might try few days in Rust as well
1515
- [x] Day 11
1616
- [x] Day 12
1717
- [x] Day 13
18-
- [ ] Day 14
19-
- [ ] Day 15
20-
- [ ] Day 16
21-
- [ ] Day 17
18+
- [x] Day 14
19+
- [x] Day 15
20+
- [x] Day 16
21+
- [?] Day 17
2222
- [ ] Day 18
2323
- [ ] Day 19
2424
- [ ] Day 20
@@ -238,3 +238,20 @@ But then at the moment when I reach the last intersection I need to go back up t
238238
```
239239

240240
The optimization would allow me to skip this last part represented with `X`
241+
242+
### Day17
243+
244+
The first part was a simple computer simulation.
245+
246+
For the second one I didn't really succeed on my own...
247+
248+
Sadly in order to find the result I had to look at tips on how to solve it.
249+
250+
Basically each instruction corresponds to a byte in the register A
251+
252+
The register A is basically reduced like `out A%8, A = A/8`, so to build the register A you just have to go backward :
253+
- For the last instruction, check all results for `regA in [0..7]`
254+
- For the one before, check all the results for `regA in [prev*8..prev*8+7]`
255+
- Continue recursively until you get all the numbers
256+
257+
Even though I didn't solve this one on my own I learnt how to analyze the output in order to find results

0 commit comments

Comments
 (0)