diff --git a/day24/Parts2_Solution.xlsx b/day24/Parts2_Solution.xlsx new file mode 100644 index 0000000..c9835e9 Binary files /dev/null and b/day24/Parts2_Solution.xlsx differ diff --git a/day24/day24.go b/day24/day24.go index ebba12d..f19866e 100644 --- a/day24/day24.go +++ b/day24/day24.go @@ -1,6 +1,7 @@ package day24 import ( + "math" "strings" "gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils" @@ -69,3 +70,85 @@ func Part1(lines []string, min, max float64) int { return result } + +// Adapted from Java code given here : https://github.com/ash42/adventofcode/blob/main/adventofcode2023/src/nl/michielgraat/adventofcode2023/day24/Day24.java +// Explanations can be found here : https://www.cs.emory.edu/~cheung/Courses/170/Syllabus/09/gaussian-elim.html +func gaussianElimination(coefficients [][]float64, rhs []float64) { + size := len(coefficients) + for i := 0; i < size; i++ { + // Select pivot + pivot := coefficients[i][i] + // Normalize row i + for j := 0; j < size; j++ { + coefficients[i][j] = coefficients[i][j] / pivot + } + rhs[i] = rhs[i] / pivot + // Sweep using row i + for k := 0; k < size; k++ { + if k != i { + factor := coefficients[k][i] + for j := 0; j < size; j++ { + coefficients[k][j] = coefficients[k][j] - factor*coefficients[i][j] + } + rhs[k] = rhs[k] - factor*rhs[i] + } + } + } +} + +// Adapted from solution given here : https://www.reddit.com/r/adventofcode/comments/18q40he/2023_day_24_part_2_a_straightforward_nonsolver/ +// and from Java code given here : https://github.com/ash42/adventofcode/blob/main/adventofcode2023/src/nl/michielgraat/adventofcode2023/day24/Day24.java +func getCoordinates(stones []Hailstone) Hailstone { + coefficients := [][]float64{{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} + rhs := []float64{0.0, 0.0, 0.0, 0.0} + + // Get X,Y,VX,VY + for i := 0; i < 4; i++ { + s1 := stones[i] + s2 := stones[i+1] + coefficients[i][0] = float64(s2.vy - s1.vy) + coefficients[i][1] = float64(s1.vx - s2.vx) + coefficients[i][2] = float64(s1.py - s2.py) + coefficients[i][3] = float64(s2.px - s1.px) + rhs[i] = float64(-s1.px*s1.vy + s1.py*s1.vx + s2.px*s2.vy - s2.py*s2.vx) + } + + gaussianElimination(coefficients, rhs) + + var x int64 = int64(math.Round(rhs[0])) + var y int64 = int64(math.Round(rhs[1])) + var vx int64 = int64(math.Round(rhs[2])) + var vy int64 = int64(math.Round(rhs[3])) + + // Get X,VZ + coefficients = [][]float64{{0.0, 0.0}, {0.0, 0.0}} + rhs = []float64{0.0, 0.0} + for i := 0; i < 2; i++ { + s1 := stones[i] + s2 := stones[i+1] + coefficients[i][0] = float64(s1.vx - s2.vx) + coefficients[i][1] = float64(s2.px - s1.px) + rhs[i] = float64(-s1.px*s1.vz + s1.pz*s1.vx + s2.px*s2.vz - s2.pz*s2.vx - ((s2.vz - s1.vz) * x) - ((s1.pz - s2.pz) * vx)) + } + + gaussianElimination(coefficients, rhs) + + var z int64 = int64(math.Round(rhs[0])) + var vz int64 = int64(math.Round(rhs[1])) + + return Hailstone{x, y, z, vx, vy, vz} +} + +func Part2(lines []string) int64 { + stones := []Hailstone{} + + for _, line := range lines { + values := utils.ParseInt64Array(strings.Replace(line, " @", ",", -1), ", ") + stone := Hailstone{values[0], values[1], values[2], values[3], values[4], values[5]} + stones = append(stones, stone) + } + + stone := getCoordinates(stones) + + return stone.px + stone.py + stone.pz +} diff --git a/day24/day24_test.go b/day24/day24_test.go index 00452c4..b5e16f6 100644 --- a/day24/day24_test.go +++ b/day24/day24_test.go @@ -31,3 +31,29 @@ func TestPart1WithInput(t *testing.T) { t.Fatalf("expected 21785, got %d", result) } } + +func TestPart2(t *testing.T) { + lines := []string{ + "19, 13, 30 @ -2, 1, -2", + "18, 19, 22 @ -1, -1, -2", + "20, 25, 34 @ -2, -2, -4", + "12, 31, 28 @ -1, -2, -1", + "20, 19, 15 @ 1, -5, -3", + } + + result := Part2(lines) + + if result != 47 { + t.Fatalf("expected 47, got %d", result) + } +} + +func TestPart2WithInput(t *testing.T) { + lines := utils.ReadLines("input.txt") + + result := Part2(lines) + + if result != 554668916217145 { + t.Fatalf("expected 554668916217145, got %d", result) + } +}