Skip to content

Commit dfc9ea9

Browse files
committed
start day17
1 parent 8537924 commit dfc9ea9

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

Sources/AdventOfCode.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let allChallenges: [any AdventDay] = [
1717
Day13(),
1818
Day14(),
1919
Day15(),
20+
Day17(),
2021
]
2122

2223
@main

Sources/Day17.swift

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import Algorithms
2+
3+
struct Registers {
4+
var A = 0
5+
var B = 0
6+
var C = 0
7+
}
8+
9+
struct Computer {
10+
var instructions = [Int]()
11+
var registers = Registers()
12+
var output = [Int]()
13+
14+
func getComboOperand(_ operand: Int) -> Int {
15+
switch operand {
16+
case 0...3: operand
17+
case 4: registers.A
18+
case 5: registers.B
19+
case 6: registers.C
20+
case 7: 0 // invalid
21+
default: 0
22+
}
23+
}
24+
25+
mutating func executeOp(_ ops: Int, _ operand: Int, combo comboOp: Int, pointer: Int) -> Int {
26+
var p = pointer
27+
func div(_ num: Int, _ denomShift: Int) -> Int {
28+
let denom = 1 << denomShift
29+
if denom > num || denomShift > num {
30+
return 0
31+
}
32+
if denom == 0 {
33+
print("division by zero")
34+
print("denomShift", denomShift)
35+
}
36+
return num / denom
37+
}
38+
39+
switch ops {
40+
case 0:
41+
// adv
42+
let res = div(comboOp, registers.A)
43+
print("adv", res)
44+
registers.A = res
45+
p += 2
46+
case 1:
47+
// bxl
48+
let res = registers.B ^ operand
49+
print("bxl", res)
50+
registers.B = res
51+
p += 2
52+
case 2:
53+
//bst
54+
let res = comboOp % 8
55+
print("bst", operand, res)
56+
registers.B = res
57+
p += 2
58+
case 3:
59+
// jnz
60+
if registers.A != 0 {
61+
// jump by the value of the operand
62+
p += comboOp
63+
} else {
64+
// simple increase
65+
p += 2
66+
}
67+
case 4:
68+
// bxc
69+
registers.B ^= registers.C
70+
// do nothing with operand
71+
p += 2
72+
case 5:
73+
// out
74+
output.append(comboOp % 8)
75+
p += 2
76+
case 6:
77+
// bdv
78+
registers.B = div(comboOp, registers.A)
79+
p += 2
80+
case 7:
81+
// cdv
82+
registers.C = div(comboOp, registers.A)
83+
p += 2
84+
default: break
85+
}
86+
return p
87+
}
88+
89+
mutating func execute() -> String {
90+
var pointer = 0
91+
92+
while pointer < instructions.count {
93+
let op = instructions[pointer]
94+
let operand = instructions[pointer + 1]
95+
96+
pointer = executeOp(op, operand, combo: getComboOperand(operand), pointer: pointer)
97+
}
98+
// join the output of program with commas
99+
return output.map { String($0) }.joined(separator: ",")
100+
}
101+
}
102+
103+
struct Day17: AdventDay {
104+
var data: String
105+
106+
func initialize() -> (instructions: [Int], registers: Registers) {
107+
let parts = data.split(separator: "\n\n")
108+
let instructions = parts[1].trimmingPrefix("Program: ").integers(separator: ",")
109+
var registers = Registers()
110+
if let match = parts[0].firstMatch(
111+
of: /Register A: (\d+)\nRegister B: (\d+)\nRegister C: (\d+)/)
112+
{
113+
registers.A = Int(match.1) ?? 0
114+
registers.B = Int(match.2) ?? 0
115+
registers.C = Int(match.3) ?? 0
116+
}
117+
return (instructions: instructions, registers: registers)
118+
}
119+
120+
func part1() -> String {
121+
let (instructions, registers) = initialize()
122+
var computer = Computer(instructions: instructions, registers: registers)
123+
return computer.execute()
124+
}
125+
126+
func part2() -> Int {
127+
0
128+
}
129+
}

Tests/Day17.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import Testing
2+
3+
@testable import aoc
4+
5+
@Suite("Day17")
6+
struct Day17Tests {
7+
let testData = """
8+
Register A: 729
9+
Register B: 0
10+
Register C: 0
11+
12+
Program: 0,1,5,4,3,0
13+
"""
14+
15+
@Test("parsing")
16+
func testParsing() async throws {
17+
let c = Day17(data: testData).initialize()
18+
let computer = Computer(instructions: c.instructions, registers: c.registers)
19+
20+
#expect(computer.registers.A == 729)
21+
#expect(computer.registers.B == 0)
22+
#expect(computer.registers.C == 0)
23+
#expect(computer.instructions == [0, 1, 5, 4, 3, 0])
24+
25+
}
26+
27+
@Test("Common operations")
28+
func testOperations() async throws {
29+
var c1 = Computer(
30+
instructions: [2, 6], registers: Registers(A: 0, B: 0, C: 9)
31+
)
32+
#expect(c1.execute() == "")
33+
#expect(
34+
c1.registers.B == 1)
35+
36+
var c2 = Computer(
37+
instructions: [5, 0, 5, 1, 5, 4], registers: Registers(A: 10, B: 0, C: 0)
38+
)
39+
#expect(c2.execute() == "0,1,2")
40+
41+
var c3 = Computer(
42+
instructions: [0, 1, 5, 4, 3, 0], registers: Registers(A: 2024, B: 0, C: 0)
43+
)
44+
#expect(c3.execute() == "4,2,5,6,7,7,7,7,3,1,0")
45+
#expect(c3.registers.A == 0)
46+
47+
var c4 = Computer(
48+
instructions: [1, 7], registers: Registers(A: 0, B: 29, C: 0)
49+
)
50+
#expect(c4.execute() == "")
51+
#expect(c4.registers.B == 26)
52+
53+
var c5 = Computer(
54+
instructions: [4, 0], registers: Registers(A: 0, B: 2024, C: 43690)
55+
)
56+
#expect(c5.execute() == "")
57+
#expect(c5.registers.B == 44354)
58+
}
59+
60+
@Test("part1")
61+
func testPart1() async throws {
62+
let challenge = Day17(data: testData)
63+
#expect(challenge.part1() == "4,6,3,5,6,3,5,2,1,0")
64+
}
65+
66+
@Test("part2")
67+
func testPart2() async throws {
68+
let challenge = Day17(data: testData)
69+
#expect(challenge.part2() == 0)
70+
}
71+
}

0 commit comments

Comments
 (0)