From 1520c8af9d38e89e1653438dc1c13683ad48b438 Mon Sep 17 00:00:00 2001 From: Acvaxoort Date: Sun, 17 Dec 2023 19:06:47 +0100 Subject: [PATCH] day 17 --- day17/Cargo.lock | 7 ++ day17/Cargo.toml | 17 ++++ day17/input.txt | 141 +++++++++++++++++++++++++++ day17/src/main.rs | 115 ++++++++++++++++++++++ day17/src/main_visualization.rs | 165 ++++++++++++++++++++++++++++++++ 5 files changed, 445 insertions(+) create mode 100644 day17/Cargo.lock create mode 100644 day17/Cargo.toml create mode 100644 day17/input.txt create mode 100644 day17/src/main.rs create mode 100644 day17/src/main_visualization.rs diff --git a/day17/Cargo.lock b/day17/Cargo.lock new file mode 100644 index 0000000..537b716 --- /dev/null +++ b/day17/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "day17" +version = "0.1.0" diff --git a/day17/Cargo.toml b/day17/Cargo.toml new file mode 100644 index 0000000..2350e62 --- /dev/null +++ b/day17/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "day17" +version = "0.1.0" +edition = "2021" +default-run = "main" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[[bin]] +name = "main" +path= "src/main.rs" + +[[bin]] +name = "visualization" +path= "src/main_visualization.rs" diff --git a/day17/input.txt b/day17/input.txt new file mode 100644 index 0000000..3f9749b --- /dev/null +++ b/day17/input.txt @@ -0,0 +1,141 @@ +111111111212112131132322111222113111121134441444244134242144345414133353141211531241422341212232243224414141424312113113121311311222222122112 +221111111121112113112211111323141331221422241141213411314413253423542114114554431435441123231242121411314332414223323213311232232221212111211 +122122212212112212332113313234211334444312322431311314124222114353422535433132444511311544412131234133114231421144413322322123223113211211211 +211211112213233233222132223113314222121232144444221414142155253533152135533551212512145253352234424132222232343121322311232322332222111222211 +111112213111232122213132334131112244411313321453131151252321321242424323353535113152334324341155514212314424244121414423222211223321322112112 +121222231132133111231334222314212422214223113125432212324222423252331232445424252222332413413554144223211113421214313133332331232212123322121 +222121331233312113123321441242142243414224432432324432211335325333432345435112344255525522114514451353313341123333122441423222131313222232221 +222223332311211321112224141324333432131215352334224433453152113332445212433455132524245345542445553414522311444441323131141211211333111212111 +211232233321132123232124421311432311134212541131135334243341324433432524445252255431425433414442532255214441323444331133412322332112133312321 +222232132211313333134123131134144121241355515453123521213213455544412235311341223244215535311111154451441542431442423321232243321211312133322 +111221322122111133434413224444242321554333214111423545535442241454224454342364335433354153325343552534325532121323131344221323221123121213231 +123132233321232324443133231412322543411141221515222112534334466234224432342526665352355541413232211332525411453331241112144423122111113212123 +213312122113123114224121414224422421113331541414131422424445435523532345546335545366544323453414452214443314153533212241312114343213332131333 +312131133112112144423132323421155314533544545511443234332325235664433246435546432626444555645541224433251155343133333222424324134112323331331 +322321213212143231234212433144511345124152213124424266663543443643344436535543333636425243542335231552221514554133534313313244343221231111231 +312313311333114234113144444244555234224154223422254446432343253324362263262356262534352553425326642133321244423451413133432411411222311333311 +222323213314143434113141312253533135412225215262245345446422663425335263423266455333465222422635532223255541122515311223431121213332322111111 +231231111134224241312324313543223435443113623344263235462565656362446222265343623535654423563436346465314322134122454233324424143131222132132 +221231112341123121222334214134223511331516442545242236523445664445533345455664455324236344666345556256534545353242151232143211441432133121113 +122122322131422434211233312132434553212454545324655622252522334633526634334443663456535266222564622236234313353353132342114334344441212133111 +331322134234413423224422535413341524532445434332555662465363652462225553633323334665642226423652325655363512132135411323322333232431122213222 +212311224233233233131135515154245441653244226465354635432436546577634555465664535636632545223656356363264423252433323214235424134431421213122 +311313412213143212454355521322522355546343635254536244362565634474636476634577566456652655232634635325523623213155113323332314444213321222233 +133324214332421312331515232443251644532223426336553653647763645766376756336445636646356564564252224242525436664524314414345443414312424442331 +213323411311423221132215344555125444422222664536242633774763667464374537464335375364467554643632423356344232622433113124121242111313443312121 +213332133411211221115435453124343624326222332236437773437434747367473374663557665763546435633355634542436342324615513111345543312331134243213 +233334232321414111422551555121442665534433642555764764357344457675365746343446677547665346766745253623346353565454335133341315132213424341211 +311332132343411353241333214422535463523544666566336774667356734463454777767577735436556475634767452534532424533625542155251513454434131333423 +324423131343432152125351451245434246526253355635567565465364546567477476776753544767334344653637777635534523566246315451231113433424131123411 +332313133424214335134142413256554534533645663643574673653374553434644374636764355646445665555773674753364224465254645233332352143431433244334 +233444444244214512345531122645263553435665563567463734345446764566355675666636564763634446577677577763524342632255556412252232251332243342124 +334413121324344245244354552246422666334274366773637376343743467676644466478845885543333545355447556477565242425422662512551241554533442213413 +134111333232545514351215446255325354343473664437747477777448644747877875847476885558337763373453745637676443653326446253554434311142214441341 +443323222311142351213222635255656232356656665356756574775648546784447744857888748676775564776466775557675635324565633245442422214115122232324 +221322342335152535132253635442554264453675334557567665864675845877446446768566847858486746535457565667677666656652453525345311525325443213332 +324112132234124114512443463346234434645536355656743685548758576588446644565874667865658864764774746543357676665466552356244524315233231323143 +441132143315345532241322522433324674747754745454744785866748555754454664488658676548876744545336456465476563625253452442432345151435453141111 +134222341241541234326632335246344744535563674544677768455466468487644467678447656444856674765854544656563637745253666346323124543123442344121 +442342214524542235516322265653424645673467637547788744487488558567688665786747464448578766468864335677444464376663524624455442332443335231414 +213133343344342522526625324645553634343433755444488877656587476684767665665776848484468657656546646435344534753245435463342453234154542232211 +244243445525242425154532424226476466634474356457556756545468568875557776887657587485744468466446886464777634355545352454252222151214212343343 +133321414243431411355322235555377666747553375647586467584845458458978769685976766548777586786645748434357633476762663542466565335215243442322 +312133142534313553662323465625467456536544754487845786855754559595577696785969658864675787564846586735646356564766563644323364511353215113331 +213322234425331156342354532426456643353363687688574848667555655667868759959779796667785755554564848557463745757334564664453225421334151122324 +311141133124122426335532366544776464356376885585876448584959867757985568698777658999655688476457678444633355533346426564264222515254212534214 +143124124111422532546342633765737753336784744485784474476999977859875865997978997679888755777787578486434653765556765463542654642244123213133 +411421355313124464425634436366766653447865844445766664578775657555896886955856796688895797768564464878777454376647533253643526361452415441513 +233224542111542643666666527666653733434555665864558767857885786577595767578976775677699667768688774677865454353535673535644555452355215423542 +421333524312433266246232443443463573548888448554875598577665868799869756896966998795776565984754445466655756764667634642562542654115311545542 +441311131524442653334333476553673344767754744867656986577868657685959778565779658767769759686465647847668777346677773456522422652433223231243 +443425124111152325256535543474636333754888485545659967856877655978688897877698966955776966866545765547484753766345773653633226536354435232444 +423133515135126426454323436454344476788655775647957757796766957557987679977957958789769659686875746648565465654653636343442532352525433521544 +145331153233263536634625343575673568466857767686659568785568769569999669979667885658799565958575864546447554567547746774365336236325145431351 +343241332213336623253452457573577575577775774888769675578755856767778677688777888876757867998656656758746784763533433665645336333355212421435 +422233534444226666564557644734367458775556754796956786586689879896778699867676976965798959699789887878587784876355465363232366534421414421532 +341524341451222553442567557363557484767866558586596896587578888996679877868698766788859799858995664678486748846434664457364264346241251524221 +311435113234352566425664634653473577558467554556796656597866887989678689896886677796697667778888966654846586644553676575263366644532352353111 +255153115411422545535263333565657548568584465956986786969786898899976878986968766698775686565865678565487885485645363377546433666532331155353 +342554355315334355222366763736554545645484589876697687576789778869897666867697696979766588557869996784884777654466335347432234223325431511132 +433323215536236362246454645535557848464585669986668797987676688967997988679899666868699655697658867948554545688673663653446222562433521334213 +335214545323356252426274777467458886467658587658858695979766997879796678997896986868878985986877587554558745485437536457556352563323311131242 +333114345353436546626375473536564684655654566856758568696896887788966777898996699779999689785976667965555684686567754574333266523553433443331 +525311154446553254523665543475738545877578668788859767977968677996879888988789697796886967795685558865544866755654756656334445565322521211315 +531521335452226562654657747555574776756546668685599688678999978767888879979999979997876878876876588975776684688877576536442554534362511215252 +451141243326333455256775374657387888887784967555596896798966689978879799979998999778698686876568977577445554464874765556343353242555424541323 +335313444536354643644364636675568558786758867868575797779779989999887898797889877686769669779765857976687774688735575766775346245534544215133 +425553342435253346226456577375367675876488687975798567779899998889999799999979998878797668856888677898586767676847376347735554636362253224552 +144553545556552354552755676555657686756478578897997796788687668877878988977879799788768776666577659556465867476836456555766622556353533114214 +251154342262662362467663677436556757475566797875788886778966769997798977878777978677886867797768576759454464767736343576355235523433434451314 +222524225452622235625775375656447887864486679988687969969996797778989889878987977997998998685569698987484548568855367674447222656366653353312 +253324114536522225327654676334546457885847887797565666987966698978887897887989888776687877785558695568484646864644753733364336443663245224421 +123533143542444566663533336747387574875689788856959696786988699789887779787777798777668986697775998578647655678854356635547455622255525325342 +342513515236663342243553474767774547678446798897988998966776789879799877778777889869989696788967778775788658464866334434344345322663331112223 +431532531535362264266466663637665864544577769866998699679877687879798997879897778989967868997796659695855465548546637346574365326262653333541 +315223121124263333453677575667747857585886595559998698768779788787979897978889787798667996786567877598766545855453543445563635336325341435115 +524224415324634354355777675574457885657846876859886866669669679888978789987887798669667766865598585769844746748436573575455353544364422151351 +143144314356524632623674763753556774788565756965996669677897778877978899789788989669876679998766666766886474756766674375534342455463622441155 +513543311423333542643457563364554856455749995586885898998879699778979879778899977998879767876566888586767547674637356633663524266534422332341 +441245215215262565254377774553468478745565578975756586676999797697797778888887788776678796965765556655548665484533766677675554355522332512234 +233344141256444466643557445674688774765846976595698786687678977887878778999997697966967696657869879674784758657447765354463235362243423151442 +234315154554326255344547557475557445858785675569799957999988878788978898978967698876797996689667998785648664886743377765664222365465222252432 +151152243454425225435335463764474468765666565677986675977996988669676878897769897697697865767887955875887668484443675534336562226445133145131 +443243413113652525445263657743365686576566695656589855676768668776879897879867886697988978596858585864577745475545443336454256556363353342215 +124153542233226424323434767346738884577874875865666965867779977868978776989979776886988865567756698786886845448747737744746624526552553545212 +211211312134526355453275577364343857548875686987766955769678769997686976697787876987776567587756785688876558665663576565424365224251512545554 +255151334333355432632336767657643554678647555767658769686796787769876666897969968686899785689998599446544768745656554763323655362441353423254 +144511144543225526644554334434446568674648776966786799777999789798887798996676967676697585856568558457576648583555774573624553335225443211255 +412454143411434533462635635644474666885457655755887957989887769789789778787876867696965589895976788867887657657756763363456663344635445544412 +211145534512452424322524563467357654778477455455895699695585867776996988687887787999567766578959788568687484877356356474656333434311315231342 +322154131442133263256243676737374758845877576889656565599896886799976698998897696667687578558997658854887584633664477633445346453412135344131 +132135154424564322444436556436347457745685446786677978566578758576767767896778778797579857655778556448655578553576736654526235434641431111152 +223332534513125265524653655564763346676546746565889867578955787989899668999669998766697766558666484474556764543353756773633332552542521315441 +324255115414512346244536635677365754677878488765588776869799785666789898586697779887887887879865777754748784454366757435643244264452532542414 +122135532114535646525345644665357654447457685858847657566555769879957758675587659878957799785456576867656833475673464665322623545333335351431 +334225511144144624622524627373437633356658856747676998856787986989857796655568985967777856585868744455777334477535756242354323531134354132221 +433425151433342654662262345743756634737656664444745465776556957785556769965765766955976559974647447654688736546477433332366345222243142534523 +143435532553142563526244443367337345643784466656877774875695696875559886859867956678796776768854888454683564634377772454653265233125213342241 +112242421243151456464562552676674464467354577488754886889895757867875786898655978997766766854855486456836474565665356554645426654235114115411 +213414232311422536624243554447757447655475587784785677855868666985756959567858555769787844847866568577547753546753726345435323541545522353434 +322312423142452446322532433366737644737577678586758784674457556557956558765975769979754565556755864844546545757536324242632622452115442333421 +422112444121223534534526263257335463573347384444555888575845796688857967958776757754648675447784887453747764644764363245452524432511113131332 +342223414542213354464332235625373654466375744846456546786765677587759875799578465888747487458584466434675647545644653665324543255322423443132 +433324424531455155362332534425355666555633434846474748768677554674654755456444787745678465857657646556374456657355665244266454541133525342442 +214144134355225235145354363526234665477364777454676668488457558847747548468668646658656756857878853443453466735662432236232423351245325432414 +132213335435212541453363546265454374465653646546446757468576587864877764457644564647445778847685544375747564366555263623325234121534434233431 +234314111414153341334456635662452333565645443545464885865646577887888676768745554857445767568757443666766436335224634434622413542142423112414 +233334442234224321424663334265462563335634463653637857774685657884464876545677874566548746464547556775333464566252536652324222415134542114424 +343121234251224212433546336456464527347567433765536554677486465844467788655667747886756885863547746637475357556625354662234431533153433144241 +423111243212254124411126453366343355457437373764373376857676566744447884744874485644484483544635534453666762465444244446122112224545222431413 +444122132314115454324535256242632465667747353356666355376656476558465684458666884885546566474673674734765535442323353263555113122525322233231 +132222141331331351331323364232632466354763555654767377337446867547446488554548548846534563645466545773636256363654535641551212443122124321444 +132431211424143123532312235226235325552665647357537337653333457775684767478556585636373674663533375443434456535255455252513323542251113334311 +123141143132442544455144224534265545542467454744565735545734556464636366473555765573353664777637755334533324233535544252253341251242312322343 +242424133124145514525144143623244446233322746457637535463644547456576774536476764764366677366765375572434563252263221213233532413214444322123 +221212434411112423234213421442645453565465637436767566436574666654363356637474377775367465533453736535454464256664341542551214452432244333414 +322223143224133242523313554455655433342643264757774536473647353737545365465446537447666573353667635324643226254544453552141551242324213312213 +231222221333142143535252445252333362225545532444755776654657653355666535666736664764455445463344225334432554462421144414144245542231311432441 +233213331322343245211222532425362242425445252624656735465364343743554633653576745334565443577323554224632533653252342125122132122432224412421 +132311113231341341214252245135212645645222326632562475357353764375554764636354375755774665332356232234223453365415133112255144332333231334132 +232121132231231221511112114321544433323634665263224255336645536655537373476756543466553555434426664425344645324251445443443342343232132432131 +223211441112423423125145233125434122456233422223222234353475367676773456647774354647545245533633334532633264233515111233443532421334414412221 +211233234132133123333312513223255252242556253255334662665535344637767365546545533754332645636653332456236652345153255441142423211232242221123 +133213233243341333122214451245423541153255226526322463346326225644546744464332545353255353333545262436223453452252542553124443314442313223132 +232211133442411421424455223145443344343323322663465633563564346366663335336334233344434442225365622265234343253254321523541234213114222323132 +123322311214132141432422354335153531553324436525455522463446522633442324555536644352446345224553452656311243545541552244412414332411243123113 +133211222113312134421324222451533115155115656223434322322452524462466232363452354554234553353264232523312554114521224521432424141122121121233 +212311121234242433341332242152141553333244354563456222643236552462346656256334543456526544645454545542241512252234224323434431412423321313211 +222122112312442434413232313254441431141324312465365343422332336353546464245236443225222446345434452544524253112544414434332434133333232121213 +121232223333222214434322341334554344131214514444325554653334225522466653232344445252536523222412522544244132253421513132122212322131221122333 +113131122223322232141114243331521414415413533325135225524334364322554243344264355644334224641252234112231341254441341432441241422211231112331 +231123223113121444412313444423455315135451132535143131363333546335563423364442224634623415221554313215113253124322313122434111313313121221223 +112113113123112332212433333412111211411133422254351211534253623363326425452243643352445333153245212235422115313142313231211411431311312123222 +211213233222131232431413123142142225252115252341423313455125554215465526343655453211314142245541113511214122542423121243443331313132211333121 +122321331211331332113342142141132114324415231124313352252433232445422232331232155211321143532154212114324412242413332414241331133312223321232 +212223232212122321231221343434321232125535343413225131312324433232331244112442143143324221451555333434153144434214124413413232131323221131112 +212112333321332322113441221213413333314144231141524123524452415351421533524512545332455212414232252213454124311231311313212211121332311331112 +212111323123221332211321312241223411344113322342235323434535352431241233313555211253443123115512211323331323234421322121313231121211332211112 +222212111232113311213222424321133422212214325542112432543334532224412134424331552233242424324114254432311123223233332332223131132131223321111 +122111113213323333233233213443233121231131213241332245435455232435225535554542341415215111125413311222432124332321141313231123223213223112221 +211221122133231223233221112441411433213334221121214334445231523455224113133444221414114425513333222111423124443111423213313122113313122112121 +212222122213211112131132322314331233144333433324442315513412314345522434534255522423411231242242432133224141342114131323221212223211111111112 diff --git a/day17/src/main.rs b/day17/src/main.rs new file mode 100644 index 0000000..f21c7e4 --- /dev/null +++ b/day17/src/main.rs @@ -0,0 +1,115 @@ +use std::collections::BTreeMap; +use std::fs::read_to_string; +use std::time::Instant; + +fn find_path(layout: &[&[u8]], min_consecutive: u8, max_consecutive: u8) -> i32 { + #[derive(Copy, Clone, PartialEq)] + #[repr(u8)] + enum Direction { + Left = 0, + Right = 1, + Up = 2, + Down = 3, + } + const ALL_DIRECTIONS: [Direction; 4] = [Direction::Left, Direction::Right, Direction::Up, Direction::Down]; + const OPPOSITE_DIRECTION: [Direction; 4] = [Direction::Right, Direction::Left, Direction::Down, Direction::Up]; + const DIRECTION_OFFSET: [(i32, i32); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)]; + struct Node { + x: i32, + y: i32, + cost: i32, + dir: Direction, + consecutive: u8, + } + let width = layout[0].len(); + let height = layout.len(); + let index_multiplier = max_consecutive as usize * 4; + // Evaluation function for visited nodes, -1 is unvisited + // Node is treated as a different one unless direction and consecutive counter are the same + let mut scores: Vec = vec![-1; width * height * index_multiplier]; + let mut queue: BTreeMap = BTreeMap::new(); + let get_node_index = |node: &Node| -> usize { + (node.y as usize * width + node.x as usize) * index_multiplier + + node.dir as usize * max_consecutive as usize + node.consecutive as usize - 1 + }; + let target_x = width as i32 - 1; + let target_y = height as i32 - 1; + let get_heuristic = |node: &Node| -> i32 { + // Heuristic is manhattan distance with addition of correction due to forced turns + // This correction seems to give minor but nonzero improvement of performance + let dx = target_x - node.x; + let dy = target_y - node.y; + let x_correction = dx / max_consecutive as i32 * min_consecutive as i32; + let y_correction = dy / max_consecutive as i32 * min_consecutive as i32; + dx + x_correction + dy + y_correction + }; + let mut current_node = Node { x: 0, y: 0, cost: 0, dir: Direction::Down, consecutive: 0 }; + 'outer: loop { + for dir in ALL_DIRECTIONS { + // Can't turn 180 + if OPPOSITE_DIRECTION[current_node.dir as usize] == dir { + continue; + } + // Can't go in one direction less than min_consecutive tiles, 0 is only for start + if current_node.consecutive > 0 && current_node.consecutive < min_consecutive + && current_node.dir != dir { + continue; + } + // Compute new node consecutive counter + let mut new_node = Node { + x: current_node.x, + y: current_node.y, + cost: current_node.cost, + dir: dir, + consecutive: if current_node.dir == dir { current_node.consecutive + 1 } else { 1 }, + }; + // Can't go in one direction more than max_consecutive tiles + if new_node.consecutive > max_consecutive as u8 { + continue; + } + // Calculating new node position and bounds checking + let (offset_x, offset_y) = DIRECTION_OFFSET[dir as usize]; + new_node.x += offset_x; + new_node.y += offset_y; + if new_node.x < 0 || new_node.y < 0 || new_node.x as usize >= width || new_node.y as usize >= height { + continue; + } + // If the node hasn't been visited yet + let node_index = get_node_index(&new_node); + if scores[node_index] < 0 { + let new_tile_cost = (layout[new_node.y as usize][new_node.x as usize] - b'0') as i32; + new_node.cost += new_tile_cost; + let new_score = new_node.cost + get_heuristic(&new_node); + scores[node_index] = new_score; + if new_node.x == target_x && new_node.y == target_y && new_node.consecutive >= min_consecutive { + current_node = new_node; + break 'outer; + } + // Combines node score with node index to provide unique keys + queue.insert((new_score as usize * scores.len() + node_index) as i32, new_node); + } + } + match queue.pop_first() { + Some((_, node)) => { + current_node = node; + } + None => { return -1; } + } + } + current_node.cost +} + +fn main() { + let time_start = Instant::now(); + let input_str = read_to_string("input.txt").unwrap(); + let time_start_no_io = Instant::now(); + let layout = input_str.lines().map(|str| str.as_bytes()).collect::>(); + let loss1 = find_path(&layout, 1, 3); + let loss2 = find_path(&layout, 4, 10); + let elapsed = time_start.elapsed().as_micros(); + let elapsed_no_io = time_start_no_io.elapsed().as_micros(); + println!("Time: {}us", elapsed); + println!("Time without file i/o: {}us", elapsed_no_io); + println!("Loss1: {}", loss1); + println!("Loss2: {}", loss2); +} diff --git a/day17/src/main_visualization.rs b/day17/src/main_visualization.rs new file mode 100644 index 0000000..01eda91 --- /dev/null +++ b/day17/src/main_visualization.rs @@ -0,0 +1,165 @@ +use std::collections::BTreeMap; +use std::fs::read_to_string; +use std::time::Instant; + +fn find_path(layout: &[&[u8]], min_consecutive: u8, max_consecutive: u8, + out_path: &mut Vec<(i32, i32)>, out_history: &mut Vec<(i32, i32)>) -> i32 { + #[derive(Copy, Clone, PartialEq)] + #[repr(u8)] + enum Direction { + Left = 0, + Right = 1, + Up = 2, + Down = 3, + } + const ALL_DIRECTIONS: [Direction; 4] = [Direction::Left, Direction::Right, Direction::Up, Direction::Down]; + const OPPOSITE_DIRECTION: [Direction; 4] = [Direction::Right, Direction::Left, Direction::Down, Direction::Up]; + const DIRECTION_OFFSET: [(i32, i32); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)]; + struct Node { + x: i32, + y: i32, + cost: i32, + dir: Direction, + consecutive: u8, + } + let width = layout[0].len(); + let height = layout.len(); + let index_multiplier = max_consecutive as usize * 4; + // Evaluation score for visited nodes, -1 is unvisited + // Node is treated as a different one unless direction and consecutive counter are the same + let mut scores: Vec = vec![-1; width * height * index_multiplier]; + let mut previous: Vec = vec![-1; width * height * index_multiplier]; + let mut queue: BTreeMap = BTreeMap::new(); + let get_node_index = |node: &Node| -> usize { + (node.y as usize * width + node.x as usize) * index_multiplier + + node.dir as usize * max_consecutive as usize + node.consecutive as usize - 1 + }; + let target_x = width as i32 - 1; + let target_y = height as i32 - 1; + let get_heuristic = |node: &Node| -> i32 { + // Heuristic is manhattan distance with addition of correction due to forced turns + // This correction seems to give minor but nonzero improvement of performance + let dx = target_x - node.x; + let dy = target_y - node.y; + let x_correction = dx / max_consecutive as i32 * min_consecutive as i32; + let y_correction = dy / max_consecutive as i32 * min_consecutive as i32; + dx + x_correction + dy + y_correction + }; + let mut current_node = Node { x: 0, y: 0, cost: 0, dir: Direction::Right, consecutive: 0 }; + let mut current_index: i32 = -1; + 'outer: loop { + out_history.push((current_node.x, current_node.y)); + for dir in ALL_DIRECTIONS { + // Can't turn 180 + if OPPOSITE_DIRECTION[current_node.dir as usize] == dir { + continue; + } + // Can't go in one direction less than min_consecutive tiles, 0 is only for start + if current_node.consecutive > 0 && current_node.consecutive < min_consecutive + && current_node.dir != dir { + continue; + } + // Compute new node consecutive counter + let mut new_node = Node { + x: current_node.x, + y: current_node.y, + cost: current_node.cost, + dir: dir, + consecutive: if current_node.dir == dir { current_node.consecutive + 1 } else { 1 }, + }; + // Can't go in one direction more than max_consecutive tiles + if new_node.consecutive > max_consecutive as u8 { + continue; + } + // Calculating new node position and bounds checking + let (offset_x, offset_y) = DIRECTION_OFFSET[dir as usize]; + new_node.x += offset_x; + new_node.y += offset_y; + if new_node.x < 0 || new_node.y < 0 || new_node.x as usize >= width || new_node.y as usize >= height { + continue; + } + // If the node hasn't been visited yet + let node_index = get_node_index(&new_node); + if scores[node_index] < 0 { + let new_tile_cost = (layout[new_node.y as usize][new_node.x as usize] - b'0') as i32; + new_node.cost += new_tile_cost; + let new_score = new_node.cost + get_heuristic(&new_node); + scores[node_index] = new_score; + previous[node_index] = current_index; + if new_node.x == target_x && new_node.y == target_y && new_node.consecutive >= min_consecutive { + current_node = new_node; + break 'outer; + } + // Combines node score with node index to provide unique keys + queue.insert((new_score as usize * scores.len() + node_index) as i32, new_node); + } + } + match queue.pop_first() { + Some((_, node)) => { + current_node = node; + current_index = get_node_index(¤t_node) as i32; + } + None => { return -1; } + } + } + let mut temp_x = current_node.x; + let mut temp_y = current_node.y; + let mut temp_index = get_node_index(¤t_node) as i32; + while temp_index >= 0 { + out_path.push((temp_x, temp_y)); + temp_index = previous[temp_index as usize]; + temp_x = temp_index / index_multiplier as i32; + temp_y = temp_x / width as i32; + temp_x -= temp_y * width as i32; + } + current_node.cost +} + +fn visualize_path(layout: &[&[u8]], path: &Vec<(i32, i32)>) { + let mut layout_copy = layout.iter().map(|&bytes| Vec::from(bytes)).collect::>(); + for &(x, y) in path { + layout_copy[y as usize][x as usize] = b'.'; + } + for line in layout_copy.iter() { + println!("{}", std::str::from_utf8(&line).unwrap()); + } +} + +fn visualize_history(layout: &[&[u8]], history: &Vec<(i32, i32)>) { + let grayscale = " .:-=+*#%@%#*+=-:. ".as_bytes(); + let mut layout_history = layout.iter().map(|&bytes| Vec::from(bytes)).collect::>(); + for (i, &(x, y)) in history.iter().enumerate() { + layout_history[y as usize][x as usize] = grayscale[i * grayscale.len() / history.len()]; + } + for line in layout_history.iter() { + println!("{}", std::str::from_utf8(&line).unwrap()); + } + +} + +fn main() { + let time_start = Instant::now(); + let input_str = read_to_string("input.txt").unwrap(); + let time_start_no_io = Instant::now(); + let layout = input_str.lines().map(|str| str.as_bytes()).collect::>(); + let mut path: Vec<(i32, i32)> = vec![]; + let mut history: Vec<(i32, i32)> = vec![]; + let mut path2: Vec<(i32, i32)> = vec![]; + let mut history2: Vec<(i32, i32)> = vec![]; + let loss1 = find_path(&layout, 0, 3, &mut path, &mut history); + let loss2 = find_path(&layout, 4, 10, &mut path2, &mut history2); + let elapsed = time_start.elapsed().as_micros(); + let elapsed_no_io = time_start_no_io.elapsed().as_micros(); + println!("Part 1 path:"); + visualize_path(&layout, &path); + println!("\nPart 1 search order:"); + visualize_history(&layout, &history); + println!("\nPart 2 path:"); + visualize_path(&layout, &path2); + println!("\nPart 2 search order:"); + visualize_history(&layout, &history2); + println!("Time: {}us", elapsed); + println!("Time without file i/o: {}us", elapsed_no_io); + println!("Loss1: {}", loss1); + println!("Loss2: {}", loss2); +}