From 14ef33326ea6aa87e5a11e87638503df35d37bf4 Mon Sep 17 00:00:00 2001 From: Andrew Ekstedt Date: Sun, 17 Dec 2023 06:26:31 +0000 Subject: [PATCH] day 17 solution there's a small bug in the cost calculation which will be fixed in the next commit --- day17/astar.py | 105 +++++++++++++++++++++++++++++++++++ day17/input | 141 +++++++++++++++++++++++++++++++++++++++++++++++ day17/sample1.in | 13 +++++ day17/sol.py | 61 ++++++++++++++++++++ 4 files changed, 320 insertions(+) create mode 100644 day17/astar.py create mode 100644 day17/input create mode 100644 day17/sample1.in create mode 100644 day17/sol.py diff --git a/day17/astar.py b/day17/astar.py new file mode 100644 index 0000000..e1fa793 --- /dev/null +++ b/day17/astar.py @@ -0,0 +1,105 @@ +from heapq import heappush, heappop + +def search(start, is_goal, neighbors, heuristic=None, worst=None): + if heuristic == None: + def heuristic(x): + return 0 + if not callable(is_goal): + goal = is_goal + def is_goal(this): + return this == goal + if not isinstance(start, list): + start = [start] + i = 0 # tiebreaker + q = [] + for s in start: + i += 1 + heappush(q, (heuristic(s), i, s, None)) + done = {} + if worst: + best_worst = min(worst(s) for s in start) + while q: + z, _, this, prev = heappop(q) + if this in done: + continue + cost_so_far = z - heuristic(this) + #print(this,z, cost_so_far) + + done[this] = (cost_so_far, prev) + + if is_goal(this): + print("astar: visited", len(done), "nodes") + print("astar: pending", len(q), "nodes") + # reconsruct the path + n = this + path = [] + while n is not None: + path.append(n) + _, n = done[n] + path.reverse() + return cost_so_far, this, path + + for c, n in neighbors(this): + c = cost_so_far + c + if n not in done or c < done[n][0]: + h = heuristic(n) + if worst: + if c+h > best_worst: + # if the best possible cost for this node + # is worse than the lowest worst-case cost we've seen + # then don't even bother exploring it + continue + w = worst(n) + if c+w < best_worst: + best_worst = c+w + i += 1 + heappush(q, (c+h, i, n, this)) + + return float('inf'), None, [] + +def test(): + data = [ + "aabqponm", + "abcryxxl", + "accszzxk", + "acctuvwj", + "abdefghi", + ] + #data = [ + # "aabbaaba", + # "abcbaaba", + # "accabcbb", + # "accbbbba", + # "abbbabab", + #] + start = (0,0) + goal = (5,2) + + def get(x,y): + return ord(data[y][x]) + + def neighbors(src): + x,y = src + here = get(x,y) + n = [] + def push(x,y): + if 0 <= y < len(data): + if 0 <= x < len(data[y]): + if get(x,y) <= here+1: + n.append((1, (x,y))) + push(x-1, y) + push(x+1,y) + push(x, y-1) + push(x, y+1) + return n + + def heuristic(n): + return abs(goal[0] - n[0]) + abs(goal[1] - n[1]) + + c, _, path = search(start, goal, neighbors, heuristic) + print(*data, sep="\n") + print(*path, sep="\n") + assert c == 31, c + +if __name__ == '__main__': + test() diff --git a/day17/input b/day17/input new file mode 100644 index 0000000..68fad5b --- /dev/null +++ b/day17/input @@ -0,0 +1,141 @@ +541325532413154112543324624344224545523462433352343463247775356367644347443563677657343744452636444345256642465244525244265544431245144444221 +331414241322155325566365653323365536535625534662334663573476555335357734444677365546643757652664642422365232553435632422462652133234221512215 +112554244333323423245642454645423242233656354535646574735346555646776767536545363675664344376545324446564445556565525526354621135153235435355 +542134154422331162256546652564242435642355365533543774673455365777557755536655735643465454333776472665655234623522255366242524413124115451453 +255251321341123224246525356462642224343225675747637556637674454344574363677445356433635464757763654622224224643632533433452565562111314332341 +323422512325314235242263655345522326644277643546736735556435374637543437655333567455673737467355557747324624235426622233354356446132133215154 +541534415132425356522655256624346542356354755664376557445744476334744743465536755754336555544636554557737333443224244456235552453253423313145 +515553552411263445633352624623665533344334337643473435634547645473665346447473446437553466757655455367463472264425533355633442452453213442124 +544214521555643342656232623463353546563633737773445375774334667743475334577363467775435576654463636667756476334523533536656245462245431325552 +444435344234254322226534364244465643743553676564764753654766336746655546757334456666436757744355475475363753752322654652363332225633645155434 +212254314564226533533534434524557665735744735556577636573746346635443434567673456637573775336347467573445644354564643546236422336444661324543 +512413516564664633325622256245356466543343753467665546337365773767564653766657446456356444363564457774376334434756443242324324342343553415431 +123353233256452626246523564247633554636547453756573433544433634767734774746646334333454765563334375553346673354374344625323266355556655225412 +332255633633636625263535525635667435356665377666744736446636545565764577677455774735573646553437444674337675673667576235366552324234533442215 +223515534224455443532343536547353366775533575556634444434737867846787446578668886484577736735663344633473457576544343265455656255646522424132 +533546255455524366545365473433534564467543663577337455744574545784658875787488555445786876364433545775774533573546546554333656323556264426531 +243536232465655424464653354376357773364566775433766547487787585756455675665875447777646868877576375577734473634775475667446545452346443626462 +155623534353226323442675576457657475474357735635687785478546678646666448578775875848665587878733645577643473333467575545543563266636464343253 +236332623432542664353547736564656564374753553734575675767575568884556566475855685848485654864454663766645444574436774645376563234666326346443 +566563433543322264347477663533766545634464344785486845767768576676857744758456485667758884677656583377736363347534654543534433463566366343363 +555223422622655243643633767456657367445676386557685464545777868586864564484676684746564574488864774674453365474765677673543553322344356325443 +666422265262655424456466666473554475447334585887857754757574584787868465865767476668456448656887677466674546647447665677555645354264545422234 +563226422242366336753544557367656637776577466488685868775888744478784748675465587674767868556748745676644554534653566733733676636233445642336 +322564234435646554674567377365335337747666488746766875574658858558556446886654658478845478476676888748467647663554665733455654534522662534653 +465555623454633354445333653446736364557747546574447766445585886557886678584858674585768866455555764486685853766473443674575654742435232244663 +343444333345462646773576447564676464457648776785566755578878787756544684757567485468846844788457564488844564553777663743437536532223424654325 +262222464566654745464554475655357345664565788445885684557675677648778887486484857545754565467575775554645447446774764536337467454235536662643 +232225445454333756373336674365336584675774545658567674845565785577665785455566754657474747566857554848688844854757347546577375635422363642242 +426462234255434436537565533757765666754465558644788765657454865698895866888566895465865676454875485688586685856333457773757443455725433334645 +536564545645475634464356564636775454456854468854545858586758597989866959966875956568758855675865676846478855774847754365447455345662662465465 +635444422225455545664356536555546766677768765875554767747678579757857766887776587776987878886577846778548485657454356354566563375337625625244 +354436534567735673766437774474565877786884768576467564566555758968956556889765687986686987865756455865744655777886676375663557576465533642236 +564665643553557647746457345554877775644875885554756589687679868898765598699897996787695896548855684484468767648688664437743364557436753642366 +562364622554366374664353374858757467476747844755657868879675897768996785676596568757988866759674578456455784488886586755755657734764436232336 +264332654365666637556563657457756576848475886566996976778877778996886659858776775557879588599578845855748764454447585737365747667555744553465 +534465655563445763544656646887457545478877655476988979997999978759788955558656988897978799577686578664666466758445658354357534445674363656354 +442265464553344643664345447584444584678685788996976769556796788869989699698556766786866576777679974865845548854444757574344344733474574455225 +462336673754537443367573555745685445476767587556988776979999959589587557999558699996957667867556799866545875787566646454665453464764454365364 +335263637555343654737775467464784587484485585556778965787785896585755977777555689698897596999577598986548777644884557658454754554636344736262 +234335766637333434546376845678668845775685795875967556579589797876866976986978887685859995675859857698744557566865874477576747466454533772422 +255434574536534753637354455547567667765778595757897575599857866877978577859965585577889676598875996979764867485875854674453536534453655577222 +434566643345555356464888454746767544687558976776679678677955866868767765969586776966879879685887568689876475854674445665645643347335464344356 +534646336647757665335846455746868845678596765786877885787975659799696678879959758659766657987769879796977674644648784577553743545437435374322 +526365737663437746666855544855754657787857895779598797959957869888886986987996999677785876678665985658777858668448457478565773676435774655566 +265667734463653544354785567557576787658656969686597997765589868689979668997699966665695687879755957566977888847446885775864346753353374573535 +253564543633573537474886666446566577786885575979777887666977886787987986687989689796888859686995995669797794674644768846685566646675743776375 +244376776367766633545876687588456786855996899689566986669889969797878866997896967996696665557978668567558875577556657546684545554563757455776 +554776573466745737474576745674745567776787959776557766566997867897986769676979869889676685769677969699775595547566885876544885443756344465663 +257575556467766775454686547865888598556866678569556978678967688996698696799696998798787699896756867598989557556768454745464684763565434737545 +537357564546643674458785745866754665595996755986665596688768796966787669977896868776776989968579766986785786678484777564864885657473634734343 +565344664665535477747684777576746876656866585967989886866888699998877899979767668998996876979767669859877688885887574546786886546537664664373 +565357774673666664574665685457558689795889587659668986987787779769889769786786677968688676789758795789778799968874554888745884477656333347734 +245364636567733378747546688568467886556575995665667899776697867979969896777697699969798666967778955575878757679874445586566685865366343455347 +575656654334567568656486467468659899798876975555697877868779698669996796698678666769878689967795566959879555869767654758764456537655557557767 +346477444766645357588884555657666698776697587778967998678897767668969786678666998777877898879695965756995895677554566657887857845647373757563 +664555364364376544585645485887676665565675956998886886898667766666879668669876889667796967869898765797966889859764865547768786566655366764647 +663335573643645757784454578444798978988975897996797676789878998969987867899789769986867999888866857798899566596886878577678866667673443666553 +665646477444467687777558754567958897787855565999966889777667798796689979878967869689697689969797678558687999957567777748468868754345565456346 +566543636475566856656775656587756577667967799766766879688687889678977997888877768899789968667679679859556898886955486585464677474675534575777 +645577757777546568576475846559988557689978768999899878797888686788977998778999799668866998997767768595597566666695577675758886657334537474335 +647443537674646775664646644485579879756769756799977696899668878789789997979999998676969697669787776678878565876897478757886554676544436373733 +735435337737668684557486784787968675575789587868997868887678797878989898977877897779967796786998868557559568875998648447577777687677333766745 +543365534657558846755485555769955989956966898986769788686688788779788887978788778979999776788888866879568986868576657577867745756657476634333 +575536335353367864458746645779595756876859568788987698977689998898877788798987888787886766966799886679868555575596986655665884467344356374634 +473743773666654456848656885888576959596756697769979988779698977879787779899997998997896679869976797956886957756797747546478877674557735477576 +645375747353758646565577776469995878658675789787886696789697888878888779887978789889769798679989886788698567658597588456647457688467657554557 +345467535536675474848846568657895799758598699988889898977697988798798789797789877898877968986996666757886787886969865748864884847444663434663 +656456334766548844754566855865579785857878878769986899686879798779888888997888797898876768676868879999656856958868968558486468757444637647463 +464343374457778676587755854879865876988558978768686966967978999997987897797897799788898988987869996895799965888998677645657757588743463334546 +347476457754374656475466676555567667657587886679767677688789978887987778988799997779879669999977768767865586875857875547687554665463564573454 +453766454355684874884885874686876989695967697979669789668987897877898978887777778979796779986768878976856765759976868744885877575746735565357 +736636647435668778784654646498787999669755687687679986876999779979898978899977999898789768998797877699878975986897764765448684554875364476735 +664436647443567755668485684766596755555769978796767678869978778798988789998777777787997666686699786798677785879868965874785748455564663637575 +433553345755375866788885748475965768586787978989798989696789999888799989878797978798798968789786967779856877995576767745856455666836337554377 +344765347543374446674554858577596665697799687787679778869887879977999987999887979878796886977978987769865666868568956585866764566535774537475 +546576646364778657445448847759585995895697878889778996669898789879989987799998979898797868677699766858578859977755677446755745878665767345653 +533546474574554677555477646465886687856557896666778797998699899977899878877779778779867866897987667857887599895995588754757778486775455634365 +364776533553388544476648645496597697688656897776688987669777788789989798888777777798988866877996776958558977857698778487778775567443437764654 +767575643445774646865587678859868695688785899996688688877668879779779878879789879897668976796797988686797559759759646754568666464766356634777 +663564774636658444884475474759797966777788768776999686687989799887988789889998777878788897969767689958777798865786678765766587576735546445447 +765545346777444457678486575588879885678987596687678987878666897997977897979987978988767978769779979865598988867978478475444464744564356435353 +366746667447578457875445867488677995859667698887779896696998788978887788989797887876769887968897796987657789656777858786758778587445346364346 +734757577657577844678557878567659668878757786878767979787666669879779997977898778999886989869968789676788565887969468567446757675547746434465 +467334563557566456758584574878865795766868658996987868887697669888997898899788998889989668879666986669776669687989566454585878855556675374743 +645575457653677884784585588855655968856577875887769876987669779888778799897898777698889967796888787578585855865768848684455877667364474457775 +767557477466374868477886488774898767588796985976996797898896789868898899977876979969877766999996989576756859996757575867468868557576573774434 +365367356554353486664888444486576978789969667598668798779679967888788999796986688989987679989688677766569979655954458755548884553647454343365 +376336736735457876455766664576868899958567899859897696666876898967968667669679868898898888678777677965768667886556674567766854753575675577476 +655377576336353777555487674664459995998755596688788868897878878786779897766898666796798699986769596797666758675744757446578744875557637667343 +346446435544365588467868786546676559596578965787878788879688679686797787696768968886787989768785998568785579588888765488767877567565467755576 +354754743465663748676677684474685586888867755998899878766698966778769666867868877666879989869975667775996755968584457547448868665676574646644 +375476567446766648657685558868684876569896777896588689767787787777779797666866966896997697886777658855887666756556865488575868637476356664546 +445443376634364754578848556856444996665555889556557986866898987898998767968769789997987768997597899598677768594578757748767547673755546757466 +665475644545575348685574648545765657959867595696876978696669997879986966979668799877788966668889557878656677776786455675445767467546444535474 +536536364733663343757854644865786455596579777665886777767776796878787689898768677668688795585588869858867558758654576484588863577736365556466 +545677765673477647458587675877857747699998588967985579966698996796669968868886777876896876566779758656867579564454754855855877653657775474465 +526634533344674357784857678766684666995887697768597868868688669877886679676996996687797775768787576675996687784778756557686657567343466435376 +555367765673445476467455475554586466585989789887787769676867966767676796687889896986877586778976986876898895566876577547785676354466367535475 +566676343464545754336756566678644764665555658957956858897698698967768969799997687799675666769956667655559976654874668868864344365374536646744 +642375475753557633436874464648878466547566967655869789865959766986877898877867796965686987965766886865865675747548555887646747776445567347646 +656326775677733743553476855846684858777567795889655999758996557887666699887977775858955696758766587856867888675575847875564373546374366533364 +356523464767556365754554458685647747687488976778688855697796599685596579789897557585667697756877865679768565567847486476653374377755437773466 +543364557655446374776484667446844587777758978869866755687997557969558968989668567678676658666557568857756646588867747655633365453645345346563 +236562656367457666473574756767787484864787678758988675958855996858589889785858687986999988859888998997488777755668648846466573577345536445525 +435425454743354543343534475784886747857444675996758965666578678996855698756785979795587987959775967867864775685466445885737645534737473665362 +656365663566663445676743748865778774886455467789977566999699575957678987978899885895585598567758556556745674586867685465366373764453753632226 +554364645654577774575347585474486665445484788787958557777995767555969688786699755588897576959596976845578586878455558754775543573553676466226 +566365526354555656773564765857585674685586764446576595576665977697577778959689988577969857867777544786674878657577858777336353333336763243544 +225645463477536636737547746855854577665455586777855595668788968669666569588785557968878679887868765668784484567586587654537447376767635645624 +326343324673543334344333453846654874888454446758467889966666595596659955785659698886979596579556454785744657484756587664635335666734746333362 +532662633633547457656367653444766558747845867568768765978675586896665555887897795567797775544675848675458648484474634746576546564554542654353 +355663354646374655677455353646574544555776878645666884896787558788857879795677987878598875568878457856645555765646757774773335733663526234223 +353422562247634437354366757547848484486845777858677644677756767685987785766977575755599856685775568757588558668567757543337544345564535234266 +625553254333746337646674767563388458857564687664846777856669755559789686587569959585684667544648664446655584855854567365533744356742364465444 +256524322524363455666676457677636858464476685768488658555885585999765659786578666675884764747557458554788587577463354747475464475463564363232 +344555253446556735453434354367637586487674456777465645884457744886765674748655466874854454886874745687874444873743475747434554764722562353544 +436336633646457553373364653633435565546884675847685764745576446566586448474646588477788544776856755887755886845455353675573457356665354253225 +353553554345353455733547735663756547845588454848874587864766784664557578755786484855447586484587747576577446434565477633534576642362554466224 +432525456624322674674455473444735465585878467468565785857768745885767848488547466474785564885557558774875737646763773465674537654223644552654 +525335354433465274655555537746447754355487677744768868776677444557756865777755446886557446678584767648468645477543475677473764432555343662443 +536234524632522465555647777335435334437785748846755474465446555657555454476786768444746644457754678455575643465746465774734443646245244645242 +543442426643426534477636563376653536756355858585748486864457846887545584748846488758855855645876464887457465374457355477665635626433523524452 +223322223546552553575645377567767764633457777574576586688766475584868555884876446564687754664544674746647356433575667577763565225654256544622 +125432653256262246645676433475543465775457456787477566566648476474677745847886586875848787748885486346376633653653363657636242326523563666434 +154555463335463666563736355477665434373773447735676677764476767476757886646475666486685555778786577733434376677574533676446342454463463634432 +141552262546462536364674453376344346655766473635575565475486864645767844585465884467586667565773377733634663557773445746422526356353452324542 +312423654364225622226637376343347535467656737454465678885885746745857776864757467665478865575446666474647437757675757473645242266443443325554 +333352266326435462625366644556555677753333564555775666584874665848744466545484587654854464745467733645434647766364433755226524223666554626514 +435132545534652226544462427766367457556547533646553733455368768864748656858757658764667566573447736343373755745347737256566566356246552554344 +251251242554456622643453332655755467667663776573476475365556464548586464744786567334573766376654353443634574576453465245553624544653336543111 +212442344546526645642263244654774376666364765664337477476566755735634734545547537453654634467644564673444576465347666352444336246443534225131 +112553156446434342262332632662776733455533536546447357345533465336456677743746473675453643333635675467467446533763524242322555366262662253531 +211154334644242354452264624333677734447567476373463347474347444453644577737565635654763766744377535655635747756455462332222243526345542432111 +452531315135444354222633542256663373756457456776563646334754543544575364335767774564575736767736775545744343363363624653264666332236225512123 +554211544546426525425562633634342635553437466647567764434744664546375647473767773675456535466347457734537637645252643554463622523335443333224 +334533452455542655362226365236322545337345466373753756677574663767643737437554464546345477754476745457537446262223644636236336656625515513231 +452555231215326224366256565643522266556465346746347363633645746436473667767556763464673664753345776465737364364536446645553352366221223144345 +514335112142516342564642545262662364262353574573475464554553456636477477446756645474374646364357353537766264336222226532264353454144251545325 +152522253244513266563264433552644226246665674554677745755364563737344773646764375565657457543353753423534335226422232656264234264153315553535 +324514541241141455232546254624542356544332452737546335476443477344545643434547765335573737455674436465526432346264244552654644651313224214233 +213141543243524321434324633656252333252323653563475667336736466576733354556565346365373663374333256546644423653255346636444624514124522425212 diff --git a/day17/sample1.in b/day17/sample1.in new file mode 100644 index 0000000..f400d6e --- /dev/null +++ b/day17/sample1.in @@ -0,0 +1,13 @@ +2413432311323 +3215453535623 +3255245654254 +3446585845452 +4546657867536 +1438598798454 +4457876987766 +3637877979653 +4654967986887 +4564679986453 +1224686865563 +2546548887735 +4322674655533 diff --git a/day17/sol.py b/day17/sol.py new file mode 100644 index 0000000..6ad10b4 --- /dev/null +++ b/day17/sol.py @@ -0,0 +1,61 @@ +import astar + +def read_input(f): + map = [] + for line in f: + map.append([int(x) for x in line.strip()]) + return map + +def solve(map,part=1): + start = (0,0,(0,0),0) + goal = (len(map)-1,len(map[-1])-1) + def is_goal(x): + return (x[1],x[0]) == goal + def neighbors(state): + y,x,dir,count = state + next = [] + def go(dx,dy): + if (-dx,-dy) == dir: + # can't turn around + return + newx = x + dx + newy = y + dy + if (dx,dy) == dir: + newcount = count+1 + else: + newcount = 1 + if part == 1: + if newcount > 3: + return + if part == 2: + if newcount > 10: + return + if newcount <= count < 4: + return + if (0 <= newy < len(map)) and (0 <= newx < len(map[newy])): + next.append((map[y][x], (newy, newx, (dx,dy), newcount))) + go(-1,0) + go(+1,0) + go(0,-1) + go(0,+1) + return next + + cost, node, path = astar.search(start, is_goal, neighbors) + print(cost) # TODO: off by one somehow? + print([(x,y) for (y,x,_,_) in path]) + print(''.join(dir2s(d) for (_,_,d,_) in path)) + costs = [map[y][x] for (y,x,_,_) in path[1:]] + print(costs) + print(sum(costs)) + +def dir2s(d): + if d == (0,1): return "v" + if d == (0,-1): return "^" + if d == (1,0): return ">" + if d == (-1,0): return "<" + return "?" + +import sys +map = read_input(sys.stdin) +solve(map, part=1) +solve(map, part=2)