From f165c8fa6609c09ffcdd1a3af07632dee91cc7e8 Mon Sep 17 00:00:00 2001 From: Lennard Brinkhaus Date: Tue, 5 Dec 2023 11:54:39 +0100 Subject: [PATCH] feat: implement day05 --- Cargo.lock | 97 +++++++++++++++ Cargo.toml | 4 +- src/day04.rs | 9 +- src/day05.rs | 255 ++++++++++++++++++++++++++++++++++++++ src/input/day05/input.txt | 206 ++++++++++++++++++++++++++++++ src/main.rs | 5 + 6 files changed, 573 insertions(+), 3 deletions(-) create mode 100644 src/day05.rs create mode 100644 src/input/day05/input.txt diff --git a/Cargo.lock b/Cargo.lock index bca4202..e69521e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,4 +13,101 @@ name = "aoc-2023" version = "0.1.0" dependencies = [ "anyhow", + "itertools", + "rayon", ] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" diff --git a/Cargo.toml b/Cargo.toml index 0b9b42b..b459734 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0" \ No newline at end of file +anyhow = "1.0" +rayon = "1.8.0" +itertools = { version = "0.12.0", features = [] } \ No newline at end of file diff --git a/src/day04.rs b/src/day04.rs index 5ef4e64..756a7c3 100644 --- a/src/day04.rs +++ b/src/day04.rs @@ -1,17 +1,22 @@ use std::collections::HashMap; +use std::time::Instant; pub fn execute_task01(content: &str) { + let start = Instant::now(); let sum_of_numbers = solve_01(content).unwrap(); + let duration = start.elapsed(); assert_eq!(25231, sum_of_numbers); - println!("Day04 - Task01 - Sum of correct Numbers: {}", sum_of_numbers) + println!("Day04 - Task01 - Duration {duration:?}- Sum of correct Numbers: {}", sum_of_numbers) } pub fn execute_task02(content: &str) { + let start = Instant::now(); let sum_of_numbers = solve_02(content).unwrap(); + let duration = start.elapsed(); assert_eq!(9721255, sum_of_numbers); - println!("Day04 - Task02 - Sum of correct Numbers: {}", sum_of_numbers) + println!("Day04 - Task02 - Duration {duration:?} - Sum of correct Numbers: {}", sum_of_numbers) } pub fn solve_01(data: &str) -> anyhow::Result { diff --git a/src/day05.rs b/src/day05.rs new file mode 100644 index 0000000..b152943 --- /dev/null +++ b/src/day05.rs @@ -0,0 +1,255 @@ +use std::collections::{HashMap}; +use std::time::Instant; +use itertools::Itertools; +use rayon::prelude::*; + +#[derive(Clone)] +struct MapLine { + dest_range_start: u64, + source_range_start: u64, + range_length: u64, +} + +impl From for MapLine { + fn from(value: String) -> Self { + let mut numbers = value + .split(" ") + .map(|number| number.parse::().unwrap()); + + MapLine{ + dest_range_start: numbers.next().unwrap(), + source_range_start: numbers.next().unwrap(), + range_length: numbers.next().unwrap(), + } + } +} + +impl MapLine { + fn is_in_range(&self, number: u64) -> bool { + return self.source_range_start <= number && self.source_range_start + self.range_length > number + } + + fn convert(&self, number: u64) -> u64 { + let diff = number - self.source_range_start; + return self.dest_range_start + diff; + } + + fn source_start(&self) -> u64 { + self.source_range_start + } + + fn source_end(&self) -> u64 { + self.source_range_start + self.range_length + } +} + +#[derive(Clone)] +struct ConvertMap { + from: String, + to: String, + + lines: Vec +} + +impl ConvertMap { + fn new(key: String, data: Vec<&str>) -> Self { + let convert_title = key.split_once("-to-").unwrap(); + + ConvertMap{ + from: convert_title.0.to_owned(), + to: convert_title.1.to_owned(), + lines: data.iter().map(|line| MapLine::from(line.to_string())).collect() + } + } + + fn map(&self, data: u64) -> u64 { + + self.lines + .iter() + .filter(|convert| convert.is_in_range(data)) + .map(|convert| convert.convert(data)) + .next().unwrap_or(data) + } + + fn from(&self) -> &str { + &self.from + } + + fn to(&self) -> &str { + &self.to + } +} + + +pub fn execute_task01(content: &str) { + let start = Instant::now(); + let lowest_location = solve_01(content).unwrap(); + let duration = start.elapsed(); + + assert_eq!(322500873, lowest_location); + println!("Day05 - Task01 - Duration: {:?} - Lowest Location: {}", duration, lowest_location) +} + +pub fn execute_task02(content: &str) { + let start = Instant::now(); + let lowest_range_location = solve_02(content).unwrap(); + let duration = start.elapsed(); + + assert_eq!(108956227, lowest_range_location); + println!("Day05 - Task02 - Duration: {:?} - Lowest Seed Range Location: {}", duration, lowest_range_location) +} + +pub fn solve_01(data: &str) -> anyhow::Result { + let (seeds, convert_maps) = convert_input_to_convert_maps(data); + + Ok(seeds.iter() + .map(|seed| convert_maps + .iter() + .fold(seed.clone(), |acc, map| map.map(acc))) + .min().unwrap()) +} + +pub fn solve_02(data: &str) -> anyhow::Result { + let (seeds, convert_maps) = convert_input_to_convert_maps(data); + + Ok(seeds + .chunks(2) + .into_iter() + .map(|chunk| chunk.iter().collect_tuple().unwrap()) + .map(|(start, range)| *start..start+range) + .par_bridge() + .flat_map(|seed_range| { + seed_range.clone().into_par_iter() + .map(|seed| convert_maps + .iter() + .fold(seed, |acc, map| map.map(acc))) + }) + .min().unwrap()) +} + +fn convert_input_to_convert_maps(input: &str) -> (Vec, Vec) { + let mut lines = input.lines(); + let seed_line = lines.next().unwrap(); + lines.next(); + let mut maps: Vec> = vec![]; + + let mut data = vec![]; + let mut key = String::new(); + + for line in lines { + if line.is_empty() { + maps.push(data); + key = String::new(); + data = vec![]; + continue; + } + + if key.is_empty() { + key = line.to_owned(); + continue; + } + + data.push(line); + } + + maps.push(data); + + let mut convert_map: Vec = vec![]; + for map in maps { + let map = ConvertMap::new("data-to-data".to_owned(), map); + convert_map.push(map); + } + + + (seed_line + .split_once(": ").unwrap().1 + .split(" ") + .map(|data| data.trim()) + .filter(|data| data.len() > 0) + .map(|num| num.parse::().unwrap()) + .collect(), + convert_map) +} + + +#[test] +pub fn test_solve_01() { + let example = r#"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"#; + + let result = solve_01(example).unwrap(); + + assert_eq!(35, result); +} + +#[test] +pub fn test_solve_02() { + let example = r#"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"#; + + let result = solve_02(example).unwrap(); + + assert_eq!(46, result); +} \ No newline at end of file diff --git a/src/input/day05/input.txt b/src/input/day05/input.txt new file mode 100644 index 0000000..bfbf53f --- /dev/null +++ b/src/input/day05/input.txt @@ -0,0 +1,206 @@ +seeds: 1367444651 99920667 3319921504 153335682 67832336 139859832 2322838536 666063790 1591621692 111959634 442852010 119609663 733590868 56288233 2035874278 85269124 4145746192 55841637 864476811 347179760 + +seed-to-soil map: +873256303 3438158294 3400501 +3338810960 408700040 99469568 +876656804 586381004 55967396 +2937187724 3352513245 85645049 +3633224442 4294716315 250981 +4063203128 3993405594 231764168 +628606346 884567853 85164246 +1848085960 2225191252 328179324 +1686068310 2992301693 162017650 +1456962076 179593806 229106234 +0 1520731987 239660433 +2759350898 1833519805 177836826 +494634602 642348400 67929420 +3022832773 758696310 125871543 +3563677889 4225169762 69546553 +2637775123 710277820 48418490 +3148704316 969732099 112580498 +3261284814 2623022420 77526146 +489910414 174869618 4724188 +1187482559 2700548566 269479517 +713770592 2139594657 85596595 +850982693 2970028083 22273610 +932624200 2013609609 125985048 +799367187 1082312597 51615506 +3633475423 3563677889 429727705 +562564022 3283192654 66042324 +2181319395 2553370576 69651844 +2250971239 1133928103 386803884 +3438280528 3349234978 3278267 +2686193613 513223719 73157285 +239660433 1760392420 73127385 +487657436 2011356631 2252978 +312787818 0 174869618 +1058609248 3154319343 128873311 +2176265284 508169608 5054111 + +soil-to-fertilizer map: +297032819 3559164217 26523093 +323555912 2482284077 316032053 +74171080 3214516077 10202585 +3176226661 2368836568 113447509 +2918425623 1610395638 257801038 +3933490965 2171144546 103908097 +1218064889 55976272 92496985 +2591090931 0 23819721 +1798514394 148473257 159960710 +2288143061 1868196676 302947870 +639587965 3736262447 6060799 +3609511269 699586127 40962058 +1575586870 3249692350 47378699 +1310561874 2798316130 265024996 +3650473327 2308711439 60125129 +1958475104 483393073 178493006 +259332771 661886079 37700048 +907741932 980768687 228854035 +1185908338 23819721 32156551 +3437918904 3874038292 163360770 +645648764 3297071049 262093168 +2648569448 1432515231 29635673 +1647939257 3585687310 150575137 +3710598456 1209622722 222892509 +2678205121 740548185 240220502 +84373665 308433967 174959106 +2614910652 2275052643 33658796 +1622965569 3224718662 24973688 +3289674170 1462150904 148244734 +3601279674 3791635617 8231595 +0 3799867212 74171080 +2136968110 3063341126 151174951 +1136595967 3742323246 49312371 + +fertilizer-to-water map: +0 478733437 191375707 +2494518625 3362803490 180386054 +1605510969 1985802816 27464898 +3545871802 2267467733 385725819 +1580307385 1113809296 8335179 +2267467733 4179194655 34953467 +1588642564 52640953 16868405 +768087626 69509358 314799711 +2835042306 4002148814 177045841 +320920516 1122144475 447167110 +1082887337 670109144 443700152 +3218018460 3543189544 156036618 +1921732119 1569311585 321765324 +1632975867 384309069 40704472 +1526587489 425013541 53719896 +3140697718 2802291105 77320742 +1726321292 1891076909 94725907 +3070918618 2732512005 69779100 +1673680339 0 52640953 +3374055078 3830332090 171816724 +2755723853 2653193552 79318453 +3012088147 3242981522 58830471 +2363412697 3699226162 131105928 +1821047199 2013267714 100684920 +2302421200 3301811993 60991497 +191375707 2113952634 129544809 +3931597621 2879611847 363369675 +2674904679 4214148122 80819174 + +water-to-light map: +3219102205 2181622520 201394006 +920319894 2563844887 124975374 +739491533 2383016526 180828361 +653894144 112244681 85597389 +3420496211 0 112244681 +3657404452 197842070 151065180 +2385949305 1028427888 284402820 +3532740892 1312830708 124663560 +379827855 754361599 274066289 +0 374533744 379827855 +1070921762 1437494268 744128252 +1815050014 3237570341 372982025 +2670352125 2688820261 548750080 +1045295268 348907250 25626494 +2188032039 3610552366 197917266 + +light-to-temperature map: +2153765789 597465407 100160624 +2781845200 2181361650 40610317 +667326513 1345068833 191904517 +2473693610 3180449558 308151590 +3613083869 2293229230 341401182 +1062907936 2938916666 34067323 +1451871003 2221971967 71257263 +3954485051 4137063579 102141117 +4192502901 3838513492 49627103 +1389629967 2876675630 62241036 +1593277643 2972983989 143397067 +859231030 2634630412 203676906 +4056626168 790528713 68145539 +1523128266 2838307318 38368312 +503645468 3488601148 84794865 +1333867367 4239204696 55762600 +2902105909 1961894500 219467150 +3268371481 858674252 266627384 +2253926413 1125301636 219767197 +4124771707 3888140595 67731194 +1159014133 3663660258 174853234 +3121573059 1536973350 56534177 +4242130004 1593507527 52837292 +3534998865 697626031 78085004 +1096975259 503645468 62038874 +588440333 3116381056 64068502 +2052224391 3955871789 101541398 +3178107236 3573396013 90264245 +1736674710 1646344819 315549681 +1561496578 565684342 31781065 +2822455517 4057413187 79650392 +652508835 775711035 14817678 + +temperature-to-humidity map: +539306376 906765326 12587914 +0 164719538 374586838 +3299714596 2417002864 137882274 +3574681727 1862289721 10695948 +1377359247 1111480860 147188226 +2546515862 3738486436 38563842 +2519543212 3564238204 26972650 +1619134727 3777050278 31686173 +551894290 728868054 177897272 +3834998050 3919246788 238635651 +729791562 919353240 625999 +1524547473 3627710187 94587254 +2399595894 3277935618 48769514 +1340859914 3591210854 36499333 +2585079704 2011159197 185411491 +3723551203 3452791357 111446847 +2895131743 2873352765 404582853 +374586838 0 164719538 +1776907125 1258669086 373340162 +2881001532 2859222554 14130211 +2217932998 2606381854 181662896 +2166436282 2554885138 51496716 +2448365408 2788044750 71177804 +1650820900 3326705132 126086225 +1110579441 1632009248 230280473 +3437596870 4157882439 137084857 +730417561 539306376 189561678 +4294065877 1110579441 901419 +2150247287 3722297441 16188995 +2770491195 3808736451 110510337 +3585377675 1872985669 138173528 +4073633701 2196570688 220432176 + +humidity-to-location map: +3656475570 3037182697 7397903 +682722270 547529272 780546181 +266636474 1328075453 316323944 +1591860664 3642496089 50700992 +1642561656 266636474 280892798 +1923454454 1644399397 1264527167 +3979139381 3408096655 6045369 +3663873473 4002979627 291987669 +3955861142 3208017899 23278239 +582960418 3414142024 99761852 +3187981621 3231296138 176800517 +3364782138 3044580600 163437299 +1463268451 3513903876 128592213 +3528219437 2908926564 128256133 +4175159701 3693197081 119807595 +3985184750 3813004676 189974951 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4bb7599..695ba95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,11 +3,13 @@ mod utils; mod day02; mod day03; mod day04; +mod day05; const CONTENT01: &'static str = include_str!("input/day01/input.txt"); const CONTENT02: &'static str = include_str!("input/day02/input.txt"); const CONTENT03: &'static str = include_str!("input/day03/input.txt"); const CONTENT04: &'static str = include_str!("input/day04/input.txt"); +const CONTENT05: &'static str = include_str!("input/day05/input.txt"); fn main() { day01::execute_task01(CONTENT01); @@ -21,4 +23,7 @@ fn main() { println!(); day04::execute_task01(CONTENT04); day04::execute_task02(CONTENT04); + println!(); + day05::execute_task01(CONTENT05); + day05::execute_task02(CONTENT05); }