Skip to content

Commit 1370b65

Browse files
committed
feat: Solving day2 part two
1 parent 35d9c16 commit 1370b65

File tree

3 files changed

+120
-11
lines changed

3 files changed

+120
-11
lines changed

docs/day2.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,24 @@ In the example above, the reports can be found safe or unsafe by checking those
4040
So, in this example, `2` reports are safe.
4141

4242
Analyze the unusual data from the engineers. How many reports are safe?
43+
44+
### Part Two
45+
46+
The engineers are surprised by the low number of safe reports until they realize they forgot to tell you about the Problem Dampener.
47+
48+
The Problem Dampener is a reactor-mounted module that lets the reactor safety systems tolerate a single bad level in what would otherwise be a safe report. It's like the bad level never happened!
49+
50+
Now, the same rules apply as before, except if removing a single level from an unsafe report would make it safe, the report instead counts as safe.
51+
52+
More of the above example's reports are now safe:
53+
54+
* `7 6 4 2 1`: Safe without removing any level.
55+
* `1 2 7 8 9`: Unsafe regardless of which level is removed.
56+
* `9 7 6 2 1`: Unsafe regardless of which level is removed.
57+
* `1 3 2 4 5`: Safe by removing the second level, `3`.
58+
* `8 6 4 4 1`: Safe by removing the third level, `4`.
59+
* `1 3 6 7 9`: Safe without removing any level.
60+
61+
Thanks to the Problem Dampener, `4` reports are actually safe!
62+
63+
Update your analysis by handling situations where the Problem Dampener can remove a single level from unsafe reports. How many reports are now safe?

src/day2/day2.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ type level uint
1313
type report []level
1414

1515
func Solve(input string) uint {
16-
return solve(parseInput(input))
16+
return solve(parseInput(input), 0)
17+
}
18+
19+
func PartTwo(input string) uint {
20+
return solve(parseInput(input), 1)
1721
}
1822

1923
func parseInput(input string) []report {
@@ -33,32 +37,55 @@ func parseInput(input string) []report {
3337
return result
3438
}
3539

36-
func solve(input []report) uint {
40+
func solve(input []report, tolerance uint) uint {
3741
var result uint = 0
3842
for _, report := range input {
39-
if isValidReport(report) {
43+
if isValidReport(report, tolerance) {
4044
result += 1
4145
}
4246
}
4347
return result
4448
}
4549

46-
func isValidReport(report report) bool {
50+
func isValidReport(report report, tolerance uint) bool {
4751
if len(report) < 2 {
4852
return true
4953
}
5054

51-
prev := report[0]
55+
var violations uint = 0
5256
ascending := report[1] > report[0]
53-
for i, level := range report {
54-
if i == 0 {
55-
continue
57+
i := 0
58+
for {
59+
i++
60+
if i > len(report)-1 {
61+
break
5662
}
5763

58-
if !isValidDelta(level, prev) || !isValidTrajectory(ascending, level, prev) {
59-
return false
64+
if !isValidDelta(report[i], report[i-1]) || !isValidTrajectory(ascending, report[i], report[i-1]) {
65+
violations++
66+
if violations > tolerance {
67+
return false
68+
}
69+
70+
selfRemoved := slices.Concat(report[0:i], report[i+1:])
71+
valid := isValidReport(selfRemoved, tolerance-violations)
72+
if valid {
73+
return true
74+
}
75+
76+
prevRemoved := slices.Concat(report[0:i-1], report[i:])
77+
valid = isValidReport(prevRemoved, tolerance-violations)
78+
if valid {
79+
return true
80+
}
81+
82+
if i == 1 {
83+
return false
84+
}
85+
twoBackRemoved := slices.Concat(report[0:i-2], report[i-1:])
86+
valid = isValidReport(twoBackRemoved, tolerance-violations)
87+
return valid
6088
}
61-
prev = level
6289
}
6390
return true
6491
}

src/day2/day2_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,64 @@ func TestSample(t *testing.T) {
1616
t.Errorf("Calculated solution was not expected")
1717
}
1818
}
19+
20+
func TestSamplePartTwo(t *testing.T) {
21+
input := `7 6 4 2 1
22+
1 2 7 8 9
23+
9 7 6 2 1
24+
1 3 2 4 5
25+
8 6 4 4 1
26+
1 3 6 7 9`
27+
result := PartTwo(input)
28+
if result != 4 {
29+
t.Errorf("Calculated solution was not expected")
30+
}
31+
}
32+
33+
func TestPartTwoFirstTooLarge(t *testing.T) {
34+
input := `1 5 6 7 8`
35+
result := PartTwo(input)
36+
if result != 1 {
37+
t.Errorf("Calculated solution was not expected")
38+
}
39+
}
40+
41+
func TestPartTwoFirstThrowsTraj(t *testing.T) {
42+
input := `4 5 4 3 2`
43+
result := PartTwo(input)
44+
if result != 1 {
45+
t.Errorf("Calculated solution was not expected")
46+
}
47+
}
48+
49+
func TestPartTwoLastTooLarge(t *testing.T) {
50+
input := `1 2 3 4 9`
51+
result := PartTwo(input)
52+
if result != 1 {
53+
t.Errorf("Calculated solution was not expected")
54+
}
55+
}
56+
57+
func TestPartTwoLastThrowsTraj(t *testing.T) {
58+
input := `5 4 3 2 3`
59+
result := PartTwo(input)
60+
if result != 1 {
61+
t.Errorf("Calculated solution was not expected")
62+
}
63+
}
64+
65+
func TestPartTwo2ndLastTooLarge(t *testing.T) {
66+
input := `9 8 7 4 5`
67+
result := PartTwo(input)
68+
if result != 1 {
69+
t.Errorf("Calculated solution was not expected")
70+
}
71+
}
72+
73+
func TestPartTwo2ndLastThrowsTraj(t *testing.T) {
74+
input := `5 4 3 4 1`
75+
result := PartTwo(input)
76+
if result != 1 {
77+
t.Errorf("Calculated solution was not expected")
78+
}
79+
}

0 commit comments

Comments
 (0)