diff --git a/example.txt b/example.txt index f756727..28f5ae9 100644 --- a/example.txt +++ b/example.txt @@ -1,33 +1,2 @@ -seeds: 79 14 55 13 - -seed-to-soil map: -50 98 2 -52 50 48 - -soil-to-fertilizer map: -0 15 37 -37 52 2 -39 0 15 - -fertilizer-to-water map: -49 53 8 -0 11 42 -42 0 7 -57 7 4 - -water-to-light map: -88 18 7 -18 25 70 - -light-to-temperature map: -45 77 23 -81 45 19 -68 64 13 - -temperature-to-humidity map: -0 69 1 -1 0 69 - -humidity-to-location map: -60 56 37 -56 93 4 +Time: 7 15 30 +Distance: 9 40 200 diff --git a/input.txt b/input.txt index c152f30..be69c19 100644 --- a/input.txt +++ b/input.txt @@ -1,172 +1,2 @@ -seeds: 5844012 110899473 1132285750 58870036 986162929 109080640 3089574276 100113624 2693179996 275745330 2090752257 201704169 502075018 396653347 1540050181 277513792 1921754120 26668991 3836386950 66795009 - -seed-to-soil map: -3547471595 1239929038 174680800 -3052451552 758183681 481745357 -0 1427884524 1775655006 -2844087171 549819300 208364381 -3767989253 4004864866 5194940 -3534196909 1414609838 13274686 -1775655006 114264781 435554519 -4148908402 4010059806 146058894 -2729822390 0 114264781 -3773184193 4156118700 138848596 -2211209525 3203539530 518612865 -3912032789 3767989253 236875613 - -soil-to-fertilizer map: -912405184 1056091028 152837752 -194471272 1208928780 200072008 -136115250 240819204 58356022 -3502815281 3536983174 299994001 -2321814552 2458149869 18748048 -3173949445 2623931701 9591555 -394543280 888648379 167442649 -1990258415 3891640206 212931291 -1068754270 54862533 153774684 -1222528954 660792432 186471834 -3340878967 3405750148 131233026 -3472111993 3836977175 30703288 -561985929 299175226 225501956 -2942828492 4104571497 88527954 -874532405 850775600 37872779 -3031356446 3867680463 23959743 -842350418 208637217 32181987 -0 524677182 136115250 -1065242936 847264266 3511334 -2203189706 2339525023 118624846 -1929736108 2563409394 60522307 -3802809282 1847367009 492158014 -1847367009 2790861223 82369099 -2442430445 2873230322 500398047 -3183541000 2633523256 157337967 -3141827666 3373628369 32121779 -787487885 0 54862533 -3055316189 2476897917 86511477 -2340562600 4193099451 101867845 - -fertilizer-to-water map: -798315344 439687669 1930292 -1174979421 2966258900 475289790 -439687669 778614573 55925503 -3743699694 3453541232 155280637 -2989334775 1659556189 96021468 -1650269211 3441548690 11992542 -3898980331 3608821869 395986965 -1705125292 2123762646 842496254 -3375514705 1755577657 368184989 -646363825 441617961 94777173 -1662261753 1616692650 42863539 -495613172 627863920 150750653 -2777061135 1174979421 212273640 -741140998 834540076 57174346 -800245636 536395134 91468786 -2547621546 1387253061 229439589 -3085356243 4004808834 290158462 - -water-to-light map: -541719462 212840988 165903288 -3437755571 1615831015 672632835 -1051033542 2678450187 510773217 -243353905 378744276 104057369 -1561806759 3801474127 134575711 -707622750 677109833 258560892 -2580483557 1051033542 195631857 -0 935670725 30512917 -347411274 482801645 194308188 -30512917 0 127836567 -2190497220 2288463850 389986337 -3068589955 1246665399 369165616 -1754579039 3936049838 66442917 -4110388406 3616895237 184578890 -158349484 127836567 85004421 -2776115414 4002492755 292474541 -1821021956 3247419973 369475264 -1696382470 3189223404 58196569 - -light-to-temperature map: -338228166 2812162941 77503977 -3123877206 693964345 40932068 -3939438903 614787731 633466 -3301169239 2299402886 215156012 -3516325251 499164007 115623724 -3852145506 3365439095 87293397 -875755064 3565078024 729889272 -2849390436 734896413 11914872 -2861305308 215265512 77518872 -4220385528 2056242491 68417151 -2221674563 3167682469 34693717 -2765973467 292784384 83416969 -3198884011 1699097031 22283517 -3164809274 2889666918 34074737 -809366712 746811285 52314986 -4096970661 1633036395 58945085 -3221167528 2699611924 80001711 -697021180 3452732492 112345532 -2059345064 799126271 162329499 -4155915746 629494563 64469782 -2431111524 1721380548 334861943 -684283267 2779613635 12737913 -440342453 2923741655 243940814 -3634265609 961455770 217879897 -4288802679 3202376186 6164617 -415732143 1691981480 4798917 -1605644336 1179335667 453700728 -420531060 2792351548 19811393 -3631948975 1696780397 2316634 -2938824180 2514558898 185053026 -215265512 376201353 122962654 -2256368280 2124659642 174743244 -3940072369 3208540803 156898292 -861681698 615421197 14073366 - -temperature-to-humidity map: -841576398 2731200418 60836938 -1860695540 395011682 292982985 -1518037021 3432774193 53954373 -1786573987 2461900019 55353430 -2940303448 1995108352 6974538 -3014069287 1664464874 53916789 -753139746 2190061656 88436652 -2351822957 2925825589 209990361 -3079884326 3498626816 37609115 -4067060121 4186346579 108620717 -4175680838 4102322798 3778367 -1571991394 2415899186 46000833 -2841627583 1157034722 22534242 -1841927417 2517253449 18768123 -2153678525 47765849 108568164 -3251281674 1179568964 226737882 -3067986076 3486728566 11898250 -1308101633 1785172964 209935388 -2262246689 1406306846 89576268 -902413336 2278498308 137400878 -1039814214 3765380846 268287419 -45422022 156334013 238677669 -3617672799 2612163195 119037223 -2947277986 1718381663 66791301 -1617992227 1495883114 168581760 -284099691 687994667 469040055 -4214721882 4106101165 80245414 -2839283756 45422022 2343827 -3117493441 2792037356 133788233 -2864161825 2536021572 76141623 -4179459205 4067060121 35262677 -3736710022 3135815950 296958243 -3478019556 2002082890 139653243 -2610138841 3536235931 229144915 -2561813318 2141736133 48325523 - -humidity-to-location map: -608325534 0 231346900 -222429954 453776854 385895580 -3710263359 3540956206 563631409 -1193511298 1116937854 38719102 -1702450793 1176729484 153572024 -1694669826 1109156887 7780967 -0 231346900 222429954 -1856022817 1686715664 1854240542 -1588644556 4104587615 106025270 -1109156887 4210612885 84354411 -4273894768 1155656956 21072528 -1232230400 1330301508 356414156 +Time: 44 82 69 81 +Distance: 202 1076 1138 1458 diff --git a/src/main.rs b/src/main.rs index fed0cd1..7e5409f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,242 +1,76 @@ -use std::cmp::{max, min}; -use std::{collections::HashMap, io::stdin}; +use std::io::stdin; -use anyhow::Result; +use anyhow::{bail, Result}; use regex::Regex; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct Range { - start: i64, - len: i64, +/// solve ax² + bx + c = 0 +fn solve_quadratic(a: f64, b: f64, c: f64) -> (f64, f64) { + let r1 = (-b + f64::sqrt(b * b - 4.0 * a * c)) / 2.0 * a; + let r2 = (-b - f64::sqrt(b * b - 4.0 * a * c)) / 2.0 * a; + (r1, r2) } -impl Range { - fn intersection(&self, other: &Range) -> Option { - let i1 = max(self.start, other.start); - let i2 = min(self.start + self.len, other.start + other.len); - - if i1 >= i2 { - return None; - } - - Some(Range { - start: i1, - len: i2 - i1, - }) - } -} - -#[derive(Debug, Clone, Copy)] -struct RangeMap { - from: i64, - to: i64, - len: i64, -} - -#[derive(Debug)] -struct SeedsMap { - range_maps: Vec, -} - -impl SeedsMap { - fn new() -> SeedsMap { - SeedsMap { range_maps: vec![] } - } - - fn add_range(&mut self, range: (i64, i64, i64)) { - self.range_maps.push(RangeMap { - from: range.1, - to: range.0, - len: range.2, - }); - self.range_maps.sort_by_key(|r| r.from); - } - - fn map(&self, ranges: &[Range]) -> Vec { - let mut result = vec![]; - for r in ranges { - result.extend(self.map_single_range(r)); - } - result - } - - fn map_single_range(&self, range: &Range) -> Vec { - if self.range_maps.is_empty() { - return vec![*range]; - } - - let mut result = vec![]; - let first = self.range_maps.first().unwrap(); - let last = self.range_maps.last().unwrap(); - let left = min(range.start, first.from); - let right = max(range.start + range.len, last.from + last.len); - - let mut last = left; - for rm in &self.range_maps { - // first, a range from last to rm.start, with no mapping - let r = Range { - start: last, - len: rm.from - last, - }; - if let Some(i) = r.intersection(range) { - result.push(i); - } - // second, a range from rm.start, with mapping - let r = Range { - start: rm.from, - len: rm.len, - }; - if let Some(i) = r.intersection(range) { - result.push(Range { - start: rm.to + i.start - rm.from, - len: i.len, - }); - last = i.start + i.len; - } - } - - let r = Range { - start: last, - len: right - last, - }; - if let Some(i) = r.intersection(range) { - result.push(i); - } - - result - } -} - -fn parse_input(seed_ranges: &mut Vec, maps: &mut HashMap) -> Result<()> { +fn parse_input() -> Result<(Vec, Vec)> { let numbers = Regex::new(r"(\d+)")?; - let pairs = Regex::new(r"(\d+) (\d+)")?; - let mut current_map = String::new(); + let mut times = vec![]; + let mut distances = vec![]; for line in stdin().lines().map_while(Result::ok) { - if line.starts_with("seeds:") { - *seed_ranges = pairs - .captures_iter(&line) - .map(|c| -> Result { - Ok(Range { - start: c.get(1).unwrap().as_str().parse()?, - len: c.get(2).unwrap().as_str().parse()?, - }) - }) - .map_while(Result::ok) - .collect(); - } else if line.ends_with(" map:") { - current_map = line - .split_whitespace() - .next() - .unwrap_or_default() - .to_owned(); - } else { - let nums: Vec = numbers + if line.starts_with("Time:") { + times = numbers .captures_iter(&line) .map(|c| c.get(1).unwrap().as_str().parse()) .map_while(Result::ok) .collect(); - if nums.len() == 3 { - let map = maps - .entry(current_map.clone()) - .or_insert_with(SeedsMap::new); - map.add_range((nums[0], nums[1], nums[2])); - } + } else if line.starts_with("Distance:") { + distances = numbers + .captures_iter(&line) + .map(|c| c.get(1).unwrap().as_str().parse()) + .map_while(Result::ok) + .collect(); + } else { + bail!("unexpected line: {}", line); } } - Ok(()) + Ok((times, distances)) } fn main() -> Result<()> { - let mut maps: HashMap = HashMap::new(); - let mut seed_ranges: Vec = vec![]; + let (times, distances) = parse_input()?; - parse_input(&mut seed_ranges, &mut maps)?; - - let map_names = [ - "seed-to-soil", - "soil-to-fertilizer", - "fertilizer-to-water", - "water-to-light", - "light-to-temperature", - "temperature-to-humidity", - "humidity-to-location", - ]; - - let mut locations = vec![]; - for range in seed_ranges { - let mut mapped_ranges = vec![range]; - for map_name in map_names { - let mapped = maps.get(map_name).unwrap().map(&mapped_ranges); - mapped_ranges = mapped; - } - locations.extend(mapped_ranges.iter().map(|r| r.start)); + if times.len() != distances.len() { + bail!( + "times has {} elements, but distances has {} elements", + times.len(), + distances.len() + ); } - println!("{}", locations.iter().min().unwrap()); + + let mut prod = 1; + for i in 0..times.len() { + let t = times[i]; + let d = distances[i]; + + // the equation to solve is x * (t - x) - d = 0 + // = t*x - x*x - d = 0 + // = -1x² + tx - d = 0 + let (r1, r2) = solve_quadratic(-1.0, t as f64, -d as f64); + let r1 = (r1 + 1.0).floor() as i64; + let r2 = (r2 - 1.0).ceil() as i64; + + let ways = (r2 - r1) + 1; + + println!("{t} {d}"); + println!("ways: {ways}"); + prod *= ways; + } + + println!("{prod}"); Ok(()) } #[cfg(test)] mod tests { - use super::*; #[test] - fn test_intersections() { - let l = |r1: &Range, r2: &Range| r1.intersection(r2); - assert_eq!( - l(&Range { start: 1, len: 3 }, &Range { start: 1, len: 3 }), - Some(Range { start: 1, len: 3 }) - ); - assert_eq!( - l(&Range { start: 1, len: 2 }, &Range { start: 1, len: 3 }), - Some(Range { start: 1, len: 2 }) - ); - assert_eq!( - l(&Range { start: 2, len: 4 }, &Range { start: 0, len: 3 }), - Some(Range { start: 2, len: 1 }) - ); - assert_eq!( - l(&Range { start: 0, len: 3 }, &Range { start: 2, len: 4 }), - Some(Range { start: 2, len: 1 }) - ); - assert_eq!( - l(&Range { start: 3, len: 4 }, &Range { start: 0, len: 3 }), - None - ); - assert_eq!( - l(&Range { start: 0, len: 10 }, &Range { start: 4, len: 4 }), - Some(Range { start: 4, len: 4 }) - ); - } - - #[test] - fn test_range_map() { - let mut m = SeedsMap::new(); - m.add_range((52, 50, 48)); - m.add_range((50, 98, 2)); - let r = m.map_single_range(&Range { start: 79, len: 14 }); - assert_eq!(r, [Range { start: 81, len: 14 }]); - - let mut m = SeedsMap::new(); - m.add_range((39, 0, 15)); - m.add_range((0, 15, 37)); - m.add_range((37, 52, 2)); - let r = m.map_single_range(&Range { start: 81, len: 14 }); - assert_eq!(r, [Range { start: 81, len: 14 }]); - - let mut m = SeedsMap::new(); - m.add_range((88, 18, 7)); - m.add_range((18, 25, 70)); - let r = m.map_single_range(&Range { start: 81, len: 14 }); - assert_eq!(r, [Range { start: 74, len: 14 }]); - - let mut m = SeedsMap::new(); - m.add_range((81, 45, 19)); - m.add_range((68, 64, 13)); - m.add_range((45, 77, 23)); - let r = m.map_single_range(&Range { start: 74, len: 14 }); - assert_eq!( - r, - [Range { start: 78, len: 3 }, Range { start: 45, len: 11 }] - ); - } + fn test() {} }