From 6cb283d4e4edf5441aa3df2c4e1604b6fdf996ce Mon Sep 17 00:00:00 2001 From: Thomas Ruggeri Date: Sat, 28 Dec 2024 01:09:08 -0800 Subject: [PATCH 1/2] feat: Solving day1 part two --- docs/day1.md | 36 +++++++++++++++++++++++++++++++++++- src/day1/day1.go | 19 ++++++++++++++++--- src/day1/day1_test.go | 13 +++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/docs/day1.md b/docs/day1.md index b1f1adc..22b46d3 100644 --- a/docs/day1.md +++ b/docs/day1.md @@ -44,4 +44,38 @@ In the example list above, the pairs and distances would be as follows: To find the total distance between the left list and the right list, add up the distances between all of the pairs you found. In the example above, this is `2 + 1 + 0 + 1 + 2 + 5`, a total distance of `11`! -Your actual left and right lists contain many location IDs. What is the total distance between your lists? \ No newline at end of file +Your actual left and right lists contain many location IDs. What is the total distance between your lists? + +### Part Two + +Your analysis only confirmed what everyone feared: the two lists of location IDs are indeed very different. + +Or are they? + +The Historians can't agree on which group made the mistakes or how to read most of the Chief's handwriting, but in the commotion you notice an interesting detail: a lot of location IDs appear in both lists! Maybe the other numbers aren't location IDs at all but rather misinterpreted handwriting. + +This time, you'll need to figure out exactly how often each number from the left list appears in the right list. Calculate a total similarity score by adding up each number in the left list after multiplying it by the number of times that number appears in the right list. + +Here are the same example lists again: + +```txt +3 4 +4 3 +2 5 +1 3 +3 9 +3 3 +``` + +For these example lists, here is the process of finding the similarity score: + +* The first number in the left list is `3`. It appears in the right list three times, so the similarity score increases by `3 * 3 = 9`. +* The second number in the left list is `4`. It appears in the right list once, so the similarity score increases by `4 * 1 = 4`. +* The third number in the left list is `2`. It does not appear in the right list, so the similarity score does not increase `(2 * 0 = 0)`. +* The fourth number, `1`, also does not appear in the right list. +* The fifth number, `3`, appears in the right list three times; the similarity score increases by `9`. +* The last number, `3`, appears in the right list three times; the similarity score again increases by `9`. + +So, for these example lists, the similarity score at the end of this process is `31` `(9 + 4 + 0 + 0 + 9 + 9)`. + +Once again consider your left and right lists. What is their similarity score? \ No newline at end of file diff --git a/src/day1/day1.go b/src/day1/day1.go index 8620e04..e721626 100644 --- a/src/day1/day1.go +++ b/src/day1/day1.go @@ -13,6 +13,19 @@ func Solve(input string) uint { return solve(parseInput(input)) } +func PartTwo(input string) uint { + left, right := parseInput(input) + occurances := make(map[uint]uint) + for _, r := range right { + occurances[r] += 1 + } + var result uint = 0 + for _, l := range left { + result += l * occurances[l] + } + return result +} + func parseInput(input string) ([]uint, []uint) { var a, b []uint for _, line := range strings.Split(input, "\n") { @@ -22,9 +35,9 @@ func parseInput(input string) ([]uint, []uint) { } x, _ := strconv.Atoi(values[0]) - a = slices.Concat(a, []uint{uint(x)}) + a = append(a, uint(x)) y, _ := strconv.Atoi(values[1]) - b = slices.Concat(b, []uint{uint(y)}) + b = append(b, uint(y)) } return a, b } @@ -34,7 +47,7 @@ func solve(a, b []uint) uint { slices.Sort(b) var sum uint = 0 for i := range a { - sum = sum + absDiffUint(a[i], b[i]) + sum += absDiffUint(a[i], b[i]) } return sum } diff --git a/src/day1/day1_test.go b/src/day1/day1_test.go index 70c7799..eaf21cc 100644 --- a/src/day1/day1_test.go +++ b/src/day1/day1_test.go @@ -16,3 +16,16 @@ func TestSample(t *testing.T) { t.Errorf("Calculated solution was not expected") } } + +func TestSamplePartTwo(t *testing.T) { + input := `3 4 +4 3 +2 5 +1 3 +3 9 +3 3` + result := PartTwo(input) + if result != 31 { + t.Errorf("Calculated solution was not expected") + } +} From 35ccb8645f942836869e942f9a9864fae5feb452 Mon Sep 17 00:00:00 2001 From: Thomas Ruggeri Date: Sat, 28 Dec 2024 01:09:19 -0800 Subject: [PATCH 2/2] feat: Solving day2 part two --- docs/day2.md | 21 +++++++++++++++ src/day2/day2.go | 49 ++++++++++++++++++++++++++-------- src/day2/day2_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 11 deletions(-) diff --git a/docs/day2.md b/docs/day2.md index 54a887f..ad5739a 100644 --- a/docs/day2.md +++ b/docs/day2.md @@ -40,3 +40,24 @@ In the example above, the reports can be found safe or unsafe by checking those So, in this example, `2` reports are safe. Analyze the unusual data from the engineers. How many reports are safe? + +### Part Two + +The engineers are surprised by the low number of safe reports until they realize they forgot to tell you about the Problem Dampener. + +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! + +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. + +More of the above example's reports are now safe: + +* `7 6 4 2 1`: Safe without removing any level. +* `1 2 7 8 9`: Unsafe regardless of which level is removed. +* `9 7 6 2 1`: Unsafe regardless of which level is removed. +* `1 3 2 4 5`: Safe by removing the second level, `3`. +* `8 6 4 4 1`: Safe by removing the third level, `4`. +* `1 3 6 7 9`: Safe without removing any level. + +Thanks to the Problem Dampener, `4` reports are actually safe! + +Update your analysis by handling situations where the Problem Dampener can remove a single level from unsafe reports. How many reports are now safe? \ No newline at end of file diff --git a/src/day2/day2.go b/src/day2/day2.go index ce25050..57cff78 100644 --- a/src/day2/day2.go +++ b/src/day2/day2.go @@ -13,7 +13,11 @@ type level uint type report []level func Solve(input string) uint { - return solve(parseInput(input)) + return solve(parseInput(input), 0) +} + +func PartTwo(input string) uint { + return solve(parseInput(input), 1) } func parseInput(input string) []report { @@ -33,32 +37,55 @@ func parseInput(input string) []report { return result } -func solve(input []report) uint { +func solve(input []report, tolerance uint) uint { var result uint = 0 for _, report := range input { - if isValidReport(report) { + if isValidReport(report, tolerance) { result += 1 } } return result } -func isValidReport(report report) bool { +func isValidReport(report report, tolerance uint) bool { if len(report) < 2 { return true } - prev := report[0] + var violations uint = 0 ascending := report[1] > report[0] - for i, level := range report { - if i == 0 { - continue + i := 0 + for { + i++ + if i > len(report)-1 { + break } - if !isValidDelta(level, prev) || !isValidTrajectory(ascending, level, prev) { - return false + if !isValidDelta(report[i], report[i-1]) || !isValidTrajectory(ascending, report[i], report[i-1]) { + violations++ + if violations > tolerance { + return false + } + + selfRemoved := slices.Concat(report[0:i], report[i+1:]) + valid := isValidReport(selfRemoved, tolerance-violations) + if valid { + return true + } + + prevRemoved := slices.Concat(report[0:i-1], report[i:]) + valid = isValidReport(prevRemoved, tolerance-violations) + if valid { + return true + } + + if i == 1 { + return false + } + twoBackRemoved := slices.Concat(report[0:i-2], report[i-1:]) + valid = isValidReport(twoBackRemoved, tolerance-violations) + return valid } - prev = level } return true } diff --git a/src/day2/day2_test.go b/src/day2/day2_test.go index 58accc0..b18004a 100644 --- a/src/day2/day2_test.go +++ b/src/day2/day2_test.go @@ -16,3 +16,64 @@ func TestSample(t *testing.T) { t.Errorf("Calculated solution was not expected") } } + +func TestSamplePartTwo(t *testing.T) { + input := `7 6 4 2 1 +1 2 7 8 9 +9 7 6 2 1 +1 3 2 4 5 +8 6 4 4 1 +1 3 6 7 9` + result := PartTwo(input) + if result != 4 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwoFirstTooLarge(t *testing.T) { + input := `1 5 6 7 8` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwoFirstThrowsTraj(t *testing.T) { + input := `4 5 4 3 2` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwoLastTooLarge(t *testing.T) { + input := `1 2 3 4 9` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwoLastThrowsTraj(t *testing.T) { + input := `5 4 3 2 3` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwo2ndLastTooLarge(t *testing.T) { + input := `9 8 7 4 5` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +} + +func TestPartTwo2ndLastThrowsTraj(t *testing.T) { + input := `5 4 3 4 1` + result := PartTwo(input) + if result != 1 { + t.Errorf("Calculated solution was not expected") + } +}