diff --git a/input/day5.txt b/input/day5.txt new file mode 100644 index 0000000..4dc6e81 --- /dev/null +++ b/input/day5.txt @@ -0,0 +1,261 @@ +seeds: 2906422699 6916147 3075226163 146720986 689152391 244427042 279234546 382175449 1105311711 2036236 3650753915 127044950 3994686181 93904335 1450749684 123906789 2044765513 620379445 1609835129 60050954 + +seed-to-soil map: +2642418175 2192252668 3835256 +2646253431 2276158914 101631202 +2640809144 3719389865 1609031 +2439110058 2377790116 121628096 +439727986 2712085714 392957193 +993018128 1316992003 327657967 +832685179 1875058987 50438969 +2796039666 0 1107546829 +182253984 3569317158 150072707 +2747884633 1826903954 48155033 +2268424297 3406848659 162468499 +0 1644649970 182253984 +1794130013 2499418212 105266207 +2560738154 2196087924 80070990 +1512587867 1925497956 72096972 +2094053960 3729216158 174370337 +1320676095 3105042907 191911772 +1899396220 1997594928 194657740 +2430892796 3720998896 8217262 +1584684839 1107546829 209445174 +332326691 2604684419 107401295 +883124148 3296954679 109893980 + +soil-to-fertilizer map: +1486714106 1238503832 507721065 +637816737 149749818 437782225 +1182620803 2675299784 39248251 +3597657865 3775149764 175910008 +3773567873 3962939269 152626038 +3000531163 3487988055 287161709 +1221869054 1043346723 160011771 +1417026163 2117544922 69687943 +3584687325 3000531163 12970540 +3938073408 3484898614 3089441 +4154999630 4115565307 65971879 +3941162849 3087497490 97611489 +427771233 2337712270 210045504 +2132339212 587532043 265793132 +4220971509 3013501703 73995787 +3926193911 3951059772 11879497 +3287692872 3271363394 97309928 +3385002800 3185108979 86254415 +277291828 2187232865 150479405 +1075598962 1746224897 107021841 +1994435171 2714548035 137904041 +2398132344 1853246738 264298184 +4038774338 3368673322 116225292 +0 2547757774 127542010 +127542010 0 149749818 +2662430528 853325175 190021548 +3471257215 4181537186 113430110 +1381880825 1203358494 35145338 + +fertilizer-to-water map: +1335715777 3551297863 15572557 +3058091197 394986221 12806050 +3214739636 1272556544 43474947 +2194583281 3796992984 5908188 +1795111705 3569682225 74131978 +2761913827 2554114847 40731321 +163407858 97246509 38153094 +201560952 135399603 99530224 +2940391010 2113359463 79167148 +1379193735 3838257748 62489021 +605586814 1626110823 487248640 +1210765693 2673739436 122138279 +2657443462 2449644482 104470365 +1332903972 3566870420 2811805 +1092835454 1468044840 52984152 +3612861396 610695664 247630343 +4056909324 407792271 18897075 +1351288334 3900746769 27905401 +2200491469 2958550754 43716751 +3070897247 426689346 143842389 +2563990948 2356191968 93452514 +3860491739 2192526611 17573017 +430342797 3077819515 14543393 +1441682756 3140553634 112714328 +1554397084 1521028992 105081831 +1659478915 858326007 135632790 +1195705829 4279907432 15059864 +4075806399 3372259011 179038852 +2490006393 570531735 40163929 +2244208220 2795877715 126807124 +3272482070 3939528106 340379326 +444886190 3092362908 48190726 +1145819606 3027933292 49886223 +2371015344 3253267962 118991049 +3878064756 3002267505 25665787 +1869243683 993958797 278597747 +3258214583 1316031491 14267487 +2802645148 1330298978 137745862 +2563752764 2673501252 238184 +3903730543 3643814203 153178781 +97246509 234929827 66161349 +2158717366 2922684839 35865915 +2147841430 3928652170 10875936 +3019558158 2594846168 38533039 +493076916 2210099628 112509898 +2530170322 2322609526 33582442 +394986221 3802901172 35356576 +4254845251 2633379207 40122045 + +water-to-light map: +52352735 734025495 196243881 +3196736017 3686620279 539418860 +4260073591 2346541810 34893705 +3824140629 2381435515 128703321 +460535344 312464861 85993982 +963896761 930269376 1539501 +2058204537 3345283958 241067289 +1428799796 3586351247 100269032 +3077002514 1717378211 119733503 +2792038862 1432414559 284963652 +0 683119049 18725350 +2738205765 2731593698 53833097 +248596616 6913757 211938728 +953587656 0 6913757 +3736154877 2818563473 87985752 +1988337486 2311649339 34892471 +668927450 398458843 284660206 +2023229957 3310309378 34974580 +18725350 951959788 13476474 +2631325954 2191463345 25160101 +1295231825 2967131323 133567971 +2491590802 2510138836 139735152 +546529326 701844399 32181096 +3952843950 2906549225 60582098 +1882790692 3100699294 48444656 +2354408068 1295231825 137182734 +4153221679 4226039139 68928157 +2299901593 3288939581 21369797 +2321271390 2785426795 33136678 +578710422 222247833 90217028 +4013426048 3149143950 139795631 +1529068828 1837741481 353721864 +1931235348 2216623446 57102138 +32201824 931808877 20150911 +2299271826 1837111714 629767 +960501413 218852485 3395348 +4222149836 2273725584 37923755 +2656486055 2649873988 81719710 + +light-to-temperature map: +2002559950 382000741 90685628 +285136495 3669200023 235300945 +1697895437 3029658057 91190914 +2333974289 2655904102 65571245 +283606237 1729595262 1530258 +3395579298 2846931786 182726271 +3908077331 4156397993 58163239 +1641412094 1383382121 13076534 +3171401086 1731125520 55619959 +2399545534 283606237 11466807 +2411012341 694053237 46713076 +555564215 2831795288 15136498 +570700713 1473120509 221347978 +520437440 1694468487 35126775 +1640428391 3411773949 983703 +2936877085 306865692 75135049 +3578305569 2167033125 54004942 +1076200859 2221038067 81247286 +3884751672 1148097778 23325659 +3632310511 746654088 139828329 +4189239539 3506297541 50289650 +1909020061 3412757652 93539889 +2709622442 740766313 5887775 +792048691 1911214447 163922279 +3999452535 4264264797 30702499 +3159608438 295073044 11792648 +1064487544 2588752680 11713315 +1172524157 902820295 245277483 +1789086351 1263448411 119933710 +2715510217 472686369 221366868 +2093245578 3147917902 240728711 +1417801640 2366125929 222626751 +3303682899 2075136726 91896399 +955970970 4214561232 49703565 +1157448145 2302285353 15076012 +3012012134 3388646613 23127336 +3966240570 1230236446 33211965 +4030155034 2317361365 48764564 +3227021045 1396458655 76661854 +3035139470 1786745479 124468968 +2457725417 3904500968 251897025 +1005674535 1171423437 58813009 +4078919598 2721475347 110319941 +1654488628 886482417 16337878 +3772138840 3556587191 112612832 +1670826506 3120848971 27068931 +4239529189 2600465995 55438107 + +temperature-to-humidity map: +2776202835 2235980179 978805 +79456303 770215397 125672111 +350944915 144658185 147068664 +239335677 1555124158 884128 +3153890512 3800437685 109571794 +240219805 0 95968287 +2078890110 4167578198 41164706 +3637428670 2781740910 54319513 +3511657938 2772352153 5987732 +2771529423 3277605929 4673412 +498013579 291726849 399032245 +3691748183 3910009479 257568719 +3548876568 3282279341 16553363 +3135162288 2217251955 18728224 +2161038070 2836060423 259888366 +3565429931 4208742904 71998739 +3952717927 3799896230 541455 +2777181640 2500118625 179031937 +3953259382 3395098982 156601616 +4109860998 3298832704 70018024 +2580082919 1819987413 191446504 +1398347285 895887508 382372949 +205128414 1556008286 34207263 +2956213577 2011433917 178948711 +3517645670 2679150562 4361571 +336188092 129901362 14756823 +1364414210 95968287 33933075 +1173909525 1590215549 190504685 +3263462306 3551700598 248195632 +2420926436 2495861681 4256944 +1819987413 2236958984 258902697 +2120054816 3095948789 26757601 +4179879022 2683512133 88840020 +3522007241 2190382628 26869327 +2146812417 4280741643 14225653 +0 690759094 79456303 +897045824 1278260457 276863701 +4268719042 3368850728 26248254 +2425183380 3122706390 154899539 +3949316902 2778339885 3401025 + +humidity-to-location map: +1568324830 3576584364 32633066 +300199016 474209742 262529847 +3559913667 3345416335 231168029 +1042084677 290085772 184123970 +0 27095618 110260307 +562728863 0 7921916 +1860347496 3086490828 96440514 +1956788010 3609217430 226060373 +262990154 1080572947 37208862 +2182848383 3062438579 9763931 +589824481 1443076400 49986334 +639810815 1329220256 113856144 +1600957896 1568324830 245101282 +2310901200 1813426112 1249012467 +3791081696 3835277803 341400607 +1846059178 3072202510 14288318 +4132482303 3182931342 162484993 +2192612314 4176678410 118288886 +965105406 736739589 76979271 +753666959 1117781809 211438447 +110260307 137355925 152729847 +1226208647 813718860 266854087 +570650779 7921916 19173702 diff --git a/src/day05.rs b/src/day05.rs new file mode 100644 index 0000000..8d7eeb3 --- /dev/null +++ b/src/day05.rs @@ -0,0 +1,270 @@ +use std::{collections::HashMap, ops::Range}; + +use regex::Regex; + +pub fn run() { + let input = include_str!("../input/day5.txt"); + // let input = 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 almanac = Almanac::parse_seed_list(input); + let part1 = almanac.convert_seeds_to_locations(); + dbg!(part1.iter().min().unwrap()); + + let almanac2 = Almanac::parse_seed_range(input); + let part2 = almanac2.convert_seeds_to_locations(); + dbg!(part2.iter().min().unwrap()); +} + +#[derive(Debug, Clone)] +struct Almanac + Clone> { + seeds: S, + maps: HashMap<(String, String), Map>, +} + +fn parse_maps<'a>(parts: impl Iterator) -> HashMap<(String, String), Map> { + let mut maps = HashMap::new(); + let map_name_re = Regex::new(r#"(\w+)-to-(\w+) map:"#).unwrap(); + for map_s in parts { + let (name, rest) = map_s.split_once("\n").unwrap(); + let map_captures = map_name_re.captures(name).unwrap(); + let map = Map::parse(rest); + maps.insert( + (map_captures[1].to_owned(), map_captures[2].to_owned()), + map, + ); + } + maps +} + +impl Almanac> { + fn parse_seed_list(s: &str) -> Self { + let mut parts = s.split("\n\n"); + let seeds_s = parts.next().unwrap(); + assert!(seeds_s.starts_with("seeds: ")); + let seeds_s = seeds_s.split_at("seeds: ".len()).1; + let seeds = seeds_s + .split(" ") + .map(|s| s.parse::().unwrap()) + .collect::>(); + Self { + seeds, + maps: parse_maps(parts), + } + } +} + +#[derive(Debug, Clone, PartialEq)] +struct Seeds { + ranges: Vec>, + cur: Option>, +} + +impl Iterator for Seeds { + type Item = i64; + + fn next(&mut self) -> Option { + if self.cur.is_none() || self.cur.as_ref().unwrap().is_empty() { + if self.ranges.is_empty() { + self.cur = None; + return None; + } else { + self.cur = Some(self.ranges.remove(0)); + return self.next(); + } + } else { + let cur = self.cur.as_ref().unwrap(); + let ret = cur.start; + self.cur = Some((cur.start + 1)..cur.end); + return Some(ret); + } + } +} + +impl Almanac { + fn parse_seed_range(s: &str) -> Self { + let mut parts = s.split("\n\n"); + let seeds_s = parts.next().unwrap(); + assert!(seeds_s.starts_with("seeds: ")); + let seeds_s = seeds_s.split_at("seeds: ".len()).1; + let numbers = seeds_s + .split(" ") + .map(|s| s.parse::().unwrap()) + .collect::>(); + assert!(numbers.len() % 2 == 0); + let ranges = numbers + .chunks(2) + .map(|chunk| chunk[0]..(chunk[0] + chunk[1])) + .collect::>(); + Self { + seeds: Seeds { ranges, cur: None }, + maps: parse_maps(parts), + } + } +} + +impl + Clone> Almanac { + fn convert(&self, xs: &mut Vec, from: &str, to: &str) { + let map = self + .maps + .get(&(from.to_owned(), to.to_owned())) + .expect(&format!("conversion from {} to {}", from, to)); + for i in 0..xs.len() { + xs[i] = map.convert(xs[i]); + } + } + + fn convert_seeds_to_locations(&self) -> Vec { + let path = &[ + "soil", + "fertilizer", + "water", + "light", + "temperature", + "humidity", + "location", + ]; + let mut cur_type = "seed"; + let mut cur = self.seeds.clone().into_iter().collect::>(); + for next in path { + self.convert(&mut cur, cur_type, next); + cur_type = next; + } + cur + } +} + +#[derive(Debug, Clone, PartialEq)] +struct Map { + // range of source and offset to dest + ranges: Vec<(Range, i64)>, +} + +impl Map { + fn parse(s: &str) -> Self { + let ranges = s + .lines() + .map(|l| { + let mut parts = l.trim().split(" "); + let dest_start: i64 = parts.next().unwrap().parse().unwrap(); + let source_start: i64 = parts.next().unwrap().parse().unwrap(); + let len: i64 = parts.next().unwrap().parse().unwrap(); + assert_eq!(parts.next(), None); + ( + source_start..(source_start + len), + dest_start - source_start, + ) + }) + .collect::>(); + Self { ranges } + } + + fn convert(&self, source: i64) -> i64 { + for (range, offset) in self.ranges.iter() { + if range.contains(&source) { + return source + offset; + } + } + source + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_map() { + assert_eq!( + Map::parse("50 98 2\n52 50 48"), + Map { + ranges: vec![(98..100, -48), (50..98, 2),], + } + ) + } + + #[test] + fn test_map_convert() { + let m = Map { + ranges: vec![(98..100, -48), (50..98, 2)], + }; + assert_eq!(m.convert(98), 50); + assert_eq!(m.convert(53), 55); + assert_eq!(m.convert(10), 10); + } + + #[test] + fn test_parse_almanac() { + let a = Almanac::parse_seed_list( + r#"seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48"#, + ); + assert_eq!(a.seeds, vec![79, 14, 55, 13]); + let k = ("seed".to_owned(), "soil".to_owned()); + assert_eq!(a.maps.keys().collect::>(), vec![&k]); + assert_eq!( + a.maps[&k], + Map { + ranges: vec![(98..100, -48), (50..98, 2)], + } + ); + } + + #[test] + fn test_parse_almanac_seed_ranges() { + let a = Almanac::parse_seed_range("seeds: 1 2 3 4"); + assert_eq!( + a.seeds, + Seeds { + ranges: vec![1..3, 3..7], + cur: None, + } + ); + } + + #[test] + fn test_seeds_iter() { + assert_eq!( + Seeds { + ranges: vec![1..3, 3..7], + cur: None, + } + .collect::>(), + vec![1, 2, 3, 4, 5, 6] + ); + } +} diff --git a/src/main.rs b/src/main.rs index ed72f99..5af56b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,8 @@ mod day01; mod day02; mod day03; mod day04; +mod day05; fn main() { - day04::run(); + day05::run(); }