diff --git a/aoc-solver/src/y2023/day17.rs b/aoc-solver/src/y2023/day17.rs new file mode 100644 index 0000000..86e70b2 --- /dev/null +++ b/aoc-solver/src/y2023/day17.rs @@ -0,0 +1,258 @@ +use std::{ + cmp::Ordering, + collections::{BinaryHeap, HashMap}, +}; + +use itertools::Itertools; + +use crate::solution::{AocError, Solution}; + +pub struct Day17; + +type Coords = (isize, isize); +type Grid = Vec>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +enum Direction { + North, + East, + South, + West, +} + +#[derive(Clone, Eq, PartialEq)] +struct Search { + heat_loss: u32, + position: Coords, + direction: Direction, + consequtive: u8, +} + +impl Ord for Search { + fn cmp(&self, other: &Self) -> Ordering { + other.heat_loss.cmp(&self.heat_loss) + } +} + +impl PartialOrd for Search { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +fn parse(input: &str) -> Result { + let grid: Grid = input + .trim() + .lines() + .map(|line| { + line.chars() + .map(|tile| { + let heat_loss = tile + .to_digit(10) + .ok_or(AocError::parse(tile, "Invalid tile"))?; + + Ok(heat_loss as u8) + }) + .try_collect() + }) + .try_collect()?; + + Ok(grid) +} + +fn directions( + direction: &Direction, + consequtive: u8, + min_consequtive: u8, +) -> Vec<(Direction, isize, isize)> { + if consequtive < min_consequtive { + return match direction { + Direction::North => vec![(Direction::North, 0, -1)], + Direction::East => vec![(Direction::East, 1, 0)], + Direction::South => vec![(Direction::South, 0, 1)], + Direction::West => vec![(Direction::West, -1, 0)], + }; + } + + match direction { + Direction::North => vec![ + (Direction::North, 0, -1), + (Direction::East, 1, 0), + (Direction::West, -1, 0), + ], + Direction::East => vec![ + (Direction::East, 1, 0), + (Direction::North, 0, -1), + (Direction::South, 0, 1), + ], + Direction::South => vec![ + (Direction::South, 0, 1), + (Direction::East, 1, 0), + (Direction::West, -1, 0), + ], + Direction::West => vec![ + (Direction::West, -1, 0), + (Direction::North, 0, -1), + (Direction::South, 0, 1), + ], + } +} + +fn dijkstra(grid: &Grid, min_consequtive: u8, max_consequtive: u8) -> Option { + let mut heat_losses: HashMap<(Coords, Direction, u8), u32> = HashMap::new(); + let mut heap: BinaryHeap = BinaryHeap::new(); + + let height = grid.len(); + let width = grid[0].len(); + let target = ((width - 1) as isize, (height - 1) as isize); + + heap.push(Search { + position: (0, 0), + direction: Direction::East, + consequtive: 0, + heat_loss: 0, + }); + + while let Some(Search { + position, + direction, + consequtive, + heat_loss, + }) = heap.pop() + { + if position == target && consequtive >= min_consequtive { + return Some(heat_losses[&(position, direction, consequtive)]); + } + + if heat_loss + > *heat_losses + .get(&(position, direction, consequtive)) + .unwrap_or(&u32::MAX) + { + continue; + } + + for (next_direction, dx, dy) in directions(&direction, consequtive, min_consequtive) { + let x = position.0 + dx; + let y = position.1 + dy; + + if x >= 0 && y >= 0 && (x as usize) < width && (y as usize) < height { + let neighbour = grid[y as usize][x as usize]; + + let next_consequtive = if direction == next_direction { + consequtive + 1 + } else { + 1 + }; + + if next_consequtive > max_consequtive { + continue; + } + + let next = Search { + position: (x, y), + direction: next_direction, + heat_loss: heat_loss + neighbour as u32, + consequtive: next_consequtive, + }; + + let best_known = heat_losses + .entry((next.position, next.direction, next.consequtive)) + .or_insert(u32::MAX); + + if next.heat_loss < *best_known { + *best_known = next.heat_loss; + heap.push(next) + } + } + } + } + + None +} + +impl Solution for Day17 { + type A = u32; + type B = u32; + + fn default_input(&self) -> &'static str { + include_str!("../../../inputs/2023/day17.txt") + } + + fn part_1(&self, input: &str) -> Result { + let grid = parse(input)?; + let total_heat_loss = dijkstra(&grid, 0, 3).ok_or(AocError::logic("No path found"))?; + + Ok(total_heat_loss) + } + + fn part_2(&self, input: &str) -> Result { + let grid = parse(input)?; + let total_heat_loss = dijkstra(&grid, 4, 10).ok_or(AocError::logic("No path found"))?; + + Ok(total_heat_loss) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_solves_part1_example() { + assert_eq!( + Day17.part_1( + "2413432311323\n\ + 3215453535623\n\ + 3255245654254\n\ + 3446585845452\n\ + 4546657867536\n\ + 1438598798454\n\ + 4457876987766\n\ + 3637877979653\n\ + 4654967986887\n\ + 4564679986453\n\ + 1224686865563\n\ + 2546548887735\n\ + 4322674655533\n" + ), + Ok(102) + ); + } + + #[test] + fn it_solves_part2_example_1() { + assert_eq!( + Day17.part_2( + "2413432311323\n\ + 3215453535623\n\ + 3255245654254\n\ + 3446585845452\n\ + 4546657867536\n\ + 1438598798454\n\ + 4457876987766\n\ + 3637877979653\n\ + 4654967986887\n\ + 4564679986453\n\ + 1224686865563\n\ + 2546548887735\n\ + 4322674655533\n" + ), + Ok(94) + ); + } + + #[test] + fn it_solves_part2_example_2() { + assert_eq!( + Day17.part_2( + "111111111111\n\ + 999999999991\n\ + 999999999991\n\ + 999999999991\n\ + 999999999991\n" + ), + Ok(71) + ); + } +} diff --git a/aoc-solver/src/y2023/mod.rs b/aoc-solver/src/y2023/mod.rs index de7ccd1..35acd19 100644 --- a/aoc-solver/src/y2023/mod.rs +++ b/aoc-solver/src/y2023/mod.rs @@ -16,8 +16,9 @@ pub mod day13; pub mod day14; pub mod day15; pub mod day16; +pub mod day17; -pub const MAX_DAYS: u8 = 16; +pub const MAX_DAYS: u8 = 17; pub struct Y2023; @@ -40,6 +41,7 @@ impl Solver for Y2023 { 14 => day14::Day14.run(input, 14, 2023), 15 => day15::Day15.run(input, 15, 2023), 16 => day16::Day16.run(input, 16, 2023), + 17 => day17::Day17.run(input, 17, 2023), _ => vec![String::from("Solution not implemented (yet?)")], } } diff --git a/inputs/2023/day17.txt b/inputs/2023/day17.txt new file mode 100644 index 0000000..9b422e1 --- /dev/null +++ b/inputs/2023/day17.txt @@ -0,0 +1,141 @@ +451523623316565623432622127257125712232367331521342225652611642316141624136152463732561551372631215312674332236746737356445314356414212616122 +131111312563542645151356721441546464555716523647724713614256756747842552485677444676614327572121711163626437457733167454462421341533136414653 +525454362235152362613613166675325577624425567562435612113577573237548842284324568833347432434356357525641342731616512267425551124621322366433 +453621463366222641245457744462611264222536513441615752884586855868327537655685623633542855335156625673761262355113167334223564652643446236246 +453266352353615445543743727743375646657225562553637678352724524556566868283582446743648766737565643756164326776755716364362241241362232252652 +451122263353224214323273367441713751643141441733885737585846346828375837678756267388268388226754457555414372365517131123514261566362641545615 +441313663646254217464221666555464221112477642445326533457735764833755428482728685564677277523326785227655677747463147365237116151641444333363 +522554551161642675362351435267157423357667265685856428553357838342554675545778768867285328652375622656252223755422631261524657264251434164354 +241233645231456376646623375477752316117484632782648382765846572778285255385558432454642236253884655832533374745325516756562372651263651226651 +414551141653254561246546636551272266347474564633653568736374267868828387228482455554726786427776588565876631144517131235474451637545244225365 +263151616625463134577367272141477372835227685486542825453363548875368275737575426448738852676577836845356534332327751273333774543244335564363 +532442555433462476112321642542565126257785787275688834643282865348648363753874673273627674825645868488288758241567421314177455311432161613643 +664145466633771652243617231663734828737447633528544728482628735655224382526267355625734488758862824374528574275143552476514215113213523141562 +135113522262127627373261516332275454854354537838625452776326576538623457844528882844775742572386387328473584434512471525263266634363265213341 +161325352221221513322127772457632687365686356343227773732442347837734636833285587774683525836428774688422742287267616151356467176446125152155 +654163116754653461421226725657557238477267586752324884554568663246938556657634848887772778366682624332574548774728366273334371133325654556264 +633341527421357526142567251757265236344844757478665254547634396884487794748886388443763788878556434362633226676372333636263166434726263221611 +244542652552514543642125675332458682325587478375278446635749374777363555988357574565934337572577838833865677785278273344166257523755455264415 +155412573416241252313344238543637565763473328462478764856976967949334565633734888865588966362268646263635243548358366756352223745652252767313 +311436267523172173526136462584564382884644748777873554747336666687857539387676737967388833984684732826446863324747236323366576164357464743622 +311612117312647746333427838584553584342338825323347834937985835579647497455736575874496393388689386334852723854576336528667167176645574136351 +441155232146372744476478525575366383833366343848438855359935334337553758793658495837844435343665485744428428688325363825824267131313753254323 +637422675616372175515678558777486322535872489894946586933448963497646633893866869967758637948497988955628637383284536757737742621325245623135 +644317322665241341215268387637378326582423679637585546553888456456377569498458856997555537476358584566347287868478434276835545136434165245671 +121133365244732427756784233443723788823473353534374769736358594538975653739666558859378443348746549365544873768537546448357735776316245762643 +475116636266424357348658744728823254858839753745679363767536585574948464738948755779789633943437397734597836248265834232535623712426333635772 +615557253664251437727675474366852384444436499984998776949373475767948944775463964836567854637996344774959686466544345755522475541223242666576 +741164731777317786257472583244344744989943878499978386983475765476646595593678646893377563637894465643593347223763327456478624617157327173235 +122516527571367765586374256548626234893576795335879845575968399899584849736353958769838873645986683773364586226773543386667878521521634544242 +665351261322165855634432437683546433988347667435669667774956477544544967474688537988578358885775988748338779487423335854638437826445331411362 +526267342177122755868365838646678337445386764537787858496545795585798695696676556633587358849396457687446837796256553576563834626126152341154 +476762522772788887224382785885276544365837698797733768738745476768689669898948898889484357356476633565558466468425843728687268855675663212474 +175253624231288356446748288787286666877997745868354688475465949678989764847654865878867687496444495754694376377757434864578755738347242262413 +272262146763767584343873876524437347354746466657364485859598789978448868449694449657564445753578398746846336434695658535265443283766564765435 +555113546156342337736245382733543545793547586499998745999876656494775776648448657754666548966675455739695565585696437863436738428252763225274 +753475772752878764568247766234965633765897556864448869798998947875564955875748498794844565599568486457859396639678722586253465734357566741456 +111324627186877645864657388895685475957484434545599858854995988455748778546665454797789898486886997898334774933639333482734277268242825477442 +273732661368226453845454284874937696374346859744574486679579448548585894968555978997469774785547969978755759555789744727782422782745844131267 +525367264864758678453348669985653369699388537485989557567468995566946849467764897798579445549546655753599799979964963334474834732786833536641 +671225624255676882582733345986973658557363687876685694856865969597868879966488699886598676956595969996393454766835996558547627683656276335151 +344711468522744626336583748384836453356653897547444586457894555859698898867859496695875979894764449433363637546593599665373575254376628635722 +426575416484224536533666367675337335993754488575785845884555748759477988578475884598566797479954666468967867359764977355833764722672368576621 +353726772855758622234244939495573988447698554564475678778876787547567469666457798694867868668458449564756796764785483764273424524283555366613 +336637426846365577274453587887444443638855797489646654946687447797965575569684578465557758694995954445746865776663384376626737885447774622133 +315155247837723228448587899869586665347797964875575456484995967678659558675576697479596456874685479455767437475754339355765322644772788321632 +371676237638444444374598453836365753858989567896687464759954559958556966689659689955746889749584449894956957754768797898952623258836648742145 +443365546482286726475736643784383388987488656669949756966999778665975666799886998685669579777886494759998733788783395573535865775353452568255 +272648247588827844567653756634753395989849854667976447776758798868756897566876667966969789555859967797954567775536595798836658563388274736224 +731335253433877768425965857754358769747856797544467675599765665958778779657975595995779896769768665548654744764783375499496747287483355553664 +114568337588588578343338654337668479886959667795844857769675755989867798787767956996966767487989688686968765779988794666648576358786675643336 +473427658434255435486597736796677579958957996978747785686597677667857667867655978978656555689944544867779887775467789944757442434535622547355 +351788366472428822295354665835974774655696547749484478597876699585588578885558559688875589898996675596479987669747938358859864362768635333735 +514767327432623888374453685546539957499698589459847677875795756897678879969979679595899958557784457858468989577844539393379688785358764824424 +456743787867385852646495436583573649777649986577986998789569595685967697899776966868596757866675768987987649543865434746643744552543565437526 +377253442378645847736333998395853486484757765958769785668997977798567759888798787685768585955885898868649777787564739635745757666336853843281 +522746843784253259783843667836978845458698788968696865897785857776999667678567558559578667885694866686664465994764757848839686375365347344283 +453267623427475736758784976638859975486546787858678556888869566986976997777755568897867667879587896774596789795777557446597335728785822873277 +755446653587532687733944458396989698865944657655797775887557679798687989779875568879576967766658745997846544485985387537563995583425663377645 +763447738265737739578596777654875798845899756995885889779887669888968877896678697569558975989669987647975479978934648868637786656535348527335 +477483775443562467663767539743468669695485775486686985597659777586786998978979988857795786968785866747994789658664646879574733584246633372544 +462848284436475333434489649384489889778887846559656696666769555677769866678968968795765698595799758576568556456957833434783847977242426386476 +448645734386766635344348686589598855675947848585669857795556578966796966987678879598756789758985696945445484648968353346856888848852374233638 +153874425435652634893357735955584896469495774589678568898985787668997989688887977869557985796898988865584478444847645588597886432282284536853 +256658435648566555894444435897549668858548855758597785799855987898869868968897888665857887598586855464968744594465553743769436956735343435762 +325643283843853893994745348646688684547867448959965555687678988997986969998788867789666567689889967486955568599979579783366574892363568366768 +435453323628335584684478887466956674978568756858867967979788867986889677776778867977668786958799575568445957446946768735938365366847683885338 +258855876267652354576946733798695795965487499897669575696589896698889786776968887686878775668655665768799889956479393398564383498464274222554 +556266743628226543533789699955854576458849555779687979876886966679698779887976889998785795856569569749988856564687344499599579654728373632823 +583522268838867797474483737586684474659848578887597885996997869977689979988867778667757566688889559999696969454565537776366957566784428322322 +443726634548653954659438463678477764684575887959859796976776887779776898899766889896677879767978766548657898597459794385975478558238623334324 +346677336678334584986588763498565564857594468575896687797679786796697887997787987878886778956958778765654789696476674559863646376342264282576 +145355477448886994578339597969979648865645869985885578885776698697997769679666676866965696889786598594678658756588576366435756338663747644558 +246885523744564973863995435576967976875999896689769679675878668767776669897666789978887767886658575577684578445666739996934355633458287582768 +472572265837547494843794466944965978754979455989999788959979988797866679788669887668757558999689666994586488498599644757965999982842836463782 +425333486653642893644387485387455485974686867665767969866976998767879966966769766698675589858759986588584998454988757677983668893572825373842 +643538476443352433937584958839858556955449476658697799586899979788867899987687997986657878999659758995685498694597879766559984336228388634336 +273834764262457889656335577655855576544548747559959568876698869777999866677888897966968879677999567957974794555544838337367647948266584326255 +775485527327645848438769346979898984999895759755675697996799996776688887676666879679767886758678788664857475695487784833338457693752786433467 +185523566433248363337833335747674687588687766658869668858997888879679989789997696989567885555799666689994546897648633994895368777267288382433 +323837348878522334449676444984555744954956857888788756958698989877999778969977779898568587585657889769987674647994564665989448958685488766262 +483246776375334779788458484856999457645847849687876695699856568699889766878698969769968556675995575777695588789885383645937857733533682866732 +124282746478664367353433589864868698545449646858855558588568986898786978998669668958675799567885759756858995949994755779466967957365545226688 +742767626527844738567865434857998858949447575959575896865595597879696988767778865985968599758688895448868676748954694639777477974342733328325 +215755476368637888685859698579576869745876669899766896899887989589998667769797785786867699786559966897745994776746579437939799877872274845583 +376323667353682699383839735633886659644958778466665965555955858666799689896778798787678897776889669846955974968984358856435454763625422824342 +323563276388567889387785644357948878458845785978787596868978556856576568796587795578976955966567757657857769957988736535454787823366246723843 +416545832824576639946436586449974694996496888474959895689656567667668696576555555659667778699867456949694557694955679887686994687566777768836 +775834744527685644698593744884439464685989788967555666979755897997659676995595885868669956559855984685855997475638453587349967742434836873873 +737773866633576228437969785875694974495747878848895689959769995559968758666966755567775899887659956987758967997767635963977852685323358582242 +544546662858758735558694466544487896784759476957686869968955657567987655776996767599768876658568946486988565464888489969344373577634473686273 +735863354626654233944666348994799349686567748668858967989985559566679858786868565595967597998678567465547549546948983557867363885864784652667 +256442652834663662677975677459443749965469499789844967585596798767998688787598689588596989788789699445597768757583995643893862345328386463827 +324126585443854528577996773375365696755596565556795945575967576755896599667666765578877597464647474689587474498444846774638964255888578547524 +575164824467825438437366983397735889455955659795795955565567988889755886778588659895685975898586979885554886369339999749758963265726332845767 +321555866445726273748633435757893885994548488864589859888568755778578875667967996759955769776984679859795483444484887763899836633343235352737 +137344736887354732338798779846879389696966776546978868556585965878669659889696588558965857464498764764759433464477894859798826257457323335625 +614114567538523557352946855596887835597577467449787786746875585757778595898689958895869567889959674678845475857586839648898632642787823452216 +747222584274766677728899576689956494739584978848654685754565558568676597977699798555446788497998579558668355966469368438336733346374584243152 +567456264673633357356458439857839388558747694874587996877787766689669688878765599678454547677467888947495476776874678398658646772854737885522 +567723182852662323276568736693536447736557788455977954446784997898978969979744988664678968799689446954896377444575537739482332843244545475722 +375574168272748425746243969385734353686485948695844785699568466998679545456646594568476554957594556674483374848543387489464783237322722873523 +532623624378828362872472349837499766746835449788884586999486885584589565447787548787699597745956886878639986637484386846724862562762686763643 +545441767257587868285374837995684947664755657486645696954785695887785668744678957444864865868679678769455846798876967956466766327636327353122 +734637223265622633468364848386788647489476745546759547747689489694844454584884958999967578544496496388793989774336866876238733857644832522525 +425611321548585554742435348535479474388439837866565797984899868448688588477444548997599588555554999684934885797963474478842268776755274321341 +642773235735463878875525384458968796746436749587887468497555577847889785588896784985875554876877993359849697889784837565638733585738457243154 +756613611658376287237552225384453936587693757743786474967997696774484994984549799665767878845443386934375385983854635658475765665873862142141 +351575315323762744486465747684588438854746987563894896877745877765894697956464979549759998448674984383855596889678855865443382538563767323767 +254353116336236838442444332465889884978666489497638777468499647746854846999785454465885696878684346587555995498963588765833246454782271463335 +165165212276385663256436367288997569977939665899754584578985976985485775754697848778458977593649473779354765486743264357384786458676672751431 +131252216474684888433256524274676987459955383535473658994955444587476587749944554946566647564498788556547934589763486483735325283752441663317 +612464415511647328788388232687568686743759773456874356945758678687665558748446447446664763895558399578864844865335856827586535335263372127447 +341173126741462324368426285783445535365979657757943973699735988446475867465898955739857656398449565954664758786667584365374377642435534724637 +314133652236153733383354627545448498576338353737953785755899435853874774646484487935875675335434999373985894783222878576455485524574476217421 +741545513654126463324748388886345375473548833934696943449385759653586533588636974885848787679543637486686887737527228352685246283416231214673 +567262325414571427644425456858245572588749483698463463958587763788737484776693973555857577566795658943575774277665822258748622222531247774654 +271477642534255664285233246383437454366433343564855993373955449674659767744799764684498956475368437454746776252288868246228378542437346545556 +751521172274662333737857333667687253788777439849894854997989668585588868388359938548639338687347938777695588852573886368477346437635112611525 +422721432632421432457544835327765242638535868637536494444347755333489749488838584759379463978956868687842757763487347683488312646671134611327 +362177766617157632775852578866852866426562846646638765787747738468369958373684476599947944567494758754653337736527237272484525425262742752652 +426577765262711444531843822256362844468554746498488675579848583697589595873657449895638989899555998662545287674428855743283541337636623717442 +566437716575232363614538546422348524658267887379866379559549469989676958495556664964573373439887464438735667227577426872452333117136163457472 +335376326734331551651642837477528553437247584227857876767647973536758899499944347598774778594873563528427536644737586834723743552563364277543 +363651514632323444231675323866858438655877527378746966747746686869447485974565844799793487984366722343335755837242266541732317434536714246211 +363561337473555152127357274434237385588826856762432696688466943976999559437585767566765993723674268576583263577376268823116742127736614534563 +554262123524124343312752648887668288438755244682754825436756586794954443746677356948994553332554364477743776566668627644416625311225552123653 +255132367547234347424372176543855452355684636622485772787763588944736833893885739679475536672642633788742453674853655356725746336166642765334 +541422545262231424513512246466244688755433454856823587755866534758886869659549454872677453422248665232742688885587553327435616664227573236233 +634552366313631321265476124611677565528225364777224528567277783256532532582665578534427233684827762852875757455337323547127744175721415211316 +455231426514574162374274745653582365277623876777256787722563755522284476777343857258535827484224375278445386345841252337421665373265443322351 +626511266535277543473637534444333534654587627257658348566885387644432547263386722748886827628567443485628335784371255647433172542326513461141 +542366552565541136313722327321257267854776745234423888282353753744876676574846336523663862838435635754233722517224512623167217747364662256513 +111114245346241772364755424333371233867578842763267878725783488322268886373542756856636452354873644675574561651411211777137657257744612234234 +356655432663526332424341351542236527733545353758768777467434644372866265372883436368243448864632852664776242755137263754332536743616534123452 +135632631545522266764264477451632442653342826357675822577852346278324486267276567354772538266652664784733422122222342126737237134441553421235 +241336366551516452522247775552723313166626354862355772236378228647666763735347273544446826377244536667575121427433261573234554213443532622635 +524333165342516561361165622424421544755144646523862382237878648463577565322566368486485858333678425657643232313727441415341674254331124535123 +432121354515234552615645566237115722361166761675477252624478845753556337487377238368764867654442672766667616133177553456447453636425241413466 +454332442353514342431662664146323314717631534717533277352475325637437373456532885283257434724867451777556164446646727663466542331656442553351 +615535564233515625364634257755177655124461253262651335448838425268544282746885834268468253261441546147467527174132757753654151525235164444536 +211325621226241546525365164421723671464374433556556637667686224263656646223454877888882614433271551256144716616576331411712632515536463245133