From a0611f1fb311e2ea3ca7a658cf4d49583317a091 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Wed, 9 Dec 2020 06:35:18 +0100 Subject: [PATCH] 2020: day09: part 1 and 2 --- aoc2020/benches/bench.rs | 2 + aoc2020/input/day09.txt | 1000 ++++++++++++++++++++++++++++++ aoc2020/input/day09_provided.txt | 20 + aoc2020/src/day09.rs | 130 ++++ aoc2020/src/lib.rs | 1 + aoc2020/src/main.rs | 2 + 6 files changed, 1155 insertions(+) create mode 100644 aoc2020/input/day09.txt create mode 100644 aoc2020/input/day09_provided.txt create mode 100644 aoc2020/src/day09.rs diff --git a/aoc2020/benches/bench.rs b/aoc2020/benches/bench.rs index 632fbf3..1e916d1 100644 --- a/aoc2020/benches/bench.rs +++ b/aoc2020/benches/bench.rs @@ -8,6 +8,7 @@ use aoc2020::day05; use aoc2020::day06; use aoc2020::day07; use aoc2020::day08; +use aoc2020::day09; fn aoc2020_all(c: &mut Criterion) { c.bench_function("day01", |b| b.iter(|| day01::run().unwrap())); @@ -18,6 +19,7 @@ fn aoc2020_all(c: &mut Criterion) { c.bench_function("day06", |b| b.iter(|| day06::run().unwrap())); c.bench_function("day07", |b| b.iter(|| day07::run().unwrap())); c.bench_function("day08", |b| b.iter(|| day08::run().unwrap())); + c.bench_function("day09", |b| b.iter(|| day09::run().unwrap())); } criterion_group! { diff --git a/aoc2020/input/day09.txt b/aoc2020/input/day09.txt new file mode 100644 index 0000000..300bfe3 --- /dev/null +++ b/aoc2020/input/day09.txt @@ -0,0 +1,1000 @@ +36 +10 +13 +25 +30 +28 +2 +16 +24 +49 +32 +14 +47 +46 +39 +5 +35 +3 +34 +20 +8 +41 +40 +43 +19 +7 +15 +38 +37 +9 +30 +10 +27 +13 +23 +70 +11 +26 +18 +14 +28 +61 +12 +16 +22 +21 +17 +35 +20 +24 +19 +25 +40 +29 +43 +34 +39 +30 +31 +32 +46 +38 +33 +26 +48 +36 +37 +89 +49 +78 +41 +55 +69 +44 +45 +63 +51 +60 +56 +57 +70 +58 +61 +107 +59 +71 +85 +62 +74 +95 +73 +106 +86 +94 +89 +102 +96 +100 +105 +115 +117 +108 +113 +159 +143 +119 +185 +120 +121 +132 +208 +163 +177 +147 +162 +192 +175 +180 +292 +189 +196 +238 +205 +435 +221 +229 +227 +404 +367 +477 +350 +279 +434 +253 +294 +343 +338 +309 +322 +337 +355 +449 +385 +394 +401 +555 +426 +612 +448 +562 +608 +549 +532 +547 +660 +603 +573 +728 +591 +681 +1153 +631 +646 +659 +1082 +996 +926 +779 +795 +827 +1094 +975 +1079 +1382 +1359 +1761 +1081 +1194 +1807 +1272 +1863 +1222 +1703 +1237 +1741 +1881 +1277 +1305 +2051 +2173 +1823 +1873 +1606 +1622 +2476 +2054 +2197 +3001 +2275 +2303 +2431 +2318 +2416 +2459 +2494 +2499 +3736 +4100 +4734 +3799 +2582 +2883 +5622 +3228 +4105 +3429 +3479 +3660 +6235 +4691 +4251 +5013 +4578 +4774 +4621 +4993 +4777 +5978 +5081 +6599 +5382 +5465 +5810 +6011 +6061 +8005 +6312 +7806 +8356 +7680 +6908 +8560 +7911 +8872 +13691 +8829 +12886 +9199 +15798 +9398 +13649 +16834 +10546 +20248 +12323 +11192 +11275 +14066 +12072 +15459 +13220 +14819 +16240 +15737 +24358 +15468 +17958 +22478 +29864 +19375 +33753 +18597 +19745 +30306 +28679 +21738 +23347 +29872 +25258 +23264 +22467 +28312 +25292 +26891 +28688 +28039 +32777 +31205 +33426 +48424 +58096 +36555 +37972 +41483 +43092 +38342 +66284 +42212 +44205 +45002 +51303 +45731 +68384 +50779 +48556 +106726 +52183 +53980 +54930 +59244 +69332 +63982 +82974 +81064 +132367 +74527 +80184 +76314 +189700 +80554 +82547 +93515 +114334 +89207 +90733 +111427 +96510 +99335 +165970 +100739 +126710 +179519 +123226 +131244 +128576 +133314 +146956 +172824 +362524 +162731 +150841 +202160 +156868 +169761 +163101 +263557 +182722 +273666 +292987 +187243 +195845 +307709 +254470 +266709 +223965 +294345 +338084 +251802 +410513 +319599 +385116 +313572 +360067 +384882 +313942 +627308 +345823 +434524 +332862 +350344 +369965 +378567 +383088 +509787 +411208 +419810 +490674 +879752 +518310 +607053 +546147 +584664 +659765 +627514 +796090 +683206 +646434 +692509 +1375715 +646804 +678685 +696167 +997479 +929597 +720309 +748532 +789775 +1038722 +1323681 +831018 +910484 +1008984 +1244429 +1196995 +1130811 +1472981 +1843429 +1273948 +1310720 +2402578 +1293238 +1325119 +1325489 +1957524 +3282643 +1374852 +1444699 +1468841 +1510084 +1538307 +1579550 +1919468 +1741502 +1840002 +1961829 +2537667 +2139795 +2849027 +2327806 +3214483 +2798470 +2635839 +2567186 +2835203 +6012953 +2618357 +3117857 +2770188 +3048391 +2954783 +4610190 +3541379 +2978925 +3089634 +4174146 +4717938 +5484866 +4279169 +4167808 +4101624 +4467601 +6049686 +5471042 +4894992 +5185543 +7553141 +6096782 +5337374 +6068559 +5388545 +5573140 +5724971 +7056407 +7564973 +7258094 +7263780 +9740948 +10522917 +11457104 +8275770 +9353351 +8269432 +8380793 +15809507 +8569225 +9362593 +10619963 +10080535 +10232366 +14823067 +10725919 +10910514 +10961685 +11113516 +11298111 +12781378 +12983065 +14314501 +14521874 +15527526 +15833005 +20854464 +19092142 +16844995 +17622783 +17922576 +16650225 +19189188 +17931818 +19479739 +20088512 +37504689 +25784752 +28836375 +21636433 +26946521 +21872199 +33459344 +26825637 +25612612 +25764443 +34619668 +30049400 +30354879 +31360531 +35854394 +34467778 +33495220 +34776813 +39568251 +55782896 +34582043 +39804017 +65828309 +46914149 +41724945 +55834152 +43508632 +47484811 +47249045 +52227078 +63850099 +52590080 +51377055 +63544620 +55813843 +64631443 +60404279 +87288828 +78845342 +81381927 +67962998 +76306988 +69358856 +115771698 +74386060 +78090675 +81528962 +163020743 +85233577 +133208955 +119340053 +90757677 +116218122 +193862373 +116134700 +103967135 +159780978 +143102671 +172031965 +185493556 +125035722 +128367277 +137321854 +154397663 +142349058 +145665844 +143744916 +201005275 +233860348 +224631633 +197430728 +200869015 +246316193 +175991254 +194724812 +206892377 +206975799 +370716066 +546707320 +268780638 +229002857 +400713856 +253402999 +262357576 +288014902 +265689131 +270716335 +279670912 +286093974 +248131121 +289410760 +441680385 +607606233 +464006156 +431607432 +382883631 +441041005 +465441147 +382967053 +611969910 +636286630 +435978656 +482405856 +477133978 +700388070 +1090012089 +501534120 +536146023 +510488697 +908741410 +513820252 +534225095 +711278344 +952169082 +1429303060 +672294391 +765850684 +814491063 +965832527 +865372909 +818862287 +959539834 +1046634720 +917192148 +946467353 +913112634 +1486394177 +1855862773 +978668098 +1620019754 +1718929111 +1678963318 +1024308949 +1044713792 +1048045347 +1558534044 +1206519486 +2925448597 +1438145075 +1810564476 +1486785454 +2373025107 +2416813173 +1959747354 +1684235196 +1736054435 +1830304782 +2152986839 +1863659501 +1859579987 +1891780732 +2185187584 +2002977047 +2023381890 +3346365441 +2743238060 +2069022741 +3222839889 +2092759139 +3828813574 +2644664561 +2693304940 +5315599028 +2924930529 +4573542842 +3595634422 +3547894697 +4280472674 +4095736186 +3921242019 +3566359217 +3984539871 +7051653463 +4668046451 +4044767571 +10647287885 +4188164631 +4026358937 +4092404631 +4161781880 +4713687302 +4737423700 +5337969501 +7592976980 +6522118514 +5569595090 +5618235469 +6472825226 +8254186511 +7143529119 +7114253914 +7550899088 +7487601236 +7592718154 +7611126788 +8232932202 +8010898808 +8071126508 +8118763568 +9382737072 +8188140817 +10283282392 +9710640100 +14601855150 +8875469182 +12042420316 +13169134557 +10907564591 +11187830559 +12091060695 +12683849004 +14483724034 +13587079140 +14257783033 +15038500324 +29640355474 +15080319390 +15498500044 +17876000546 +15622025596 +16082025316 +22044603739 +24153151824 +19666019464 +43227434614 +24133481011 +18586109282 +27167573038 +20063299741 +19783033773 +29918420862 +22095395150 +22998625286 +26226330883 +24774909699 +33253098604 +28625579464 +27844862173 +29296283357 +30118819714 +30578819434 +36145325057 +31120525640 +31704050912 +34208134878 +34668134598 +38252128746 +38369143055 +42719590293 +39846333514 +66214005228 +38649409023 +41878428923 +42158694891 +42781659059 +54119150926 +61250754032 +70353459935 +51001240582 +63371918318 +69398423661 +81150802114 +61239345354 +59415103071 +60697639148 +66724144491 +99491474100 +103117774277 +65912185790 +85501249352 +95918888630 +166652051466 +120031336716 +122490099386 +80808103914 +84660087982 +102856334039 +102576068071 +130096062809 +108693844849 +150206527575 +142058857946 +110416343653 +127421783639 +156616527778 +163815413425 +180642276214 +120112742219 +125327288861 +169841918768 +244915191985 +146720289704 +414757110753 +229727599215 +165468191896 +183384171985 +187516422021 +183664437953 +200920846133 +320048446343 +205432402110 +211269912920 +237838127292 +228806587068 +235743632514 +296926817279 +372336975624 +230529085872 +245440031080 +333657332193 +565488477423 +441176034624 +266833031923 +272047578565 +686091226609 +375526876772 +312188481600 +348852363881 +370900594006 +349132629849 +367048609938 +406353248243 +412190759053 +435961487982 +459335672940 +540995068668 +474246618148 +464550219582 +818544007296 +785094117831 +475969116952 +497362117795 +502576664437 +808468302789 +579021513523 +621180208414 +584236060165 +777253842249 +718541729843 +716181239787 +661040845481 +720033223855 +715900973819 +737949203944 +761323388902 +773401858181 +842314736225 +848152247035 +910208106130 +923885892522 +967126884019 +978545781389 +1054990630475 +973331234747 +1163257573688 +1081598177960 +999938782232 +1086812724602 +1685668613862 +1200201721937 +1205416268579 +1639226690640 +1376941819300 +1377222085268 +1381074069336 +1398990049425 +1580263940169 +2138545474170 +1923912914185 +2033536411864 +1615716594406 +3254943285046 +1758360353165 +2355767866657 +1891012776541 +1978484563621 +3732989951925 +1973270016979 +2458539997260 +2839428412577 +2604406318004 +2086751506834 +2287014446539 +3359558632957 +2405617990516 +4977973886747 +2776212134693 +2754163904568 +2758296154604 +5819741458759 +4835207225215 +3195980534575 +3736844916786 +5706259968904 +3374076947571 +3506729370947 +5212703901828 +10541467194119 +8578037613363 +3864282793520 +5169250551554 +5654520531835 +4060021523813 +5534508289297 +7256002058388 +4373765953373 +4492369497350 +4692632437055 +5159781895084 +5163914145120 +7754186021440 +5512460059172 +7238359741091 +6132373102175 +8675979922501 +8896626811870 +9271353206083 +7924304317333 +8199361808002 +9161249902782 +7371012164467 +9533547848457 +13589259248925 +13266646080612 +8238048746893 +8433787477186 +13221271426595 +9185001934405 +8866135450723 +9066398390428 +9656283642470 +9652151392434 +17618789411591 +16650812833310 +10676374204292 +11644833161347 +12750819800263 +13370732843266 +13503385266642 +15295316481800 +18051137385128 +15570373972469 +17027295806937 +25856838158484 +15609060911360 +17932533841151 +16671836224079 +17104184197616 +17299922927909 +17304447137321 +18251400324833 +18518286843157 +18522419093193 +18718549782862 +19742772594720 +19308435034904 +28359880711623 +33621511357597 +22321207365639 +26246748176761 +27253894072707 +26121552643529 +35313146567189 +29112446178002 +30865690454269 +32242210196548 +32674558170085 +33699132031016 +32908983839269 +32280897135439 +59030536482798 +44765035019918 +34404107125525 +50760497039705 +35555847462154 +70868994029343 +45864325238249 +65583542009354 +38026984817766 +58402449778968 +64073470054822 +48442760009168 +48567955542400 +49575101438346 +52368300820290 +61787004348087 +55233998821531 +63146587589708 +59978136632271 +66685004260964 +64916768366633 +65980029166455 +81476939381669 +68464831301423 +112346437452561 +69959954587679 +80268432363774 +73582832279920 +110229764357255 diff --git a/aoc2020/input/day09_provided.txt b/aoc2020/input/day09_provided.txt new file mode 100644 index 0000000..28d66e4 --- /dev/null +++ b/aoc2020/input/day09_provided.txt @@ -0,0 +1,20 @@ +35 +20 +15 +25 +47 +40 +62 +55 +65 +95 +102 +117 +150 +182 +127 +219 +299 +277 +309 +576 diff --git a/aoc2020/src/day09.rs b/aoc2020/src/day09.rs new file mode 100644 index 0000000..4a91a22 --- /dev/null +++ b/aoc2020/src/day09.rs @@ -0,0 +1,130 @@ +use std::fmt::Write; + +use aoc::err; + +const INPUT: &str = include_str!("../input/day09.txt"); + +pub fn run() -> aoc::Result { + let mut res = String::with_capacity(128); + + writeln!(res, "part 1: {}", part1(INPUT)?)?; + writeln!(res, "part 2: {}", part2(INPUT)?)?; + + Ok(res) +} + +fn find_pair_sum(data: &[u64], total: u64) -> Option<(u64, u64)> { + // on huge entries using a set like in day 01 would be faster, but here it's actually slower, + // probably due to relatively small input size + for i in 0..data.len() { + for j in (i + 1)..data.len() { + if data[i] + data[j] == total { + return Some((data[i], data[j])); + } + } + } + + None +} + +fn find_outlier(numbers: &[u64], preamble_size: usize) -> aoc::Result<(u64, usize)> { + // start checking numbers after the preamble only + for i in preamble_size..numbers.len() { + let preamble = &numbers[(i - preamble_size)..i]; + let curr = numbers[i]; + + match find_pair_sum(preamble, curr) { + Some(_) => continue, + None => return Ok((curr, i)), + } + } + + Err(err!("couldn't find number with that property")) +} + +fn part1(input: &str) -> aoc::Result { + let numbers = input + .lines() + .map(|line| line.parse::()) + .collect::, _>>() + .map_err(|e| err!("couldn't parse number: {}", e))?; + + let (solution, _) = find_outlier(&numbers, 25)?; + + Ok(solution) +} + +fn find_contiguous_range(numbers: &[u64], total: u64, total_idx: usize) -> aoc::Result<(u64, u64)> { + for i in 0..total_idx { + for j in (i + 1)..total_idx { + let range = &numbers[i..=j]; + + if range.iter().sum::() == total { + // it's safe to unwrap here because j > i so the range always has one number + let min = range.iter().min().unwrap(); + let max = range.iter().max().unwrap(); + + return Ok((*min, *max)); + } + } + } + + Err(err!("couldn't find number with that property")) +} + +fn part2(input: &str) -> aoc::Result { + let numbers = input + .lines() + .map(|line| line.parse::()) + .collect::, _>>() + .map_err(|e| err!("couldn't parse number: {}", e))?; + + let (outlier, idx) = find_outlier(&numbers, 25)?; + + let (min, max) = find_contiguous_range(&numbers, outlier, idx)?; + + Ok(min + max) +} + +#[cfg(test)] +mod tests { + use super::*; + + const PROVIDED: &str = include_str!("../input/day09_provided.txt"); + + #[test] + fn part1_provided() { + let numbers = PROVIDED + .lines() + .map(|line| line.parse::().unwrap()) + .collect::>(); + + assert_eq!(find_outlier(&numbers, 5).unwrap(), (127, 14)); + } + + #[test] + fn part1_real() { + assert_eq!(part1(INPUT).unwrap(), 248131121); + } + + #[test] + fn part2_provided() { + let numbers = PROVIDED + .lines() + .map(|line| line.parse::().unwrap()) + .collect::>(); + + let (outlier, idx) = find_outlier(&numbers, 5).unwrap(); + + let (min, max) = find_contiguous_range(&numbers, outlier, idx).unwrap(); + + assert_eq!(min, 15); + assert_eq!(max, 47); + assert_eq!(min + max, 62); + } + + #[test] + fn part2_real() { + assert_eq!(part2(INPUT).unwrap(), 31580383); + } +} diff --git a/aoc2020/src/lib.rs b/aoc2020/src/lib.rs index 9ac735a..a8fc1a9 100644 --- a/aoc2020/src/lib.rs +++ b/aoc2020/src/lib.rs @@ -6,3 +6,4 @@ pub mod day05; pub mod day06; pub mod day07; pub mod day08; +pub mod day09; diff --git a/aoc2020/src/main.rs b/aoc2020/src/main.rs index af9cef2..9208c5a 100644 --- a/aoc2020/src/main.rs +++ b/aoc2020/src/main.rs @@ -9,6 +9,7 @@ use aoc2020::day05; use aoc2020::day06; use aoc2020::day07; use aoc2020::day08; +use aoc2020::day09; fn main() -> Result<()> { let days: &[DayFunc] = &[ @@ -20,6 +21,7 @@ fn main() -> Result<()> { day06::run, day07::run, day08::run, + day09::run, ]; aoc::run(days)