From a61991af52fe34c7cee17fffa57f2b3ea784b772 Mon Sep 17 00:00:00 2001 From: Burnus Date: Fri, 5 Jan 2024 16:43:05 +0100 Subject: [PATCH] Added Solution for 2023 day 24 --- 2023/day24_never_tell_me_the_odds/Cargo.toml | 15 + .../challenge.txt | 125 ++++++++ 2023/day24_never_tell_me_the_odds/src/lib.rs | 248 +++++++++++++++ .../tests/challenge_input | 300 ++++++++++++++++++ .../tests/sample_input | 5 + 5 files changed, 693 insertions(+) create mode 100644 2023/day24_never_tell_me_the_odds/Cargo.toml create mode 100644 2023/day24_never_tell_me_the_odds/challenge.txt create mode 100644 2023/day24_never_tell_me_the_odds/src/lib.rs create mode 100644 2023/day24_never_tell_me_the_odds/tests/challenge_input create mode 100644 2023/day24_never_tell_me_the_odds/tests/sample_input diff --git a/2023/day24_never_tell_me_the_odds/Cargo.toml b/2023/day24_never_tell_me_the_odds/Cargo.toml new file mode 100644 index 0000000..ed9f59e --- /dev/null +++ b/2023/day24_never_tell_me_the_odds/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "day24_never_tell_me_the_odds" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[dev-dependencies] +criterion = "0.5.1" + +[[bench]] +name = "test_benchmark" +harness = false diff --git a/2023/day24_never_tell_me_the_odds/challenge.txt b/2023/day24_never_tell_me_the_odds/challenge.txt new file mode 100644 index 0000000..1dc1c1b --- /dev/null +++ b/2023/day24_never_tell_me_the_odds/challenge.txt @@ -0,0 +1,125 @@ +It seems like something is going wrong with the snow-making process. Instead of forming snow, the water that's been absorbed into the air seems to be forming [hail](https://en.wikipedia.org/wiki/Hail)! + +Maybe there's something you can do to break up the hailstones? + +Due to strong, probably-magical winds, the hailstones are all flying through the air in perfectly linear trajectories. You make a note of each hailstone's *position* and *velocity* (your puzzle input). For example: + +``` +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 + +``` + +Each line of text corresponds to the position and velocity of a single hailstone. The positions indicate where the hailstones are *right now* (at time `0`). The velocities are constant and indicate exactly how far each hailstone will move in *one nanosecond*. + +Each line of text uses the format `px py pz @ vx vy vz`. For instance, the hailstone specified by `20, 19, 15 @ 1, -5, -3` has initial X position `20`, Y position `19`, Z position `15`, X velocity `1`, Y velocity `-5`, and Z velocity `-3`. After one nanosecond, the hailstone would be at `21, 14, 12`. + +Perhaps you won't have to do anything. How likely are the hailstones to collide with each other and smash into tiny ice crystals? + +To estimate this, consider only the X and Y axes; *ignore the Z axis*. Looking *forward in time*, how many of the hailstones' *paths* will intersect within a test area? (The hailstones themselves don't have to collide, just test for intersections between the paths they will trace.) + +In this example, look for intersections that happen with an X and Y position each at least `7` and at most `27`; in your actual data, you'll need to check a much larger test area. Comparing all pairs of hailstones' future paths produces the following results: + +``` +Hailstone A: 19, 13, 30 @ -2, 1, -2 +Hailstone B: 18, 19, 22 @ -1, -1, -2 +Hailstones' paths will cross inside the test area (at x=14.333, y=15.333). + +Hailstone A: 19, 13, 30 @ -2, 1, -2 +Hailstone B: 20, 25, 34 @ -2, -2, -4 +Hailstones' paths will cross inside the test area (at x=11.667, y=16.667). + +Hailstone A: 19, 13, 30 @ -2, 1, -2 +Hailstone B: 12, 31, 28 @ -1, -2, -1 +Hailstones' paths will cross outside the test area (at x=6.2, y=19.4). + +Hailstone A: 19, 13, 30 @ -2, 1, -2 +Hailstone B: 20, 19, 15 @ 1, -5, -3 +Hailstones' paths crossed in the past for hailstone A. + +Hailstone A: 18, 19, 22 @ -1, -1, -2 +Hailstone B: 20, 25, 34 @ -2, -2, -4 +Hailstones' paths are parallel; they never intersect. + +Hailstone A: 18, 19, 22 @ -1, -1, -2 +Hailstone B: 12, 31, 28 @ -1, -2, -1 +Hailstones' paths will cross outside the test area (at x=-6, y=-5). + +Hailstone A: 18, 19, 22 @ -1, -1, -2 +Hailstone B: 20, 19, 15 @ 1, -5, -3 +Hailstones' paths crossed in the past for both hailstones. + +Hailstone A: 20, 25, 34 @ -2, -2, -4 +Hailstone B: 12, 31, 28 @ -1, -2, -1 +Hailstones' paths will cross outside the test area (at x=-2, y=3). + +Hailstone A: 20, 25, 34 @ -2, -2, -4 +Hailstone B: 20, 19, 15 @ 1, -5, -3 +Hailstones' paths crossed in the past for hailstone B. + +Hailstone A: 12, 31, 28 @ -1, -2, -1 +Hailstone B: 20, 19, 15 @ 1, -5, -3 +Hailstones' paths crossed in the past for both hailstones. + +``` + +So, in this example, `*2*` hailstones' future paths cross inside the boundaries of the test area. + +However, you'll need to search a much larger test area if you want to see if any hailstones might collide. Look for intersections that happen with an X and Y position each at least `200000000000000` and at most `400000000000000`. Disregard the Z axis entirely. + +Considering only the X and Y axes, check all pairs of hailstones' future paths for intersections. *How many of these intersections occur within the test area?* + +Your puzzle answer was `17906`. + +\--- Part Two --- +---------- + +Upon further analysis, it doesn't seem like *any* hailstones will naturally collide. It's up to you to fix that! + +You find a rock on the ground nearby. While it seems extremely unlikely, if you throw it just right, you should be able to *hit every hailstone in a single throw*! + +You can use the probably-magical winds to reach *any integer position* you like and to propel the rock at *any integer velocity*. Now *including the Z axis* in your calculations, if you throw the rock at time `0`, where do you need to be so that the rock *perfectly collides with every hailstone*? Due to probably-magical inertia, the rock won't slow down or change direction when it collides with a hailstone. + +In the example above, you can achieve this by moving to position `24, 13, 10` and throwing the rock at velocity `-3, 1, 2`. If you do this, you will hit every hailstone as follows: + +``` +Hailstone: 19, 13, 30 @ -2, 1, -2 +Collision time: 5 +Collision position: 9, 18, 20 + +Hailstone: 18, 19, 22 @ -1, -1, -2 +Collision time: 3 +Collision position: 15, 16, 16 + +Hailstone: 20, 25, 34 @ -2, -2, -4 +Collision time: 4 +Collision position: 12, 17, 18 + +Hailstone: 12, 31, 28 @ -1, -2, -1 +Collision time: 6 +Collision position: 6, 19, 22 + +Hailstone: 20, 19, 15 @ 1, -5, -3 +Collision time: 1 +Collision position: 21, 14, 12 + +``` + +Above, each hailstone is identified by its initial position and its velocity. Then, the time and position of that hailstone's collision with your rock are given. + +After 1 nanosecond, the rock has *exactly the same position* as one of the hailstones, obliterating it into ice dust! Another hailstone is smashed to bits two nanoseconds after that. After a total of 6 nanoseconds, all of the hailstones have been destroyed. + +So, at time `0`, the rock needs to be at X position `24`, Y position `13`, and Z position `10`. Adding these three coordinates together produces `*47*`. (Don't add any coordinates from the rock's velocity.) + +Determine the exact position and velocity the rock needs to have at time `0` so that it perfectly collides with every hailstone. *What do you get if you add up the X, Y, and Z coordinates of that initial position?* + +Your puzzle answer was `571093786416929`. + +Both parts of this puzzle are complete! They provide two gold stars: \*\* + +At this point, you should [return to your Advent calendar](/2023) and try another puzzle. + +If you still want to see it, you can [get your puzzle input](24/input). \ No newline at end of file diff --git a/2023/day24_never_tell_me_the_odds/src/lib.rs b/2023/day24_never_tell_me_the_odds/src/lib.rs new file mode 100644 index 0000000..b05c619 --- /dev/null +++ b/2023/day24_never_tell_me_the_odds/src/lib.rs @@ -0,0 +1,248 @@ +use core::fmt::Display; +use std::num::ParseFloatError; + +#[derive(Debug, PartialEq, Eq)] +pub enum ParseError<'a> { + ParseFloatError(std::num::ParseFloatError), + LineMalformed(&'a str), +} + +impl From for ParseError<'_> { + fn from(value: ParseFloatError) -> Self { + Self::ParseFloatError(value) + } +} + +impl Display for ParseError<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::LineMalformed(v) => write!(f, "Line is malformed: {v}"), + Self::ParseFloatError(e) => write!(f, "Unable to parse into a float: {e}"), + } + } +} + +#[derive(Debug, PartialEq)] +struct ExtendedMatrix { + left: [[f64; D]; D], + right: [f64; D], +} + +impl ExtendedMatrix { + + /// Solves the given square matrix in place by Gaussian Elimination. Returns Some(()), + /// if the matrix was solvable (i. e. its rows are linearly independent) and None + /// otherwise. If it was solvable, its left part is transformed into reduced echolon form, + /// and its right part represents the solution vector. No columns are swapped, + /// but due to the transformation, the determinant will likely be changed. + fn solve(&mut self) -> Option<()> { + // Gaussian Elimination + let dim = D; + for row in 0..dim { + let (r_max, val) = self.left.iter().enumerate().skip(row).map(|(idx, r)| (idx, r[row])).max_by_key(|(_idx, val)| val.abs() as usize).unwrap(); + if val.is_subnormal() { + // This column is already 0 for all rows. This means, the rows aren't linearly independent, + // so there is no unique solution. + return None; + } else { + if row != r_max { + self.left.swap(row, r_max); + self.right.swap(row, r_max); + } + let pivot = self.left[row]; + self.left.iter_mut().enumerate().skip(row+1).for_each(|(r_idx, r)| { + let factor = r[row]/pivot[row]; + r[row] = 0.0; + r.iter_mut().enumerate().skip(row+1).for_each(|(c_idx, val)| *val -= pivot[c_idx]*factor); + self.right[r_idx] -= self.right[row]*factor; + }); + } + } + for row in (0..dim).rev() { + let was = self.right[row]; + let sub: f64 = self.left[row].iter().enumerate().skip(row+1).map(|(col, val)| val*self.right[col]).sum(); + self.right[row] = (was-sub)/self.left[row][row]; + self.left[row].fill(0.0); + self.left[row][row] = 1.0; + } + Some(()) + } +} + +#[derive(Clone, Copy, Debug)] +struct Path { + px: f64, + py: f64, + pz: f64, + vx: f64, + vy: f64, + vz: f64, +} + +impl<'a> TryFrom<&'a str> for Path { + type Error = ParseError<'a>; + + fn try_from(value: &'a str) -> Result { + let components: Vec<_> = value.split_whitespace().map(|c| c.split_once([',', '@']).unwrap_or((c, "")).0).collect(); + if components.len() != 7 { + return Err(Self::Error::LineMalformed(value)); + } + let px = components[0].parse::()?; + let py = components[1].parse::()?; + let pz = components[2].parse::()?; + let vx = components[4].parse::()?; + let vy = components[5].parse::()?; + let vz = components[6].parse::()?; + + Ok(Path{ px, py, pz, vx, vy, vz, }) + } +} + +impl Path { + fn m_y(&self) -> f64 { + self.vy/self.vx + } + + fn n_y(&self) -> f64 { + self.py - self.px * self.vy / self.vx + } + + fn at(&self, t: f64) -> (f64, f64, f64) { + (self.px+t*self.vx, self.py+t*self.vy, self.pz+t*self.vz) + } + + fn horizontal_intersection(&self, other: &Self) -> (f64, f64, bool) { + let x = (other.n_y() - self.n_y()) / (self.m_y() - other.m_y()); + let y = self.m_y() * x + self.n_y(); + let future = match (self.vx > 0.0, other.vx > 0.0) { + (true, true) => x > self.px && x > other.px, + (true, false) => x > self.px && x <= other.px, + (false, true) => x <= self.px && x > other.px, + (false, false) => x <= self.px && x <= other.px, + }; + (x, y, future) + } + +} + +pub fn run(input: &str, min: f64, max: f64) -> Result<(usize, usize), ParseError> { + let paths: Vec<_> = input.lines().map(Path::try_from).collect::, _>>()?; + let intersections: Vec<_> = paths.iter().enumerate().flat_map(|(idx, p1)| paths.iter().skip(idx+1).map(|p2| p1.horizontal_intersection(p2)).collect::>()).collect(); + let first = intersections.iter().filter(|&(x, y, future)| *future && (min..=max).contains(x) && (min..=max).contains(y)).count(); + let stone_path = find_stone_path(&paths); + let second = (stone_path.px + stone_path.py + stone_path.pz) as usize; + Ok((first, second)) +} + +fn find_stone_path(paths: &[Path]) -> Path { + // Since the rock r must hit any hail j at time t_j, we know that their x coordinates must be equal: + // p_xj+v_xj*t_j = p_xr+v_xr*t_j + //// p_xj-p_xr = t_j(v_xr-v_xj) + // (p_xj-p_xr)/(v_xr-v_xj) = t_j + // + // Since the same holds true on the y axis, we can equate: + // p_yj+v_yj(p_xj-p_xr)/(v_xr-v_xj) = p_yr+v_yr(p_xj-p_xr)/(v_xr-v_xj) + // (v_xr-v_xj)p_yj + (p_xj-p_xr)v_yj - (v_xr-v_xj)p_yr - (p_xj-p_xr)v_yr = 0 + // + // Now, this must be true for any hail k as well (since the equation no longer depends on t_j), so: + // 0 = (v_xr-v_xk)p_yk + (p_xk-p_xr)v_yk - (v_xr-v_xk)p_yr - (p_xk-p_xr)v_yr + // (v_xr-v_xj)p_yj + (p_xj-p_xr)v_yj - (v_xr-v_xj)p_yr - (p_xj-p_xr)v_yr = (v_xr-v_xk)p_yk + (p_xk-p_xr)v_yk - (v_xr-v_xk)p_yr - (p_xk-p_xr)v_yr + // + // Wich simplifies as + //// v_yr(p_xk-p_xj) + p_yr(v_xj-v_xk) + v_xr(p_yj-p_yk) + p_xr(v_yk-v_yj) = p_xk*v_yk + p_yj*v_xj - p_yk*v_xk - p_xj*v_yj + // v_xr(p_yj-p_yk) + v_yr(p_xk-p_xj) + p_xr(v_yk-v_yj) + p_yr(v_xj-v_xk) = p_xk*v_yk + p_yj*v_xj - p_yk*v_xk - p_xj*v_yj + // + // Now we have a linear equation with four unknowns (v_xr, v_yr, p_xr, and p_yr), which only depends on the + // parameters of j and k. So we can pick any 4 (linearly independent) combination of 2 hails and solve. + + let (p_x0, p_y0, v_x0, v_y0) = { + let hail = paths[0]; + (hail.px, hail.py, hail.vx, hail.vy) + }; + let (p_x1, p_y1, v_x1, v_y1) = { + let hail = paths[1]; + (hail.px, hail.py, hail.vx, hail.vy) + }; + let (p_x4, p_y4, v_x4, v_y4) = { + let hail = paths[2]; + (hail.px, hail.py, hail.vx, hail.vy) + }; + let (p_x2, p_y2, v_x2, v_y2) = { + let hail = paths[3]; + (hail.px, hail.py, hail.vx, hail.vy) + }; + let (p_x3, p_y3, v_x3, v_y3) = { + let hail = paths[4]; + (hail.px, hail.py, hail.vx, hail.vy) + }; + + let mut matrix = ExtendedMatrix{ + left: [ + [p_y0-p_y1, p_x1-p_x0, v_y1-v_y0, v_x0-v_x1], + [p_y0-p_y2, p_x2-p_x0, v_y2-v_y0, v_x0-v_x2], + [p_y0-p_y3, p_x3-p_x0, v_y3-v_y0, v_x0-v_x3], + [p_y0-p_y4, p_x4-p_x0, v_y4-v_y0, v_x0-v_x4], + ], + right: [ + p_x1*v_y1 + p_y0*v_x0 - p_y1*v_x1 - p_x0*v_y0, + p_x2*v_y2 + p_y0*v_x0 - p_y2*v_x2 - p_x0*v_y0, + p_x3*v_y3 + p_y0*v_x0 - p_y3*v_x3 - p_x0*v_y0, + p_x4*v_y4 + p_y0*v_x0 - p_y4*v_x4 - p_x0*v_y0, + ], + }; + if matrix.solve().is_none() { + panic!("Hails aren't linearly independent"); + } + let (v_xr, v_yr, p_xr, p_yr) = (matrix.right[0].round(), matrix.right[1].round(), matrix.right[2].round(), matrix.right[3].round()); + + let t_0 = (p_x0-p_xr)/(v_xr-v_x0); + let t_1 = (p_x1-p_xr)/(v_xr-v_x1); + let z_0 = paths[0].at(t_0).2; + let z_1 = paths[1].at(t_1).2; + + let v_zr = (z_1-z_0)/(t_1-t_0); + let p_zr = z_0 - t_0*v_zr; + + Path{ px: p_xr, py: p_yr, pz: p_zr, vx: v_xr, vy: v_yr, vz: v_zr } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs::read_to_string; + + fn read_file(name: &str) -> String { + read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string() + } + + #[test] + fn matrix_solver() { + let mut m = ExtendedMatrix{ left: [ + [1.0, 3.0, -2.0, 4.0], + [3.0, 5.0, 6.0, 0.0], + [2.0, 4.0, 3.0, 2.0], + [1.0, 2.0, -2.0, 2.0], + ], right: [5.0, 7.0, 8.0, 1.0], }; + let expected = ExtendedMatrix{ left: [ + [1.0, 0.0, 0.0, 0.0], + [0.0, 1.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0], + ], right: [5.0, -4.0, 2.0, 4.0], }; + assert!(m.solve().is_some()); + assert_eq!(m.left, expected.left); + expected.right.iter().enumerate().for_each(|(idx, e)| assert!((e - m.right[idx]).abs() < 0.0001)); + } + + #[test] + fn test_sample() { + let sample_input = read_file("tests/sample_input"); + assert_eq!(run(&sample_input, 7.0, 27.0), Ok((2, 47))); + } + + #[test] + fn test_challenge() { + let challenge_input = read_file("tests/challenge_input"); + assert_eq!(run(&challenge_input, 200_000_000_000_000.0, 400_000_000_000_000.0), Ok((17906, 571093786416929))); + } +} diff --git a/2023/day24_never_tell_me_the_odds/tests/challenge_input b/2023/day24_never_tell_me_the_odds/tests/challenge_input new file mode 100644 index 0000000..c720bfc --- /dev/null +++ b/2023/day24_never_tell_me_the_odds/tests/challenge_input @@ -0,0 +1,300 @@ +194592040768564, 332365743938486, 196880917504399 @ 160, -81, 182 +119269259427296, 151358331038299, 32133087271013 @ 320, 350, 804 +137316267565914, 280950442046082, 163349784223749 @ 252, -89, 298 +156784243533036, 239107035457244, 225936623290041 @ 43, -98, -76 +321769272453694, 324937275314713, 420778403813678 @ 42, -28, -69 +204814986025924, 237908862805026, 274364047444843 @ 52, 43, -34 +333027566352680, 89887889274820, 426837656966891 @ -57, 292, -175 +147291187869291, 176591814445512, 244033006247870 @ 141, 805, -405 +236268629660353, 289057626760187, 260610739172231 @ 63, -38, 66 +164410288824386, 286208852663572, 210705833149481 @ 56, -400, 132 +273161387532794, 273878751925386, 222888807806499 @ -58, -29, 130 +356353709190834, 131308503961606, 496168973459609 @ -57, 212, -234 +346296827868374, 328216483521434, 357918726952129 @ 32, -23, 13 +239213578517828, 179111262937711, 145725447469709 @ 144, 128, 228 +259576781321898, 276543072765882, 243990103643330 @ -50, -45, 75 +263359092904370, 399330848050006, 453386292077045 @ 35, -212, -249 +159016686684041, 58290485987122, 153212541374054 @ 195, 507, 303 +166636658074410, 5217870351550, 256902756939367 @ 180, 605, 47 +224613837886664, 222046446202438, 280338992917109 @ 27, 89, -22 +243512471484168, 380540650808944, 446878830823205 @ -17, -310, -438 +201232882839174, 395199378872156, 341345960569729 @ 138, -210, -64 +148477759743232, 255670686373024, 180670149058146 @ 168, -211, 407 +317413746352115, 127017744115204, 269305412683311 @ 35, 197, 94 +149944965125582, 301448789473072, 185860854881565 @ 230, -16, 194 +133765828474994, 46582475528146, 283604514918089 @ 251, 317, 66 +443984894132948, 435554256713062, 307670535614441 @ -212, -233, 16 +317552070085532, 243455935482874, 270442812731321 @ -55, 51, 60 +178192066418733, 202666031638573, 393001029985771 @ 133, 146, -374 +318106714182566, 240386718498424, 242733891074687 @ -102, 52, 97 +158589521202559, 321631322115311, 55207956904364 @ 183, -236, 663 +140604613634294, 257756663459476, 217953521418859 @ 242, -190, 71 +156238157047268, 215762540573168, 209088305076919 @ 59, 184, 133 +224734796156530, 372297178297748, 313974888121040 @ 118, -135, 9 +177592868881709, 114735442697521, 212972206654244 @ 129, 418, 147 +213089881169878, 173008927872570, 377677334114641 @ -74, 307, -580 +325737613249818, 271711880603062, 317344121446681 @ 19, 26, 34 +228272147885042, 347526968312218, 204090629656565 @ 111, -101, 171 +175898718770910, 220406071348070, 269143801562370 @ -6, 111, -275 +155341724218414, 235475759804958, 220450947333745 @ 12, -90, -56 +341349366286042, 294405408305978, 355973112067945 @ -125, -45, -106 +435925655471414, 173632585604191, 518031133553147 @ -78, 138, -170 +218053166067755, 71840710634341, 137255125394057 @ 143, 278, 256 +164168066315094, 215421575423706, 211723107301009 @ -68, 201, 94 +212387567125088, 264921400824612, 177775757245573 @ -52, -83, 284 +204192294330338, 166501029824802, 255783280932537 @ -37, 337, -50 +229984105434500, 253630277322058, 270890108023619 @ -27, -5, -27 +188648071555718, 240194658723046, 256038193320485 @ 166, 58, 89 +148979137973576, 218263188933886, 291783965071928 @ 160, 143, -671 +167004459104420, 203943950531319, 228615798366620 @ 140, 162, 81 +179345516801094, 185236382554746, 219057873495889 @ -39, 367, 74 +267915762923903, 242993432031898, 373521164370257 @ 23, 51, -120 +258788204520200, 427890445574080, 397010237620691 @ 73, -208, -105 +208349284553122, 207454721940239, 253986757382895 @ 126, 112, 86 +329555432976074, 348715051961494, 403812039003653 @ -103, -144, -193 +556131001350959, 520072787312301, 474274887951104 @ -181, -218, -105 +189655319558899, 261847792376008, 256932651070916 @ 187, 41, 111 +292073313628042, 154688479053354, 427269393723029 @ 16, 187, -162 +305954953780324, 339265862824030, 320102991318636 @ 52, -49, 37 +284754365669054, 181290838182166, 473028854091629 @ -156, 202, -569 +186725953231058, 237798255831796, 429733150692347 @ 70, 33, -666 +286146205193446, 275684917640650, 292005354348177 @ -107, -40, -38 +161887883588998, 239427982572726, 214657859072733 @ 58, -47, 94 +239553976468993, 368423690009212, 247083226298659 @ 73, -163, 98 +150994721274003, 224547131890092, 217347722963201 @ 109, 81, 24 +234333607450270, 206408001321532, 279119708527461 @ 70, 116, 34 +348552551289794, 321433260575846, 261055952350214 @ -178, -113, 57 +201666998248578, 244873841470940, 218851819139723 @ -74, -23, 102 +502432891143082, 435610442530406, 381502346575071 @ -152, -147, -23 +151366968247590, 327875068643946, 271914220940153 @ 190, -417, -150 +408298066577054, 210607215941186, 164747261926409 @ -127, 102, 225 +484431672442499, 246463737889732, 240905466843890 @ -163, 57, 127 +52883757158229, 76114345174920, 42541331360542 @ 397, 345, 457 +416449089098504, 405449300519911, 391697343764534 @ -244, -236, -159 +175350105318010, 316763050487630, 240420049288067 @ 160, -135, 87 +298854963330554, 323064637127614, 228439508952161 @ 72, -23, 144 +221832346492139, 201465989455711, 64869576854624 @ -45, 164, 667 +119220945656986, 62922376371906, 180350601262461 @ 291, 453, 227 +312457113713982, 400805845503962, 276816347304773 @ 16, -149, 75 +275626627690758, 275383246042334, 389958046934257 @ 54, 12, -88 +195158716907378, 228539490679306, 314376769456985 @ -21, 63, -354 +472243086252642, 284872070086666, 393589942404521 @ -87, 23, -18 +399765970959515, 239157918577366, 465259640437910 @ -109, 63, -183 +110999402534782, 137296489574870, 82857985744953 @ 328, 336, 526 +263562453820660, 307770025933662, 486315506885051 @ 9, -75, -363 +142194037062798, 203927063027957, 278615727038184 @ 234, 186, -197 +274964020546493, 339932452476795, 369437169947127 @ -115, -224, -266 +314360979197674, 325644599098966, 371729351005839 @ -36, -79, -97 +228943159959594, 244245481515046, 284365659661489 @ -65, 14, -104 +363435793314360, 330469205745187, 148055430920576 @ -92, -76, 255 +302228359717220, 129037647143146, 444004623217055 @ -97, 283, -331 +337907092264556, 188265083723560, 392285129144063 @ 29, 122, -33 +153611038780589, 269232088745744, 216751164661083 @ 137, -279, 82 +147743200191354, 251468286955346, 206098283112689 @ 126, -357, 168 +212268958457294, 237290471738086, 266296332764009 @ -8, 38, -42 +434697144176079, 270041073515238, 500190813654474 @ -93, 31, -167 +159725595458220, 239273715728775, 234385508800662 @ 48, -68, -119 +219885712798374, 251418537112246, 268712333020684 @ 66, 23, 29 +236806616843034, 228774778423762, 200496647482813 @ -153, 65, 191 +330844475446508, 206054517447082, 189289941908397 @ -7, 107, 190 +173622309101864, 229282400109586, 261127775558639 @ 80, 59, -102 +219181468793084, 156872999311282, 283511036713571 @ 107, 199, 35 +214012796248074, 275390258643730, 191223467162002 @ -138, -181, 245 +154728556272596, 191463384844507, 281312531861237 @ 76, 470, -716 +206879193025518, 237366334430276, 255604595429025 @ -90, 18, -80 +256537961873990, 284215470011584, 194579264537591 @ -70, -78, 199 +216592162082504, 264435121550590, 270265546246733 @ -73, -83, -98 +178498568878649, 219617615101891, 205903455579299 @ -147, 132, 170 +200999110034798, 173269563976606, 304774330381229 @ -12, 298, -247 +206804497214834, 273305248093345, 209408277291716 @ 62, -50, 159 +225362580767540, 152903109310087, 467221313169659 @ 44, 250, -442 +176108476811174, 206300826051250, 173299476177857 @ 32, 190, 362 +348389318168510, 359030199773114, 428123683907817 @ -79, -125, -175 +272759789596990, 168746605054074, 274784196935406 @ 90, 147, 89 +183905492088072, 254884466045846, 212196998387869 @ 100, -17, 148 +262469685158204, 271262071025296, 355461114365071 @ 47, 8, -71 +218514671916736, 382664866338214, 195362645160384 @ -12, -433, 203 +383809554484388, 466135140184604, 114805137147939 @ -91, -248, 293 +208044537569270, 310095793003978, 308663167430465 @ 146, -39, 22 +366979533039998, 266221037821000, 334869523499267 @ -34, 32, 11 +223186938096188, 321929068168246, 213901337392553 @ 115, -67, 156 +87470490102904, 137444142073126, 175183883967153 @ 352, 263, 232 +248212110584339, 395939073213496, 323998671075347 @ -103, -467, -210 +219486311582326, 251361470218354, 246119144571617 @ -30, -10, 30 +236783298769050, 121301161291974, 343743227706741 @ -92, 441, -310 +322186826109518, 350031107392702, 327153091429505 @ 44, -54, 36 +331419514588878, 282746903068678, 288537730612485 @ 36, 20, 79 +317682922119372, 244350583400923, 322273936367350 @ -104, 44, -59 +174605643877940, 239107753506748, 273846604568312 @ 108, 25, -99 +237936295121672, 148134965984953, 339450350662325 @ -12, 282, -180 +375902565070565, 209971516601428, 227071916666897 @ -117, 105, 136 +369191841468281, 266001330670459, 329848815438890 @ -181, 6, -61 +355876424562770, 225430850109214, 402650806134341 @ 35, 82, -21 +171731096097150, 290211712269266, 218401240607889 @ -11, -452, 68 +268465561549904, 229785866375246, 265443026870989 @ 5, 73, 58 +195201526729362, 189623987463181, 189873728749532 @ 30, 218, 231 +407534357819094, 319980595357746, 348581051968089 @ -54, -23, 10 +351927245183504, 316946925968631, 317493158658009 @ -16, -30, 32 +209831696736070, 276820224666144, 203044147093493 @ -30, -123, 180 +442784186678942, 378190806892222, 411390683634053 @ -204, -144, -135 +162803147059574, 250231369985311, 242170899928769 @ 114, -66, -40 +211028895801663, 304576953523881, 361589519977276 @ 141, -32, -55 +199603752116521, 336058786968925, 283835345404722 @ 9, -358, -139 +507504675605472, 372917172962436, 267917330753347 @ -215, -102, 91 +204282928099077, 309418003203847, 222293923785813 @ 69, -148, 124 +407228477106134, 351078626040106, 366735020732369 @ -80, -70, -26 +178285829987366, 228823973946778, 258187023365465 @ 106, 67, -20 +322298441925114, 157606131163050, 37172129242305 @ 57, 151, 340 +192708194919521, 237321705463360, 315249581133566 @ 105, 49, -119 +160394496375896, 233057047471824, 218450791621336 @ -64, -51, -23 +495718520512280, 328073782189066, 232019006242469 @ -169, -37, 138 +342562452644958, 191360401981286, 428818142956225 @ 28, 118, -68 +217519783124059, 372497309059540, 293388056859213 @ 27, -331, -76 +453751601569358, 133277500524998, 165406866601353 @ -112, 186, 214 +133718863989821, 3063222526171, 247412780979527 @ 263, 758, 42 +295483731132839, 409307169350027, 292455124384605 @ 77, -114, 76 +262281968042673, 46476102551812, 405485544538184 @ 123, 257, -27 +267882149806214, 272019904778306, 213702915777049 @ -76, -36, 149 +228441177964039, 318228709947686, 143357880020014 @ 81, -89, 283 +215620039528328, 183166196160612, 337882139413019 @ 131, 144, -27 +230863779167754, 281359661681974, 216882495098505 @ -143, -160, 122 +498559811515694, 422800342209922, 552803460489245 @ -108, -111, -171 +205012084127876, 245790114394198, 206098283112689 @ -65, -19, 168 +436061054260858, 327384508057375, 349665145107287 @ -42, -16, 30 +206521766061731, 199552542378448, 243355804049936 @ 35, 161, 51 +290450430271133, 364442862082155, 394140092225585 @ 89, -60, -24 +175466983449398, 245998295961599, 227524114561555 @ 50, -36, 50 +223336167208334, 466150874002974, 379374925876095 @ 62, -443, -209 +196453907208044, 244198772457436, 225012577202999 @ -133, -50, 41 +139028457329500, 37616367551857, 77641544271978 @ 244, 320, 331 +225394876600626, 236503784379422, 247392242349539 @ -66, 39, 18 +222664230907919, 247002873096456, 320617037885659 @ 17, 21, -146 +277975020706532, 241728902213044, 238773768290066 @ 36, 57, 119 +281195371996334, 112438989492766, 377931432221849 @ -82, 341, -228 +377094235141690, 360688343286804, 369474701024287 @ -20, -68, -13 +444798262357424, 363343544024956, 353312987186105 @ -163, -102, -28 +308376375182204, 273431866122412, 366126732589157 @ 47, 26, -18 +265626794671837, 297380717905737, 245845219280694 @ 69, -18, 113 +200175627321557, 199951499439274, 308438229703628 @ 125, 131, -33 +178082737130366, 185283282543610, 262315468356797 @ 196, 131, 99 +400391641164904, 373129058282031, 558762538102429 @ -144, -138, -356 +169363531913114, 228225412107122, 235815832000803 @ 212, 79, 137 +218512520117536, 256887235689694, 288172387803591 @ 55, 5, -29 +163043361100763, 235683592643267, 219444204808432 @ 89, 6, 77 +219259584293234, 262323783321066, 299535925562139 @ -40, -53, -167 +306929801496016, 126940449204708, 313073954600845 @ 15, 216, 22 +472719759257630, 559402388307439, 393395778028175 @ -102, -264, -26 +141278788412130, 268886425007122, 168344495553873 @ 240, -49, 280 +246957199050706, 282832161854212, 423015437526361 @ 40, -28, -244 +372348027627984, 228347484543009, 292578142481066 @ -168, 76, 15 +271032616039160, 250288146465136, 294148956216335 @ -35, 28, -19 +206536773329094, 221423942483680, 259503332465477 @ 42, 92, 6 +295028712387190, 455671221903546, 522774430324849 @ 25, -242, -277 +371539695623214, 233376690525546, 414568862962609 @ -15, 73, -64 +257255425687670, 145282867702714, 130342295974577 @ -106, 319, 394 +188117938624139, 25835205238699, 271616657572370 @ 147, 480, 37 +193624435284158, 283876543228330, 252005689663181 @ 160, -9, 97 +161560944228851, 224188413045844, 223814987721614 @ 35, 85, -7 +302065658815894, 278883992418736, 370586722891444 @ 82, 29, 5 +195982335687151, 316374224605200, 254905766955885 @ 183, -15, 116 +249772012962944, 150492957816706, 230954860190597 @ -83, 303, 94 +335214669324500, 320423956366747, 340926164832701 @ -64, -68, -44 +213642106361294, 255650936557102, 264236127323381 @ -8, -24, -31 +405690793518014, 266683841446266, 161539637491209 @ -109, 27, 227 +159862419005406, 273410757887322, 291664213795698 @ 154, -141, -223 +169318892280910, 246733179515768, 242233105679217 @ -114, -194, -280 +248881260889431, 261682544615824, 198247408387241 @ -89, -31, 192 +139080613222519, 275597303505586, 278945502795534 @ 247, -85, -71 +178673998509764, 187515838437628, 205650407996507 @ -13, 330, 171 +226748056297526, 213056226161626, 219133146147257 @ 90, 103, 145 +234838879769347, 305385630810818, 178840437536434 @ 121, -21, 203 +300258700656269, 186378011807571, 220718620752064 @ -31, 148, 143 +194484281587548, 304080048915493, 333073444652875 @ -44, -340, -506 +281712517826078, 408444677746186, 1594074139089 @ 104, -97, 368 +222094380157809, 28937991015801, 218352383341789 @ 109, 402, 148 +173569941925637, 230067038912164, 261331581508118 @ 91, 57, -85 +282367432093634, 345071032563538, 345680135134193 @ 47, -83, -24 +296984669832342, 173060031528602, 130295736787681 @ -20, 169, 295 +213772319300302, 205795782152618, 218225527145729 @ 61, 129, 138 +214518217373654, 523916969585162, 459516353076209 @ 32, -768, -552 +169626678227318, 251145605466640, 120392498611415 @ 178, 24, 357 +159105649717772, 53612095053226, 70898404041119 @ 216, 323, 358 +310718414188730, 387869045521904, 264612604579995 @ -40, -188, 71 +240976147908646, 250759682572530, 279675721373125 @ 6, 21, -5 +427428033764534, 370192794902818, 436353750939465 @ -118, -100, -121 +377693614107294, 276550469774006, 326539495352973 @ -8, 28, 41 +358582143848664, 260619842060146, 210928810098049 @ -119, 23, 160 +406791084116324, 348897464572831, 303986210967371 @ -68, -62, 54 +173963299115474, 299565392162746, 251202984608369 @ 100, -237, -24 +223399866315646, 2183042400141, 97125119657086 @ 106, 448, 347 +359271662860566, 292253077360858, 392719299262697 @ 10, 11, -30 +267669940597046, 283366357880506, 291880782328049 @ 5, -27, 8 +326191722102064, 147735344868041, 419926908086424 @ 12, 178, -97 +166001862990318, 225611911273601, 241996318260146 @ 138, 78, 21 +156164785431974, 81107641032976, 222306795401939 @ 194, 525, 118 +180683816800164, 676064725908, 298280450394190 @ 132, 697, -85 +275735350005598, 339692659291113, 417607261780817 @ 58, -74, -120 +380487003018750, 263272925311932, 460479058668733 @ -122, 24, -218 +291734183726102, 126500145405934, 454546136975737 @ -22, 254, -266 +215554350773350, 243128323954710, 303388807283579 @ 34, 31, -102 +350448625268694, 150743712509796, 328171001419239 @ 34, 156, 47 +371841779372008, 337514107440914, 416540739701328 @ -36, -53, -85 +291204423769319, 260534844102352, 345988773415890 @ 17, 29, -41 +351469411647026, 285430699621000, 415113389914783 @ 14, 17, -58 +375012087346342, 254013812172018, 429558155030493 @ -122, 37, -179 +137700308943780, 109135850899022, 273508723560935 @ 261, 837, -273 +410272967211110, 74786891395882, 459567477640721 @ -41, 240, -98 +328086813170468, 415604078251616, 336682899705049 @ 41, -122, 28 +159397975646478, 309870374951170, 323708355059905 @ 211, -58, -26 +239964978616429, 281614136518296, 272165122655784 @ 51, -27, 41 +320083245136628, 314581156756546, 373852179893765 @ 43, -17, -18 +411284172830258, 510829190325949, 302504701456457 @ -50, -226, 64 +152837256446432, 270209648273305, 210605046254003 @ 128, -344, 126 +169420934543066, 313099955996950, 121626911036975 @ 140, -231, 467 +340532893550022, 149927805823782, 420307154450969 @ 46, 156, -42 +142391764095074, 238271091582004, 178814452744781 @ 212, -150, 626 +431148082462375, 143308991392342, 395289379093765 @ -59, 167, -28 +278481005739319, 434750870767327, 357368381879345 @ 67, -184, -24 +381675542318011, 490235905886377, 342355764542616 @ -11, -196, 25 +248519060194697, 488181759039820, 252347331638576 @ 53, -379, 87 +217583166410940, 256606583563256, 252217592265217 @ 15, -12, 32 +188682945393724, 299046684327446, 224911543366379 @ -80, -417, 42 +158731284200912, 234189089976226, 189522994261232 @ 20, -37, 371 +301655814994600, 146081589925944, 351635377919938 @ 24, 189, -29 +369244669469563, 391513441693035, 408080753962680 @ 19, -80, -29 +245106546719894, 387413905283482, 293879906904593 @ -208, -619, -210 +153128620640586, 230110514916914, 229174012557353 @ 115, 25, -66 +392341575910408, 327546261429707, 379285742122196 @ -24, -26, -15 +167352915766076, 243244993751374, 165094438870559 @ -107, -163, 703 +165886258110438, 224925008919442, 209570058234413 @ -42, 77, 129 +148185538074197, 251147093575486, 217692638138423 @ 225, 23, 142 +314283277623761, 336273774337318, 34371064786025 @ -25, -89, 432 +335779971093354, 212857800365547, 466923533535251 @ 22, 96, -126 +232810119512864, 222927310211556, 291864039374343 @ -73, 88, -125 +285402689900654, 164566421317792, 232390565382107 @ -138, 240, 99 +403966864035488, 286200397417165, 369132057170571 @ -52, 14, -14 +386086444392605, 332859605586409, 411617955375461 @ -59, -50, -84 +397163203044614, 336833234411506, 371594410232309 @ -82, -59, -41 +182759090922574, 266021708855266, 165776609184769 @ 81, -76, 322 +329733444702712, 313243360641686, 452346559805797 @ -56, -57, -220 +193402760735474, 240365713664662, 248878320251081 @ 47, 24, 10 +218944749852526, 37333829720290, 398751067077933 @ 144, 317, -73 +381454787342189, 333009595459781, 384610764802070 @ -13, -32, -21 +289281102281198, 329015085384434, 315540698366660 @ 26, -69, 9 +139118085765086, 235415971366572, 216132346229843 @ 266, -95, 6 +333623065418684, 381665183716486, 225161833906209 @ -163, -247, 128 +216282915873248, 249616990416264, 232129472180698 @ -40, -11, 71 +302851132686828, 46443094580070, 503674848010885 @ 25, 321, -230 +370489964387066, 275579935384126, 351289030956545 @ -5, 28, 12 +282973154291994, 254491666837574, 221962206214547 @ -108, 9, 129 +412266502846601, 143565864780334, 328084200307196 @ -121, 191, 5 +182065902232958, 246168536206618, 258448394979689 @ 44, -21, -82 +140479173011833, 255876485907657, 254894685250018 @ 243, -168, -221 +260489864338082, 276689824540726, 313109949848285 @ -56, -47, -98 +234260539336934, 318325553246701, 220871390440784 @ -94, -254, 115 +257077177409169, 190447456798411, 121572479687494 @ 67, 134, 295 +294490689959642, 240310138944982, 293211952756636 @ -106, 47, -29 +354957840511370, 495734855438943, 418750293903439 @ -10, -236, -82 +417745975923774, 293484304091146, 309738404744489 @ -119, -7, 33 +178036993404394, 290432302550051, 351282441792434 @ 102, -164, -375 +272561138243744, 176786320665271, 300472253244764 @ 84, 140, 55 diff --git a/2023/day24_never_tell_me_the_odds/tests/sample_input b/2023/day24_never_tell_me_the_odds/tests/sample_input new file mode 100644 index 0000000..35963dc --- /dev/null +++ b/2023/day24_never_tell_me_the_odds/tests/sample_input @@ -0,0 +1,5 @@ +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