Skip to content

Commit 8091959

Browse files
Y23 D24
1 parent 3251af8 commit 8091959

File tree

1 file changed

+262
-0
lines changed

1 file changed

+262
-0
lines changed
Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
namespace AdventOfCode.Puzzles._2023;
2+
3+
[Puzzle(2023, 24, CodeType.Original)]
4+
public partial class Day_24_Original : IPuzzle
5+
{
6+
//private const double Low = 7;
7+
//private const double High = 27;
8+
private const double Low = 200_000_000_000_000;
9+
private const double High = 400_000_000_000_000;
10+
11+
private record struct Hailstone(
12+
double Px, double Py, double Pz,
13+
int Vx, int Vy, int Vz)
14+
{
15+
private readonly double _c2d = (Py * Vx) - (Px * Vy);
16+
17+
public readonly bool IsValid2dIntersection(Hailstone other)
18+
{
19+
var det = (Vx * other.Vy) - (Vy * other.Vx);
20+
if (det == 0)
21+
return false;
22+
23+
var x = ((_c2d * other.Vx) - (Vx * other._c2d)) / det;
24+
if (!x.Between(Low, High))
25+
return false;
26+
27+
var y = ((_c2d * other.Vy) - (Vy * other._c2d)) / det;
28+
if (!y.Between(Low, High))
29+
return false;
30+
31+
return (x - Px) / Vx > 0
32+
&& (x - other.Px) / other.Vx > 0;
33+
}
34+
}
35+
36+
private static long FindIntersection(Hailstone a, Hailstone b, Hailstone c)
37+
{
38+
// for any given stone, A = A0 + Av*t, our ray (P + Qt) should have a matching t value.
39+
// With three stones, we have nine equations and nine unknowns (t, u, v, Px, Py, Pz, Qx, Qy, Qz), assuming that
40+
// any solution for three will work for all:
41+
// A0x + Avx*t = Px + Qx*t
42+
// A0y + Avy*t = Py + Qy*t
43+
// A0z + Avz*t = Pz + Qz*t
44+
//
45+
// B0x + Bvx*u = Px + Qx*u
46+
// B0y + Bvy*u = Py + Qy*u
47+
// B0z + Bvz*u = Pz + Qz*u
48+
//
49+
// C0x + Cvx*v = Px + Qx*v
50+
// C0y + Cvy*v = Py + Qy*v
51+
// C0z + Cvz*v = Pz + Qz*v
52+
//
53+
// We can eliminate t, u, and v and end up with 6 equations with 6 unknowns (Px, Py, Pz, Qx, Qy, Qz):
54+
// (Px - A0x) / (Avx - Qx) = (Py - A0y) / (Avy - Qy) = (Pz - A0z) / (Avz - Qz)
55+
// (Px - B0x) / (Bvx - Qx) = (Py - B0y) / (Bvy - Qy) = (Pz - B0z) / (Bvz - Qz)
56+
// (Px - C0x) / (Cvx - Qx) = (Py - C0y) / (Cvy - Qy) = (Pz - C0z) / (Cvz - Qz)
57+
58+
// Rearranging the Px/Py pairing:
59+
60+
// Px * Avy - Px * Qy - A0x * Avy + A0x * Qy = Py * Avx - Py * Qx - A0y * Avx + A0y * Qx
61+
// (Px * Qy - Py * Qx) = (Px * Avy - Py * Avx) + (A0y * Avx - A0x * Avy) + (A0x * Qy - A0y * Qx)
62+
// (Px * Qy - Py * Qx) = (Px * Bvy - Py * Bvx) + (B0y * Bvx - B0x * Bvy) + (B0x * Qy - B0y * Qx)
63+
// (Px * Qy - Py * Qx) = (Px * Cvy - Py * Cvx) + (C0y * Cvx - C0x * Cvy) + (C0x * Qy - C0y * Qx)
64+
//
65+
// Note that this gets a common (Px * Qy - Py * Qx) on the left side of everything, and the right side of each is
66+
// now just a linear equation.
67+
// Do the same for the Pz/Px and Py/Pz pairints:
68+
//
69+
// (Pz * Qx - Px * Qz) = (Pz * Avx - Px * Avz) + (A0x * Avz - A0z * Avx) + (A0z * Qx - A0x * Qz)
70+
// (Pz * Qx - Px * Qz) = (Pz * Bvx - Px * Bvz) + (B0x * Bvz - B0z * Bvx) + (B0z * Qx - B0x * Qz)
71+
// (Pz * Qx - Px * Qz) = (Pz * Cvx - Px * Cvz) + (C0x * Cvz - C0z * Cvx) + (C0z * Qx - C0x * Qz)
72+
//
73+
// (Py * Qz - Pz * Qy) = (Py * Avz - Pz * Avy) + (A0z * Avy - A0y * Avz) + (A0y * Qz - A0z * Qy)
74+
// (Py * Qz - Pz * Qy) = (Py * Bvz - Pz * Bvy) + (B0z * Bvy - B0y * Bvz) + (B0y * Qz - B0z * Qy)
75+
// (Py * Qz - Pz * Qy) = (Py * Cvz - Pz * Cvy) + (C0z * Cvy - C0y * Cvz) + (C0y * Qz - C0z * Qy)
76+
//
77+
// This now turns into a series of 6 straight-up linear equations, which we can solve in, you know, the normal way.
78+
// [Avy - Bvy]Px - [Avx - Bvx]Py - [A0y - B0y]Qx + [A0x - B0x]Qy = (B0y * Bvx - B0x * Bvy) - (A0y * Avx - A0x * Avy)
79+
// [Avy - Cvy]Px - [Avx - Cvx]Py - [A0y - C0y]Qx + [A0x - C0x]Qy = (C0y * Cvx - C0x * Cvy) - (A0y * Avx - A0x * Avy)
80+
// [Avx - Bvx]Pz - [Avz - Bvz]Px - [A0x - B0x]Qz + [A0z - B0z]Qx = (B0x * Bvz - B0z * Bvx) - (A0x * Avz - A0z * Avx)
81+
// [Avx - Cvx]Pz - [Avz - Cvz]Px - [A0x - C0x]Qz + [A0z - C0z]Qx = (C0x * Cvz - C0z * Cvx) - (A0x * Avz - A0z * Avx)
82+
// [Avz - Bvz]Py - [Avy - Bvy]Pz - [A0z - B0z]Qy + [A0y - B0y]Qz = (B0z * Bvy - B0y * Bvz) - (A0z * Avy - A0y * Avz)
83+
// [Avz - Cvz]Py - [Avy - Cvy]Pz - [A0z - C0z]Qy + [A0y - C0y]Qz = (C0z * Cvy - C0y * Cvz) - (A0z * Avy - A0y * Avz)
84+
//
85+
// Combine some terms to get:
86+
double abvx = a.Vx - b.Vx;
87+
double abvy = a.Vy - b.Vy;
88+
double abvz = a.Vz - b.Vz;
89+
90+
double acvx = a.Vx - c.Vx;
91+
double acvy = a.Vy - c.Vy;
92+
double acvz = a.Vz - c.Vz;
93+
94+
var ab0x = a.Px - b.Px;
95+
var ab0y = a.Py - b.Py;
96+
var ab0z = a.Pz - b.Pz;
97+
98+
var ac0x = a.Px - c.Px;
99+
var ac0y = a.Py - c.Py;
100+
var ac0z = a.Pz - c.Pz;
101+
102+
var h0 = (b.Py * b.Vx) - (b.Px * b.Vy) - ((a.Py * a.Vx) - (a.Px * a.Vy));
103+
var h1 = (c.Py * c.Vx) - (c.Px * c.Vy) - ((a.Py * a.Vx) - (a.Px * a.Vy));
104+
var h2 = (b.Px * b.Vz) - (b.Pz * b.Vx) - ((a.Px * a.Vz) - (a.Pz * a.Vx));
105+
var h3 = (c.Px * c.Vz) - (c.Pz * c.Vx) - ((a.Px * a.Vz) - (a.Pz * a.Vx));
106+
var h4 = (b.Pz * b.Vy) - (b.Py * b.Vz) - ((a.Pz * a.Vy) - (a.Py * a.Vz));
107+
var h5 = (c.Pz * c.Vy) - (c.Py * c.Vz) - ((a.Pz * a.Vy) - (a.Py * a.Vz));
108+
109+
// abvy*Px - abvx*Py - ab0y*Qx + ab0x*Qy = h0
110+
// acvy*Px - acvx*Py - ac0y*Qx + ac0x*Qy = h1
111+
// abvx*Pz - abvz*Px - ab0x*Qz + ab0z*Qx = h2
112+
// acvx*Pz - acvz*Px - ac0x*Qz + ac0z*Qx = h3
113+
// abvz*Py - abvy*Pz - ab0z*Qy + ab0y*Qz = h4
114+
// acvz*Py - acvy*Pz - ac0z*Qy + ac0y*Qz = h5
115+
116+
// Now we're going to take each pair of those eliminate its initial P variable (leaving just the other)
117+
// Okay now that's 6 linear equations and 6 variable, right?
118+
//
119+
// Px = [h0 + abvx*Py + ab0y*Qx - ab0x*Qy]/abvy
120+
// Px = [h1 + acvx*Py + ac0y*Qx - ac0x*Qy]/acvy
121+
//
122+
// [h0 + abvx*Py + ab0y*Qx - ab0x*Qy]/abvy = [h1 + acvx*Py + ac0y*Qx - ac0x*Qy]/acvy
123+
// (acvy*abvx - abvy*acvx)*Py = [abvy*ac0y - acvy*ab0y]*Qx + [acvy*ab0x - abvy*ac0x]*Qy + [abvy*h1 - acvy*h0]
124+
//
125+
// -----------
126+
// Py = ([abvy*ac0y - acvy*ab0y]*Qx + [acvy*ab0x - abvy*ac0x]*Qy + [abvy*h1 - acvy*h0])/(acvy*abvx - abvy*acvx)
127+
// -----------
128+
//
129+
// [h4 + abvy*Pz + ab0z*Qy - ab0y*Qz]/abvz = [h5 + acvy*Pz + ac0z*Qy - ac0y*Qz]/acvz
130+
// (acvz*abvy - abvz*acvy)*Pz = [abvz*ac0z - acvz*ab0z]*Qy + [acvz*ab0y - abvz*ac0y)*Qz + [abvz*h5 - acvz*h4]
131+
//
132+
//
133+
// -----------
134+
// Pz = ([abvz*ac0z - acvz*ab0z]*Qy + [acvz*ab0y - abvz*ac0y)*Qz + [abvz*h5 - acvz*h4])/(acvz*abvy - abvz*acvy)
135+
// -----------
136+
//
137+
// [h2 + abvz*Px + ab0x*Qz - ab0z*Qx]/abvx = [h3 + acvz*Px + ac0x*Qz - ac0z*Qx]/acvx
138+
// (acvx*abvz - abvx*acvz)*Px = [abvx*ac0x - acvx*ab0x]*Qz + [acvx*ab0z - abvx*ac0z]*Qx + [abvx*h3 - acvx*h2]
139+
//
140+
// -----------
141+
// Px = ([abvx*ac0x - acvx*ab0x]*Qz + [acvx*ab0z - abvx*ac0z]*Qx + [abvx*h3 - acvx*h2])/(acvx*abvz - abvx*acvz)
142+
// Py = ([abvy*ac0y - acvy*ab0y]*Qx + [acvy*ab0x - abvy*ac0x]*Qy + [abvy*h1 - acvy*h0])/(acvy*abvx - abvy*acvx)
143+
// Pz = ([abvz*ac0z - acvz*ab0z]*Qy + [acvz*ab0y - abvz*ac0y)*Qz + [abvz*h5 - acvz*h4])/(acvz*abvy - abvz*acvy)
144+
// -----------
145+
//
146+
// Alright, now we can sub these into (half of) our original linear equations and rearrange in terms of Qx, Qy,
147+
// and Qz, leaving us with three equations and three variables.
148+
// abvy*Px - abvx*Py - ab0y*Qx + ab0x*Qy = h0
149+
// abvx*Pz - abvz*Px - ab0x*Qz + ab0z*Qx = h2
150+
// abvz*Py - abvy*Pz - ab0z*Qy + ab0y*Qz = h4
151+
//
152+
// Make some more variables to make this easier
153+
// Px = (Pxz*Qz + Pxx*Qx + Pxc)/Pxd
154+
// Py = (Pyx*Qx + Pyy*Qy + Pyc)/Pyd
155+
// Pz = (Pzy*Qy + Pzz*Qz + Pzc)/Pzd
156+
var Pxx = (acvx * ab0z) - (abvx * ac0z);
157+
var Pyy = (acvy * ab0x) - (abvy * ac0x);
158+
var Pzz = (acvz * ab0y) - (abvz * ac0y);
159+
160+
var Pxz = (abvx * ac0x) - (acvx * ab0x);
161+
var Pzy = (abvz * ac0z) - (acvz * ab0z);
162+
var Pyx = (abvy * ac0y) - (acvy * ab0y);
163+
164+
var Pxc = (abvx * h3) - (acvx * h2);
165+
var Pyc = (abvy * h1) - (acvy * h0);
166+
var Pzc = (abvz * h5) - (acvz * h4);
167+
168+
var Pxd = (acvx * abvz) - (abvx * acvz);
169+
var Pyd = (acvy * abvx) - (abvy * acvx);
170+
var Pzd = (acvz * abvy) - (abvz * acvy);
171+
172+
// abvy*[(Pxz*Qz + Pxx*Qx + Pxc)/Pxd] - abvx*[(Pyx*Qx + Pyy*Qy + Pyc)/Pyd] - ab0y*Qx + ab0x*Qy = h0
173+
// abvx*[(Pzy*Qy + Pzz*Qz + Pzc)/Pzd] - abvz*[(Pxz*Qz + Pxx*Qx + Pxc)/Pxd] - ab0x*Qz + ab0z*Qx = h2
174+
// abvz*[(Pyx*Qx + Pyy*Qy + Pyc)/Pyd] - abvy*[(Pzy*Qy + Pzz*Qz + Pzc)/Pzd] - ab0z*Qy + ab0y*Qz = h4
175+
//
176+
// okay this is unintelligible garbage now but we're almost there:
177+
//
178+
// ([abvy/Pxd]*Pxz)*Qz + ([abvy/Pxd]*Pxx - [abvx/Pyd]*Pyx - ab0y)*Qx + (ab0x - [abvx/Pyd]*Pyy)*Qy
179+
// = h0 - [abvy/Pxd]*Pxc + [abvx/Pyd]*Pyc
180+
// ([abvx/Pzd]*Pzy)*Qy + ([abvx/Pzd]*Pzz - [abvz/Pxd]*Pxz - ab0x)*Qz + (ab0z - [abvz/Pxd]*Pxx)*Qx
181+
// = h2 - [abvx/Pzd]*Pzc + [abvz/Pxd]*Pxc
182+
// ([abvz/Pyd]*Pyx)*Qx + ([abvz/Pyd]*Pyy - [abvy/Pzd]*Pzy - ab0z)*Qy + (ab0y - [abvy/Pzd]*Pzz)*Qz
183+
// = h4 - [abvz/Pyd]*Pyc + [abvy/Pzd]*Pzc
184+
//
185+
// MOAR VARIABLES
186+
var Qz0 = abvy / Pxd * Pxz;
187+
var Qx0 = (abvy / Pxd * Pxx) - (abvx / Pyd * Pyx) - ab0y;
188+
var Qy0 = ab0x - (abvx / Pyd * Pyy);
189+
var r0 = h0 - (abvy / Pxd * Pxc) + (abvx / Pyd * Pyc);
190+
var Qy1 = abvx / Pzd * Pzy;
191+
var Qz1 = (abvx / Pzd * Pzz) - (abvz / Pxd * Pxz) - ab0x;
192+
var Qx1 = ab0z - (abvz / Pxd * Pxx);
193+
var r1 = h2 - (abvx / Pzd * Pzc) + (abvz / Pxd * Pxc);
194+
var Qx2 = abvz / Pyd * Pyx;
195+
var Qy2 = (abvz / Pyd * Pyy) - (abvy / Pzd * Pzy) - ab0z;
196+
var Qz2 = ab0y - (abvy / Pzd * Pzz);
197+
var r2 = h4 - (abvz / Pyd * Pyc) + (abvy / Pzd * Pzc);
198+
199+
// Qz0*Qz + Qx0*Qx + Qy0*Qy = r0
200+
// Qy1*Qy + Qz1*Qz + Qx1*Qx = r1
201+
// Qx2*Qx + Qy2*Qy + Qz2*Qz = r2
202+
//
203+
// Qx = [r0 - Qy0*Qy - Qz0*Qz]/Qx0
204+
// = [r1 - Qy1*Qy - Qz1*Qz]/Qx1
205+
// = [r2 - Qy2*Qy - Qz2*Qz]/Qx2
206+
//
207+
// Qx1*r0 - Qx1*Qy0*Qy - Qx1*Qz0*Qz = Qx0*r1 - Qx0*Qy1*Qy - Qx0*Qz1*Qz
208+
// Qy = ([Qx0*Qz1 - Qx1*Qz0]Qz + [Qx1*r0 - Qx0*r1])/[Qx1*Qy0 - Qx0*Qy1]
209+
// = ([Qx0*Qz2 - Qx2*Qz0]Qz + [Qx2*r0 - Qx0*r2])/[Qx2*Qy0 - Qx0*Qy2]
210+
//
211+
// ([Qx2*Qy0 - Qx0*Qy2][Qx0*Qz1 - Qx1*Qz0] - [Qx1*Qy0 - Qx0*Qy1][Qx0*Qz2 - Qx2*Qz0])Qz
212+
// = [Qx1*Qy0 - Qx0*Qy1][Qx2*r0 - Qx0*r2] - [Qx2*Qy0 - Qx0*Qy2][Qx1*r0 - Qx0*r1]
213+
214+
// Alright after alllll that we can now solve for Qz, and then backsolve for everything else up the chain.
215+
var Qz = ((((Qx1 * Qy0) - (Qx0 * Qy1)) * ((Qx2 * r0) - (Qx0 * r2))) - (((Qx2 * Qy0) - (Qx0 * Qy2)) * ((Qx1 * r0) - (Qx0 * r1))))
216+
/ ((((Qx2 * Qy0) - (Qx0 * Qy2)) * ((Qx0 * Qz1) - (Qx1 * Qz0))) - (((Qx1 * Qy0) - (Qx0 * Qy1)) * ((Qx0 * Qz2) - (Qx2 * Qz0))));
217+
218+
var Qy = ((((Qx0 * Qz1) - (Qx1 * Qz0)) * Qz) + ((Qx1 * r0) - (Qx0 * r1))) / ((Qx1 * Qy0) - (Qx0 * Qy1));
219+
220+
var Qx = (r0 - (Qy0 * Qy) - (Qz0 * Qz)) / Qx0;
221+
222+
var Px = ((Pxz * Qz) + (Pxx * Qx) + Pxc) / Pxd;
223+
var Py = ((Pyx * Qx) + (Pyy * Qy) + Pyc) / Pyd;
224+
var Pz = ((Pzy * Qy) + (Pzz * Qz) + Pzc) / Pzd;
225+
226+
// Now, sum the (rounded, to deal with float precision issues) coordinates of the starting position together.
227+
// The end. FINALLY.
228+
return (long)Math.Round(Px) + (long)Math.Round(Py) + (long)Math.Round(Pz);
229+
}
230+
231+
public (string, string) Solve(PuzzleInput input)
232+
{
233+
var regex = HailstoneRegex();
234+
var hailstones = input.Lines
235+
.Select(l => regex.Match(l))
236+
.Select(m => new Hailstone(
237+
Px: double.Parse(m.Groups[1].Value),
238+
Py: double.Parse(m.Groups[2].Value),
239+
Pz: double.Parse(m.Groups[3].Value),
240+
Vx: int.Parse(m.Groups[4].Value),
241+
Vy: int.Parse(m.Groups[5].Value),
242+
Vz: int.Parse(m.Groups[6].Value)))
243+
.ToList();
244+
245+
var part1 = 0;
246+
for (var i = 0; i < hailstones.Count; i++)
247+
{
248+
for (var j = i + 1; j < hailstones.Count; j++)
249+
{
250+
if (hailstones[i].IsValid2dIntersection(hailstones[j]))
251+
part1++;
252+
}
253+
}
254+
255+
var part2 = FindIntersection(hailstones[0], hailstones[1], hailstones[2]);
256+
257+
return (part1.ToString(), part2.ToString());
258+
}
259+
260+
[GeneratedRegex(@"^(-?\d+),\s+(-?\d+),\s+(-?\d+)\s+@\s+(-?\d+),\s+(-?\d+),\s+(-?\d+)$")]
261+
private static partial Regex HailstoneRegex();
262+
}

0 commit comments

Comments
 (0)