Skip to content

Commit 496ab39

Browse files
committed
day17
1 parent 7a74d21 commit 496ab39

File tree

3 files changed

+172
-10
lines changed

3 files changed

+172
-10
lines changed

day17/Program.fs

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,172 @@
1-
module Program = let [<EntryPoint>] main _ = 0
1+
open Xunit
2+
open FsUnit.Xunit
3+
4+
// 0 adv: A <- A / 2^■
5+
// 1 bxl: B <- B xor ■
6+
// 2 bst: B <- ■ % 8
7+
// 3 jnz: A ≠ 0 ⇒ ip <- ■
8+
// 4 bxc: B <- B xor C
9+
// 5 out: ■ % 8
10+
// 6 bdv: B <- A / 2^■
11+
// 7 cdv: C <- A / 2^■
12+
13+
type Register = { A: int64; B: int64; C: int64 }
14+
15+
type Env =
16+
{ Ip: int
17+
Register: Register
18+
Program: int[]
19+
Out: int64 list }
20+
21+
let rec pow' x n =
22+
if n = 0L then 1L
23+
else if n % 2L = 0L then pow' (x * x) (n / 2L)
24+
else x * pow' x (n - 1L)
25+
26+
let execute register program halt =
27+
let rec f env =
28+
match halt env with
29+
| Some out -> out
30+
| None ->
31+
let { Ip = ip
32+
Register = reg
33+
Program = program
34+
Out = out } =
35+
env
36+
37+
let combo operand =
38+
match operand with
39+
| 0
40+
| 1
41+
| 2
42+
| 3 as x -> int64 x
43+
| 4 -> reg.A
44+
| 5 -> reg.B
45+
| 6 -> reg.C
46+
| x -> failwith $"{x} !?"
47+
48+
let opcode = program[ip]
49+
let operand = program[ip + 1]
50+
51+
let newEnv =
52+
match opcode with
53+
| 0 ->
54+
{ env with
55+
Ip = ip + 2
56+
Register =
57+
{ reg with
58+
A = reg.A / (pow' 2 (combo operand)) } }
59+
| 1 ->
60+
{ env with
61+
Ip = ip + 2
62+
Register = { reg with B = reg.B ^^^ operand } }
63+
| 2 ->
64+
{ env with
65+
Ip = ip + 2
66+
Register = { reg with B = (combo operand) % 8L } }
67+
| 3 ->
68+
if reg.A = 0 then
69+
{ env with Ip = ip + 2 }
70+
else
71+
{ env with Ip = operand }
72+
| 4 ->
73+
{ env with
74+
Ip = ip + 2
75+
Register = { reg with B = reg.B ^^^ reg.C } }
76+
| 5 ->
77+
{ env with
78+
Ip = ip + 2
79+
Out = (combo operand) % 8L :: out }
80+
| 6 ->
81+
{ env with
82+
Ip = ip + 2
83+
Register =
84+
{ reg with
85+
B = reg.A / (pow' 2 (combo operand)) } }
86+
| 7 ->
87+
{ env with
88+
Ip = ip + 2
89+
Register =
90+
{ reg with
91+
C = reg.A / (pow' 2 (combo operand)) } }
92+
| x -> failwith $"{x} !?"
93+
94+
f newEnv
95+
96+
f
97+
{ Ip = 0
98+
Register = register
99+
Program = program
100+
Out = [] }
101+
102+
let outputOnHalt env =
103+
if env.Ip >= env.Program.Length then
104+
env.Out |> Array.ofList |> Array.map int |> Array.rev |> Some
105+
else
106+
None
107+
108+
let part1 (register: Register) (program: int[]) =
109+
let out = execute register program outputOnHalt
110+
out |> Array.map string |> String.concat ","
111+
112+
let part2 (register: Register) (program: int[]) =
113+
// reversing
114+
//
115+
// do
116+
// B <- A % 8
117+
// B <- B xor 5
118+
// C <- A / (2 ** B)
119+
// B <- B xor 6
120+
// A <- A / (2 ** 3)
121+
// B <- B xor C
122+
// output(B % 8)
123+
// while (A <> 0)
124+
//
125+
126+
let rec find i a =
127+
if i = 0 then
128+
Some a
129+
else
130+
[ 0..7 ]
131+
|> List.tryPick (fun j ->
132+
let a = a * 8L + int64 j
133+
let out = execute { register with A = a } program outputOnHalt
134+
135+
if out = program[(i - 1) ..] then find (i - 1) a else None)
136+
137+
find program.Length 0 |> Option.get
138+
139+
let parse (input: string) =
140+
let input = input.Split("\n\n")
141+
let register = input[0].Split("\n")
142+
143+
let register =
144+
{ A = register[0].Replace("Register A: ", "") |> int64
145+
B = register[1].Replace("Register B: ", "") |> int64
146+
C = register[2].Replace("Register C: ", "") |> int64 }
147+
148+
let program = input[1].Replace("Program: ", "").Split(",") |> Array.map int
149+
150+
register, program
151+
152+
module Example =
153+
let input =
154+
"Register A: 729
155+
Register B: 0
156+
Register C: 0
157+
158+
Program: 0,1,5,4,3,0"
159+
160+
[<Fact>]
161+
let testPart1 () =
162+
parse input ||> part1 |> should equal "4,6,3,5,6,3,5,2,1,0"
163+
164+
[<EntryPoint>]
165+
let main _ =
166+
let input = stdin.ReadToEnd().TrimEnd()
167+
let register, program = parse input
168+
169+
(register, program) ||> part1 |> printfn "Part 1: %s"
170+
(register, program) ||> part2 |> printfn "Part 2: %d"
171+
172+
0

day17/Tests.fs

Lines changed: 0 additions & 8 deletions
This file was deleted.

day17/day17.fsproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12-
<Compile Include="Tests.fs" />
1312
<Compile Include="Program.fs" />
1413
</ItemGroup>
1514

0 commit comments

Comments
 (0)