diff --git a/aoc2021/input/day09.txt b/aoc2021/input/day09.txt new file mode 100644 index 0000000..3084053 --- /dev/null +++ b/aoc2021/input/day09.txt @@ -0,0 +1,100 @@ +8969799987646798965432975435334567987976999867976794468999979759865767896545699865678952123899325456 +7658678998434597654321984320123458976765789998965432367998968998754556789434987654489543535698912349 +6243457899325679997620195431934569765654667999993101246796856997643245679759865443356954656987894498 +4102345678912998789531297659895978954213456899874512659965239876432134578998754321267899877976789987 +3212466989109887678942989797659799542102345798765423867894103987543026799989866532345678999765469896 +4323487893299795489899978987947689654243496789876864988943212498654135999967987765466789987654398754 +5694698999987654398788967895434589879359989999987879999994467598795276789756798876567895699873219865 +6788799998998975976567456899598678985498879898798989865879978939876987993145899987879954598765102987 +7899899897989989875432345678998789897987968799659197654756899857989899921034999898989433459854213698 +8913998766779999964321234569999897789876754678943296543434998769997797892129898789995321298765434569 +9101987655767989875732345679987946689654343469764987542127899898765656789298797678976510159977675678 +3212396543256878986893478999876434596543212378965698321016789999854245991987664599987621245698789789 +5433495432145767897954567896985423689954301299986986432125899998762127892976553469998753457789899892 +6567989543023456798966878994597434567896212989897998764234678987654679999897432348999864567997999953 +7699978932124569899987989789986545678997329878798969976656789998785793599789645667898965989456789867 +8988767993237678998998995678998698789865498765689654399787898999887975987689956788977899992398999879 +9976458789398899687899234567999899899978987654569543219899956789998989896579899899866458943989109989 +9854345679479976556954346788998999999989876543468965323987548999969498765466788956954367969878998797 +8765456796567895434699459899996878998694987742556896439876439999854329654354567899875167898657897656 +9896577897679966724978998943985456896513498651345689546989998898765439843212456789984356789346789843 +5998678998789653219866987899876368954323489710556898768998787789876898756533568899995679891245898932 +4299789349898742109654346798765458976535679921237999879867546678987989987654679978976789910234567891 +5989894234969876298743234569878567899796798545346899998653434569399876599785789567987898929345688932 +9878943123459865459652127999989678978998987655456789129742129679210997679897995456798987898957899543 +4965431012567986798764335679598789469899998767767891019843298999429698789998932348899876767899999654 +3986949143479997899865466789409892346789979879878992123969976578998539997899321467999765646978998765 +2399898954567898999876567893219921235798766990999789235698895457997623456921932346998654334567899978 +1299767895789999999987678999398633896899954321235695476987789598998735797899894459876543212456899899 +2988956799899998989998989798976545789999896532346789569986679679439987898986789667987654201268999798 +9876545788987887679899897657987656798998789987656799698785458994321299999575678978998764312349987677 +8787434867976544556797623546698767987887678999767978988654356789490123985434567899799876543456997536 +9643323456895433545679510134599879876765567899878969876543234899989349876423468976567998954567895215 +7432102568954321234595431235678998765634345678989456998754345987879956994312469965456899996789954324 +6543212349975410123489545676789769874321234789790365679976576896567898984203457896597946987898766534 +7695323457897521236679686787896656965454345689621234567987687932498959876412679989989532498939878745 +8986445569998934345689899998955549877965678796542347678999798940989942986567897678978901359012999987 +9997556978969765456897998899643435988876789898753456789999899759878891987879976564568992459223989999 +9998967889349876577896767789532123999998898999897598999988959898767790298989985323456789998939878998 +9879878993212987698965656679921039876439967899999979899876545987656689349896546012367899876899767987 +8867989854623999999873245567892134965323456789998765789987632496545459998765432123456998765698959876 +7656799769539897895482133456954379854212597993987653999898521569632367899979643236567898754987939984 +9545678998998765989321012567895459763102379932199654569765437698743458932398654387989987543656898765 +8936567897899874578932123456976598765213467891034987698996548899654567891019767898999876521246789897 +7623468976799765799543438967898679984324579932123498997989679998765678942423989999978988430134899998 +5434578985679878997654567898939789995445698965349569876678989899876789759994596598769877321475678999 +6559689643456989298775678999029895987576987896467978965457899782989899998789789429898765432386799989 +7798789432345690129976789998939974599999896889878999784346998651296989876598993219989876743457898878 +8989895431258789245987899987898953459878784978989989653245696542345679999457894398879987857567947566 +9877987646779898659998999876567994979967643467899878964126789655456989998379965976569898967679434345 +9965499867895989798999598765476789398756532456798967893235899766967998987567899879456799298989321234 +9876789978954878987995459654345891296543101236987656789345678979899896798679998768345692129695433545 +1988899989763567896889698743236892989754752345698545678956799998789765698789876753238789234569546656 +3499949999874878945779987632123999768969643467899234589999899876578954329999875432124679945698756767 +9989237999996989234567976431019888943498955989998545678989906987689965410199764321012989896799999879 +8978956789997892146678986542239767832487996792987656789679215698896894321989875754123456797899989992 +7867897899989921012349597953398756721276789891098767896598924599965789939878996543254597898998978991 +5658998979876432124692398965986543210345996999239878965487895987654597898965987654765678949987959889 +4234789767987543235789459896798765321267894878945989874356789998783456987954599875676989657995349778 +2123679854987674347896569789999876543458943467956999995245894987632969876843456996787899969986234567 +3012568966998989498987998677899987754567892458969899874348943986549898765652345987998999898942123679 +6123456799879996579999899576789999869678943467899789965457921098798789854321234598949998677991014589 +5434767959767987898998765435699987998789765598923679876767892349987698765210349899659986566789323899 +8545679943854598986987654324589996689896986679013459989888999959876579894321235789898975345678946789 +7676899892123999875698763215679965456965498793223598794999998799975467965452347999987654234599659899 +8989986799019887654679974323467896568942349954334987653234987678894359879643458969876542123689898988 +9798865678998765712578985454598987979321257895455798852109895467789234998754569653999892012567987877 +7697654367897654323456798579689898989910969999579999743219654347689945679967679999549764123456896556 +3598765456998768974567987689795679099899898997678987654498653201567896989898798878934965236587974449 +2359987767999899765978998999964589298787656789989398765789765443489989899789897767949874347678953237 +1491299879999999987889459329899999987654745894590249876899899865679876784699976456899985678789654126 +0989901989789989998991399439777899898543435789931399987934999876898765633987895367899876799896543235 +9877899995678978989532578998656998797632124567893989998923498989999874012346789246987989898987655345 +8766798989789469878943789879546899654321012978999878999212997796799982178968992134976591997899796656 +9954547878992399967899899865434678998732129899998769899929876565689875357899843239899432395698989768 +7653235669991987856798999876215789987654239789987657789899765373499876567898765498798954986987878979 +8762124456789996543467894989104589998768998678986545678789876212345987688959876569657995999876567999 +9989012347899865432356993298913478999879876548995434345678968101356799799545987898745789865985456789 +6598924456895996421245689987897567892989998756789621257989543212456893987634598999658999654986687899 +7987899568934987840234567896789978921399899987898530968999964566567892396723679998767898953199789989 +9876798979924987656495888934567899210198789898987649899999898788689910975435678979878997899019899975 +7675356899899898767686789123679954391297698769999789799898789898799921296586789567989876798923989764 +6543245698798789879899899019789995989987569543935998689765679909899892397697994345698765867894578953 +8432136987657678999910998998998789778943468999899019789954234912998789998998943234989544556895678942 +7543239876543457989422997867997643567892979679678929899892123893989689789989432109875432347989989431 +8664345975442345678999876656789432456789895434569439998789234679876597678976543499964321235679894320 +8798459864321256899987655346896563567898789212497598687679345798765326567897654989984310199998789491 +9897568995438767898998643238987678689987679101789987543568996987654215458998775979996532987877578989 +9987679986549878987976543129998989799986568932679876542356789099873101299439989868987543976966457577 +8998790197678989756797643256899999899865457894569867421867992198764323489321098756597654965452323456 +7679891998789691234598765345678923989954366789697654320378943579885654678999987643469869876321012345 +4567939879896542456999975457789019878942134898789865621247894567986965699678996532398979876432123456 +3459329765998653567895986568993139765899012979899876732456789678987876896599989421297989998673234568 +5678909984329764678993497679954397654678923567943987654567997999799987897987678932986794569984545778 +8799998965679889889989598989795986543567994578992399876799236789654398999896568943975523679995656789 +9989767899789997993978999895689997562456789989989976987890145899876789998768456999854302368987789894 +9879356789899876432767898764789775431634578899879765698991236799987896999654397789763213459998993912 +8656244678998765321545987653459654320123456789767954019789445678998945898743235678954424668999542103 +7542133569899878510126976432398797431835668892456892124689556889329236789655656789765634569987543765 +6531012456789996431239954321239986545646799986587893776789678993210127898767787899879745678998955897 +6542123568899987544398765510123497656656789987678954567898799654431338999978898910989656789209876789 diff --git a/aoc2021/input/day09_provided.txt b/aoc2021/input/day09_provided.txt new file mode 100644 index 0000000..6dee4a4 --- /dev/null +++ b/aoc2021/input/day09_provided.txt @@ -0,0 +1,5 @@ +2199943210 +3987894921 +9856789892 +8767896789 +9899965678 diff --git a/aoc2021/src/day09.rs b/aoc2021/src/day09.rs new file mode 100644 index 0000000..3dd7c4c --- /dev/null +++ b/aoc2021/src/day09.rs @@ -0,0 +1,133 @@ +use std::fmt::Write; + +use anyhow::{Context, Result}; + +const INPUT: &str = include_str!("../input/day09.txt"); + +pub fn run() -> Result { + let mut res = String::with_capacity(128); + + writeln!(res, "part 1: {}", part1(INPUT)?)?; + + Ok(res) +} + +fn part1(input: &str) -> Result { + let height_map: HeightMap = input.parse()?; + + Ok(height_map + .low_points() + .map(|(x, y)| height_map.risk_level(x, y)) + .sum()) +} + +#[derive(Clone, Copy)] +enum Neighbour { + Up, + Down, + Left, + Right, +} + +impl Neighbour { + fn apply(&self, x: usize, y: usize, width: usize, height: usize) -> Option<(usize, usize)> { + match self { + Neighbour::Left if x > 0 => Some((x - 1, y)), + Neighbour::Right if x < width - 1 => Some((x + 1, y)), + Neighbour::Up if y > 0 => Some((x, y - 1)), + Neighbour::Down if y < height - 1 => Some((x, y + 1)), + _ => None, + } + } + + const ALL: &'static [Self] = &[ + Neighbour::Left, + Neighbour::Right, + Neighbour::Up, + Neighbour::Down, + ]; +} + +#[derive(Debug)] +struct HeightMap { + heights: Vec, + width: usize, + height: usize, +} + +impl HeightMap { + fn low_points(&self) -> impl Iterator + '_ { + (0..self.height) + .flat_map(|y| (0..self.width).map(move |x| (x, y))) + .filter(|&(x, y)| { + self.neighbours(x, y) + .all(|(nx, ny)| self.get(x, y) < self.get(nx, ny)) + }) + } + + fn neighbours(&self, x: usize, y: usize) -> impl Iterator + '_ { + Neighbour::ALL + .iter() + .copied() + .filter_map(move |neighbour| neighbour.apply(x, y, self.width, self.height)) + } + + fn risk_level(&self, x: usize, y: usize) -> u64 { + self.get(x, y) as u64 + 1 + } + + fn get(&self, x: usize, y: usize) -> u8 { + self.heights[y * self.width + x] + } +} + +impl std::str::FromStr for HeightMap { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let mut heights = Vec::new(); + + let mut height = 0; + let mut width = None; + for line in s.lines().map(str::trim) { + let line = line + .chars() + .map(|chr| { + chr.to_digit(10) + .map(|digit| digit as u8) + .with_context(|| format!("cannot parse char {} to digit", chr)) + }) + .collect::>>()?; + + if width.is_none() { + width = Some(line.len()); + } + + height += 1; + heights.extend_from_slice(&line); + } + + Ok(HeightMap { + heights, + width: width.context("0 lines parsed, width never computed")?, + height, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const PROVIDED: &str = include_str!("../input/day09_provided.txt"); + + #[test] + fn part1_provided() { + assert_eq!(part1(PROVIDED).unwrap(), 15); + } + + #[test] + fn part1_real() { + assert_eq!(part1(INPUT).unwrap(), 522); + } +} diff --git a/aoc2021/src/lib.rs b/aoc2021/src/lib.rs index 31b0d7e..98f8aa8 100644 --- a/aoc2021/src/lib.rs +++ b/aoc2021/src/lib.rs @@ -8,3 +8,4 @@ pub mod day05; pub mod day06; pub mod day07; pub mod day08; +pub mod day09; diff --git a/aoc2021/src/main.rs b/aoc2021/src/main.rs index 7d1b154..b94515f 100644 --- a/aoc2021/src/main.rs +++ b/aoc2021/src/main.rs @@ -10,6 +10,7 @@ use aoc2021::day05; use aoc2021::day06; use aoc2021::day07; use aoc2021::day08; +use aoc2021::day09; fn main() -> Result<()> { let days: &[DayFunc] = &[ @@ -21,6 +22,7 @@ fn main() -> Result<()> { day06::run, day07::run, day08::run, + day09::run, ]; aoc::run(days)