diff --git a/Cargo.lock b/Cargo.lock index c2ea9a9..5a94fa6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,11 @@ name = "aoc23" version = "0.1.0" dependencies = [ "async-recursion", + "derive_builder", "expanduser", "futures", "itertools", + "rayon", "regex", "reqwest", "reqwest-middleware", @@ -114,7 +116,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -125,7 +127,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -329,6 +331,30 @@ dependencies = [ "cfg-if", ] +[[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" @@ -338,6 +364,41 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "deranged" version = "0.3.9" @@ -347,6 +408,37 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "dirs" version = "1.0.5" @@ -512,7 +604,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -700,6 +792,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -829,6 +927,15 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -940,7 +1047,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1119,6 +1226,26 @@ dependencies = [ "getrandom 0.2.11", ] +[[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 = "redox_syscall" version = "0.1.57" @@ -1374,7 +1501,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1444,6 +1571,23 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.39" @@ -1515,7 +1659,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1604,7 +1748,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1656,7 +1800,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] @@ -1769,7 +1913,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-shared", ] @@ -1803,7 +1947,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index cf1f795..8270dc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,5 @@ serde_json = "1" tiktoken-rs = "0.5" tokio = { version = "1", features = ["full"] } itertools = "0.12" +derive_builder = "0.12.0" +rayon = "1.8.0" diff --git a/aoc_puzzle_cache/day_5 b/aoc_puzzle_cache/day_5 new file mode 100644 index 0000000..d1aabaa --- /dev/null +++ b/aoc_puzzle_cache/day_5 @@ -0,0 +1,197 @@ +seeds: 3127166940 109160474 3265086325 86449584 1581539098 205205726 3646327835 184743451 2671979893 17148151 305618297 40401857 2462071712 203075200 358806266 131147346 1802185716 538526744 635790399 705979250 + +seed-to-soil map: +931304316 1786548802 232453384 +3500539319 2322065235 6421609 +496396007 147739714 266329192 +3169724489 768672891 39526579 +3689153715 1361862036 346985 +1936948751 3328259881 542896984 +3209251068 3154345676 173914205 +1163757700 2814318523 24125066 +2484210664 1362209021 231487475 +3991904247 2133571422 188493813 +1187882766 4045525873 83717994 +861951350 3084992710 69352966 +2715698139 2838443589 43714032 +3830303258 4025104215 20421658 +768672891 1268583577 93278459 +4180398060 2019002186 114569236 +3689500700 1593696496 10659519 +1271600760 808199470 460384107 +166497091 526585653 102729094 +3700160219 3894961176 130143039 +2966889400 2882157621 202835089 +147739714 414068906 18757377 +3850724916 4133608796 141179331 +2759412171 2328486844 183672918 +2479845735 4129243867 4364929 +3480360150 4274788127 20179169 +402636637 432826283 93759370 +3383165273 2717123646 97194877 +3506960928 1604356015 182192787 +269226185 629314747 133410452 +2943085089 3871156865 23804311 +1731984867 2512159762 204963884 + +soil-to-fertilizer map: +3368312743 826425240 243745914 +1045038113 3682756471 174490549 +3931158487 1530223690 363808809 +1219528662 2460222182 131099318 +3020480207 1894032499 63879875 +121779694 248970341 36319877 +1993634034 2662348686 86667553 +3612058657 1323325837 196530127 +1531175223 2604354699 57993987 +158099571 121779694 127190647 +1867147432 3317666386 126486602 +2080301587 2768963716 548702670 +1402482267 1070171154 21180243 +2959841028 4051272297 60639179 +834756529 1966243663 128160296 +3911211010 2749016239 19947477 +962916825 3857247020 82121288 +2629004257 3444152988 238603483 +826425240 1957912374 8331289 +1350627980 3939368308 51854287 +1589169210 4214533702 80433594 +2867607740 2094403959 92233288 +1669602804 1125781209 197544628 +3084360082 1519855964 10367726 +1483712212 1091351397 34429812 +3094727808 2186637247 273584935 +1423662510 3991222595 60049702 +3808588784 4111911476 102622226 +1518142024 2591321500 13033199 + +fertilizer-to-water map: +206818393 1973789958 18543481 +2641351404 1992333439 41420268 +58400970 2574944960 107826712 +3710426911 4065366707 42793360 +4217161704 4274048011 20919285 +1926695368 705931711 328031436 +1449580741 1210970895 50549447 +907984567 1421828853 15115545 +769748018 1108192216 102778679 +451427938 35457870 38201654 +2254726804 2033892789 137829519 +923239194 1513967644 270588891 +3753220271 4108160067 165887944 +499804857 310274559 109862756 +3061525238 3535532059 426476055 +1193828085 73659524 196024324 +872526697 0 35457870 +1766386857 1261520342 160308511 +4057593930 3283950856 159567774 +1389852409 646203379 59728332 +3919108215 3962008114 103358593 +1577153434 1784556535 189233423 +4022466808 3443518630 35127122 +489629592 1098016951 10175265 +923100112 2033753707 139082 +2392556323 2390203683 158894869 +1500130188 1436944398 77023246 +2577297600 1033963147 64053804 +609667613 2171722308 160080405 +3488001293 3061525238 222425618 +2551451192 2549098552 25846408 +4238080989 3478645752 56886307 +166227682 269683848 40590711 +0 2331802713 58400970 +225361874 420137315 226066064 + +water-to-light map: +1833244152 0 764535859 +212138399 2132863085 224047237 +445686952 1600446740 163005122 +3322180377 2914685303 488586806 +2739726430 3712513349 582453947 +3946546331 3589340640 8839399 +1441711040 799272484 245821386 +1038755613 1763451862 6623730 +608692074 1587251997 13194743 +701103180 2356910322 39153476 +1687532426 1045093870 145711726 +2597780011 764535859 34736625 +740256656 1490869662 54307168 +0 1920724686 212138399 +2632516636 1545176830 9229765 +668257778 1554406595 32845402 +3955385730 2739726430 39179725 +4180633986 3598180039 114333310 +3810767183 2778906155 135779148 +1291061946 1770075592 150649094 +436185636 1481368346 9501316 +1045379343 2396063798 245682603 +794563824 1237176557 244191789 +621886817 1190805596 46370961 +3994565455 3403272109 186068531 + +light-to-temperature map: +432141642 1268486741 19474646 +3617581823 3276436954 357008111 +3505110084 3786131308 49942802 +0 1287961387 432141642 +3096011130 1808659179 409098954 +1347993824 2675880000 161612192 +3019335150 3199760974 76675980 +3555052886 3137232037 62528937 +2778092757 1720103029 88556150 +451616288 2217758133 458121867 +1509606016 0 1268486741 +909738155 3836074110 138515824 +1048253979 2837492192 299739845 +2866648907 3633445065 152686243 + +temperature-to-humidity map: +646729740 1519504972 559297346 +1894539176 2990410634 44298872 +232257988 972432123 414471752 +2277879451 278205785 108711195 +1775790220 132298732 118748956 +3371687162 2663455233 326955401 +1612056920 272509895 5695890 +1208383109 3703499740 147415518 +4070380190 4053129082 69974785 +4155541210 3305585510 139426086 +81956384 386916980 150301604 +3987543096 896459472 75972651 +2148980475 1386903875 128898976 +1617752810 3445011596 154599732 +4063515747 2078802318 6864443 +2392568787 3599611328 101532389 +2386590646 4123103867 5978141 +2494101176 2122546980 187027686 +2681128862 2085666761 36880219 +4140354975 2648268998 15186235 +1772352542 3051742077 3437678 +1355798627 3850915258 202213824 +3720104770 3055179755 250405755 +3032992830 2309574666 338694332 +1206027086 3701143717 2356023 +1938838048 537218584 44257139 +1558012451 81956384 50342348 +3970510525 3034709506 17032571 +1608354799 1515802851 3702121 +1983095187 4129082008 165885288 +3698642563 251047688 21462207 +2718009081 581475723 314983749 + +humidity-to-location map: +971626884 4275486551 19480745 +1218249913 2090555906 502249162 +2914848039 2902831882 224865747 +3341591733 2819947352 82884530 +991107629 2592805068 227142284 +3424476263 606585628 95279547 +4279176998 2064757318 10971709 +3139713786 4068790015 201877947 +606585628 701865175 365041256 +3534582689 3291885426 744594309 +1916997152 1066906431 997850887 +1752809355 3127697629 164187797 +1720499075 4036479735 32310280 +4290148707 4270667962 4818589 +3519755810 2075729027 14826879 diff --git a/src/bin/day5.rs b/src/bin/day5.rs index 583b328..aab9255 100644 --- a/src/bin/day5.rs +++ b/src/bin/day5.rs @@ -1,27 +1,251 @@ use aoc23::prelude::*; -use std::time::Instant; +use derive_builder::Builder; +use itertools::Itertools; +use rayon::prelude::*; +use std::{str::FromStr, time::Instant}; + +#[derive(Debug, Builder, Clone)] +struct Map { + destination_start: usize, + source_start: usize, + length: usize, +} + +impl FromStr for Map { + type Err = BoxE; + + fn from_str(s: &str) -> std::result::Result { + let mut parts = s + .trim() + .split_whitespace() + .map(|s| s.parse::().expect("failed to parse")); + Ok(MapBuilder::default() + .destination_start(parts.next().expect("no dest")) + .source_start(parts.next().expect("no start")) + .length(parts.next().expect("no length")) + .build()?) + } +} + +impl Map { + fn includes_source(&self, source: usize) -> bool { + source >= self.source_start && source < self.source_start + self.length + } + + fn apply(&self, source: usize) -> Option { + if self.includes_source(source) { + let diff = source - self.source_start; + Some(self.destination_start + diff) + } else { + None + } + } +} + +#[derive(Debug, Builder, Clone)] +struct Mapper { + source: String, + destination: String, + maps: Vec, +} + +impl FromStr for Mapper { + type Err = BoxE; + + fn from_str(s: &str) -> std::result::Result { + let mut mapper = MapperBuilder::default(); + mapper.maps(vec![]); + for line in s.trim().lines() { + if mapper.source.is_none() { + let mut keys = line + .split_whitespace() + .next() + .expect("no source-dest") + .split("-to-"); + mapper.source(keys.next().expect("no source key").to_owned()); + mapper.destination(keys.next().expect("no destination key").to_owned()); + } else if let Some(maps) = &mut mapper.maps { + maps.push(line.parse()?); + } + } + Ok(mapper.build()?) + } +} + +impl Mapper { + fn apply(&self, source: usize) -> usize { + self.maps + .iter() + .find_map(|map| map.apply(source)) + .unwrap_or(source) + } +} + +#[derive(Debug, Builder, Clone)] +struct Seeds { + source: String, +} + +#[derive(Debug, Builder)] +struct Almanac { + seeds: Seeds, + mappers: Vec, +} + +impl Almanac { + fn map_source(&self, source: usize, start_key: &str, end_key: &str) -> usize { + let mut current_key = start_key; + let mut current_value = source; + while current_key != end_key { + let mapper = self + .mappers + .iter() + .find(|mapper| mapper.source == current_key) + .expect("could not find mapper"); + current_value = mapper.apply(current_value); + current_key = &mapper.destination; + } + current_value + } +} + +impl FromStr for Almanac { + type Err = BoxE; + + fn from_str(s: &str) -> std::result::Result { + let mut almanac = AlmanacBuilder::default(); + let mut parts = s.trim().split("\n\n"); + almanac.seeds(Seeds { + source: parts.next().expect("seed line missing").to_string(), + }); + almanac.mappers(vec![]); + while let Some(mapper_section) = parts.next() { + if let Some(mappers) = &mut almanac.mappers { + mappers.push(mapper_section.parse()?); + } + } + Ok(almanac.build()?) + } +} fn part1(input: String) -> Result { - let mut answer = 0; - println!("Input:\n{}", input); + // parse + let start = Instant::now(); + let almanac: Almanac = input.parse()?; + let parsed_time = start.elapsed(); + + // algo + let start = Instant::now(); + let answer = almanac + .seeds + .source + .split(":") + .nth(1) + .expect("seeds missing") + .trim() + .split_whitespace() + .map(|s| s.parse::().expect("failed to parse seed as number")) + .map(|source| almanac.map_source(source, "seed", "location")) + .par_bridge() + .min() + .ok_or("failed to get min location")?; + let algo_time = start.elapsed(); + + // output + println!("Day 5, part 1: {answer}"); + println!("\tparse: {parsed_time:?}"); + println!("\talgo: {algo_time:?}"); Ok(answer) } fn part2(input: String) -> Result { - let mut answer = 0; + // parse + let start = Instant::now(); + let almanac: Almanac = input.parse()?; + let parsed_time = start.elapsed(); + + // algo + let start = Instant::now(); + let answer = almanac + .seeds + .source + .split(":") + .nth(1) + .expect("seeds missing") + .trim() + .split_whitespace() + .map(|s| s.parse::().expect("failed to parse seed as number")) + .tuples() + .flat_map(|(start, length)| start..start + length) + .par_bridge() + .map(|source| almanac.map_source(source, "seed", "location")) + .min() + .ok_or("failed to get min location")?; + let algo_time = start.elapsed(); + + // output + println!("Day 5, part 1: {answer}"); + println!("\tparse: {parsed_time:?}"); + println!("\talgo: {algo_time:?}"); Ok(answer) } #[tokio::main] async fn main() -> Result<()> { - println!("Day 5"); - println!("====="); - - // let input = utils::aoc::get_puzzle_input(5).await?; - let input = "".to_owned(); - let start = Instant::now(); - println!("part 1: {}\t[{:?}]", part1(input.clone())?, start.elapsed()); - let start = Instant::now(); - println!("part 2: {}\t[{:?}]", part2(input.clone())?, start.elapsed()); + let input = utils::aoc::get_puzzle_input(5).await?; + part1(input.clone())?; + part2(input.clone())?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + static DATA: &'static str = "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 +"; + + #[test] + fn test_part_1() -> Result<()> { + assert_eq!(part1(DATA.to_owned())?, 35); + Ok(()) + } + + #[test] + fn test_part_2() -> Result<()> { + assert_eq!(part2(DATA.to_owned())?, 46); + Ok(()) + } +}