Skip to content

Commit 1e6b226

Browse files
committed
day3 part2
1 parent 0d8d482 commit 1e6b226

File tree

2 files changed

+130
-3
lines changed

2 files changed

+130
-3
lines changed

resources/2024/day03-requirement.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,26 @@
2323
Sum: `(2*4) + (5*5) + (11*8) + (8*5) = 161`
2424

2525
The goal is to find the sum of all valid multiplication results in the corrupted input.
26+
27+
--- Part Two ---
28+
1. Two new instructions are added:
29+
- `do()`: Enables multiplication instructions
30+
- `don't()`: Disables multiplication instructions
31+
32+
2. Key rules:
33+
- At program start, multiplications are enabled by default
34+
- Only the most recent `do()`/`don't()` instruction affects the state
35+
- Only enabled `mul()` instructions should be calculated
36+
37+
3. Example:
38+
```
39+
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)do()?mul(8,5))
40+
```
41+
- `mul(2,4)` is counted (enabled by default)
42+
- `don't()` disables multiplications
43+
- `mul(5,5)` and `mul(11,8)` are ignored (disabled)
44+
- `do()` re-enables multiplications
45+
- `mul(8,5)` is counted
46+
- Final sum: `(2*4) + (8*5) = 48`
47+
48+
The task is to modify our previous solution to track the enabled/disabled state and only sum up the results of enabled multiplications.

src/adventofcode2024/day03.odin

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "core:strconv"
66
import "core:strings"
77
import "core:testing"
88
import "core:text/match"
9+
import "core:unicode"
910

1011
main :: proc() {
1112
data, ok := os.read_entire_file("resources/2024/day03-input.txt")
@@ -15,6 +16,8 @@ main :: proc() {
1516
input := string(data)
1617

1718
fmt.println(part1(input)) // 179834255
19+
fmt.println(part2(input)) // 80570939
20+
1821
}
1922

2023
part1 :: proc(input: string) -> (sum: int) {
@@ -24,15 +27,116 @@ part1 :: proc(input: string) -> (sum: int) {
2427
matcher := match.matcher_init(input, pattern)
2528
for s in match.matcher_gmatch(&matcher) {
2629
ss := strings.split(s, ",")
30+
defer delete(ss)
2731
sum += strconv.atoi(ss[0]) * strconv.atoi(ss[1])
2832
}
29-
return
33+
return sum
3034
}
3135

3236
@(test)
3337
part1_test :: proc(t: ^testing.T) {
34-
example := `xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))`
38+
example := `xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))`
3539
result := part1(example)
36-
fmt.printf("Test Result: %d\n", result)
3740
testing.expect_value(t, result, 161)
3841
}
42+
43+
// Helper to check for exact match of an instruction
44+
check_instruction :: proc(text: string, pos: int) -> (kind: enum {
45+
None,
46+
Do,
47+
Dont,
48+
Mul,
49+
}, next_pos: int) {
50+
if pos >= len(text) {
51+
return .None, pos
52+
}
53+
54+
// Check for do()
55+
if pos + 4 <= len(text) && text[pos:pos + 4] == "do()" {
56+
return .Do, pos + 4
57+
}
58+
59+
// Check for don't()
60+
if pos + 7 <= len(text) && text[pos:pos + 7] == "don't()" {
61+
return .Dont, pos + 7
62+
}
63+
64+
// Check for mul(X,Y)
65+
if pos + 5 <= len(text) && text[pos:pos + 4] == "mul(" {
66+
new_pos := pos
67+
new_pos += 4 // skip "mul("
68+
69+
// Parse first number
70+
num1_start := new_pos
71+
for new_pos < len(text) && unicode.is_digit(rune(text[new_pos])) {
72+
new_pos += 1
73+
}
74+
if new_pos == num1_start || new_pos > num1_start + 3 { // check 1-3 digits
75+
return .None, pos + 1
76+
}
77+
78+
// Check for comma
79+
if new_pos >= len(text) || text[new_pos] != ',' {
80+
return .None, pos + 1
81+
}
82+
new_pos += 1
83+
84+
// Parse second number
85+
num2_start := new_pos
86+
for new_pos < len(text) && unicode.is_digit(rune(text[new_pos])) {
87+
new_pos += 1
88+
}
89+
if new_pos == num2_start || new_pos > num2_start + 3 { // check 1-3 digits
90+
return .None, pos + 1
91+
}
92+
93+
// Check for closing parenthesis
94+
if new_pos >= len(text) && text[new_pos] != ')' {
95+
return .None, pos + 1
96+
}
97+
98+
return .Mul, new_pos + 1
99+
}
100+
101+
return .None, pos + 1
102+
}
103+
104+
part2 :: proc(input: string) -> (sum: int) {
105+
sum = 0
106+
mul_enabled := true
107+
pos := 0
108+
109+
for pos < len(input) {
110+
kind, new_pos := check_instruction(input, pos)
111+
112+
switch kind {
113+
case .Do:
114+
mul_enabled = true
115+
case .Dont:
116+
mul_enabled = false
117+
case .Mul:
118+
if mul_enabled {
119+
// Extract and parse numbers
120+
mul_str := input[pos + 4:new_pos - 1]
121+
nums := strings.split(mul_str, ",")
122+
defer delete(nums)
123+
if len(nums) == 2 {
124+
sum += strconv.atoi(nums[0]) * strconv.atoi(nums[1])
125+
}
126+
}
127+
case .None:
128+
// Continue to next character
129+
}
130+
131+
pos = new_pos
132+
}
133+
134+
return sum
135+
}
136+
137+
@(test)
138+
part2_test :: proc(t: ^testing.T) {
139+
example := `xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))`
140+
result := part2(example)
141+
testing.expect_value(t, result, 48)
142+
}

0 commit comments

Comments
 (0)