Compare commits
25 Commits
da25b73eca
...
main
Author | SHA1 | Date | |
---|---|---|---|
48c96ce7ea
|
|||
342f4c1883
|
|||
881d0b08ad
|
|||
c1eb7761e3
|
|||
98456ed98d
|
|||
d6d4c0d056
|
|||
3bb3b3d6b6
|
|||
dd91259fe2
|
|||
8495969877
|
|||
190fc92842
|
|||
eb6c1f42cd
|
|||
512b05f624
|
|||
877101f9a2
|
|||
cdfecf821c
|
|||
2b921b5fb2
|
|||
a5dea64b32
|
|||
8200c1a8cf
|
|||
8d178ddfc6
|
|||
3bc073f9b8
|
|||
0a9fa8e32f
|
|||
e65c17c8e6
|
|||
3ee26cefe5
|
|||
9e37b2ce66
|
|||
d422c9b84e
|
|||
5efa9853ca
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
**/target
|
**/target
|
||||||
|
input
|
||||||
|
1
.rustfmt.toml
Normal file
1
.rustfmt.toml
Normal file
@ -0,0 +1 @@
|
|||||||
|
max_width = 120
|
141
17/Cargo.lock
generated
Normal file
141
17/Cargo.lock
generated
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day17"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"termcolor",
|
||||||
|
"test-case",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||||
|
dependencies = [
|
||||||
|
"test-case-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-core"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-macros"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"test-case-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
11
17/Cargo.toml
Normal file
11
17/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day17"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
termcolor = "1.4.0"
|
||||||
|
test-case = "3.3.1"
|
141
17/input
Normal file
141
17/input
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
325324343122414426341311521355436756516735365767735336243266456152424263655442375437323425146317632655141433156665635625563452536534233413111
|
||||||
|
445243425411645566112351545244163515223165477656331552463117221625365717275545124476464451442531715677337534443363223313661263112221651414352
|
||||||
|
434514252414363452511152554236546325615346321237216231776737145123246363247221568835776177657563335176174462444145653231645541641352324222432
|
||||||
|
512344115556454364551122335531173547353527264165771324616431564154352161434333624143426673724271674725735171453732677454152514121553642514342
|
||||||
|
245335631545534511262451241637156561454332212544137121477616833536676467486356424113643275743254655271257165273233333713436363316152215525412
|
||||||
|
525134431665424254245311755242225774344146256415414763387571367658688754454216857288228327638844315166557547372743531744154253555366125322251
|
||||||
|
242226151434514231642522163777343413375375427786665751532313584425311152314384883312415875143615383175544722257361643371324456124635121426143
|
||||||
|
355256351224414362134546117516475527772757412718633456138147647447166316435131753115166364762163147767575652646664125323524233344211152621644
|
||||||
|
423662265151444333172175576611421743625662125375255611436332835555433412245516663422413367584728254346217161613476513362411124354554141656661
|
||||||
|
343132241425514222366532375754443311661867761827448367742356551447788222565282822336472646562481274186323321263463733172737523415231263231452
|
||||||
|
414512633246125157451572561554537454722163673577424576376853177774626628186236767857316633668123264385753152773455553614673334436441316224135
|
||||||
|
212324565521155353412567475573615133714344617411175657288438127655616781713123465347422118615674666483872652757672245614227473525561435343566
|
||||||
|
445221414451625675624645665212427183844173224183625244868437762281745333878761243125126616283437123288348253513642236266513777143336423452244
|
||||||
|
363544111542646272625122735154448186467255668146344132826437421272718576129612166754885626667262876277185872166576146412755315427431235361345
|
||||||
|
264656533336664366256136422751241622361444458382586165836578937121934658199719386351541531343455316352721641517715741643374346623641245141642
|
||||||
|
112445611653647577632776715757651127562631764334214565265123726662877597342896255454454353581576436364858847152147334456111671241736213243235
|
||||||
|
555625554155515642753141133472357442522378575788761684343125889676496481416737941365773489236312262742358647378637816625524652376464221145552
|
||||||
|
166212536136161764262663264151715412324265162172461388359546247927137713732357391885873753572632213528125746133582543132557354616253656161125
|
||||||
|
262214154431312345513141264637587481623632438762129328373598884879612652692926671574635499263972534168721832253467846424556241116716116355662
|
||||||
|
135241432555162671524462538183836241418472746146531476679922477637662841812239647283188595978522895688251211412744783771567244452546153345245
|
||||||
|
532216637311743517223634115741886133752415248862823922293142226987777614157674447415432957111246289861372245785828235814464543732552357524115
|
||||||
|
146561263436471442615526287283328418146343943213682363991837281378678451857923183343659739289952517643483666668454477612872264623531527114156
|
||||||
|
553563547345231122325535834576322628262281752991871677465471578556275546387834293362893217319352873468631622524488454757543336657573343346231
|
||||||
|
266564156547622167463643435425825221285933354618914693416371827482999473949778132544823891982233412759525148822255432468651261727135416714414
|
||||||
|
241435326144677632666655834466775762193454726392523657676252731186895484227244331982511164875543224648614243615642216164551727621224255321645
|
||||||
|
165625766274415126221387567754684125769562911449418567328954999269442383397657742111976735747616543945193885678317732613823354147551434172254
|
||||||
|
663471266547665567383385744766857544125555773727948178721595766362768764763389283465275425521861727174339179777676482636283377221474131172664
|
||||||
|
552267351614751263715528842613544492131357823275224224529882976386327823433479377684379863655876688634865837667534467375571818473234352527123
|
||||||
|
417167733326125612732158464675728774915115736789599864674655267296528289764653496935556672211933382185491674889326327638863358225141641776661
|
||||||
|
553433447763465113852224382474727588458713673836733584749236658844822472658497492547688383864951836467139432662174767657312876885715517172566
|
||||||
|
667541167336254488524837342876671664656562954852183656576233333873254363945623456596769545333862526193411672878826354158866344875721272113745
|
||||||
|
742742423566122778386568143632291815363624774439785729782249926489483479225989595798258826325346485866553327934443377824316727757316672416437
|
||||||
|
422416173617118884742181153285466515613425316646999647735464985688784946488843572663439527248557925282489796183853745584334188218713316517611
|
||||||
|
763175754752411761475574463499814429498138728567958989277844494897966247687976299566598923968224276327562217938234278212488752542237314351724
|
||||||
|
556357515132757111313386163174758761223833727635896636363788757464722947589395479356794346762935869851131172237499953267126584137242266563332
|
||||||
|
553452514551382115465845459551888517462873873925388334689354634986788558835365333394575696667743754281865874432573149225448868716422314153151
|
||||||
|
727477115766217727216544583899411845473274393224259527268426677665382498542244536749359523368784334883684284657479479623145838735713142311641
|
||||||
|
623775723417856274672723115245954791372868276248326532785676923354468396436867556933672689642689493334426665994793891938554866266411441635464
|
||||||
|
357655727381528486471438934682246867878728953726863365263395378599979499989445494543554685888797994457246284425146494523847682845162841467676
|
||||||
|
713225442368616642825874251457728254726498336436857496884894665436838647759737379449974974472942976778385826682519218241645473616645531255227
|
||||||
|
143115132751882814645234335693993315693492273544964459798578395446856796646994466763377345499557552788438771441525234336612412423834346523211
|
||||||
|
563124357115326738651179813293721543858493473499475888785648678877598767685393985868373765343793387586922432532313835672612126152631344576713
|
||||||
|
161643744871583517778716716592732854695358997554424874653584484749995659355969399657538739855335364842584499341554829664297243422443742217627
|
||||||
|
314417571311644786676857812476382568772944752389723949877773676947654886977363564564656448787568736238564893432112877333626254348575386766736
|
||||||
|
776344328255614461719768964778491246343236536693785358783954458767465334474845788383458739454343787762929647765239152374349167566558438427423
|
||||||
|
352364825562284245598758827867146952949744839636858679487354649333897878699343577583358936494456794644762845245583132395957674685442674213657
|
||||||
|
165116474648463674164854916648534936489844557493948573494559834384533436539877799979968846353597267726398358327688234857762963775536887664434
|
||||||
|
636244476616574846647739459365589464485573472239755849649363338696465548697637638734975433686777966529489995479371427436795444712248542244242
|
||||||
|
637735864354122638598582193357329687493754334369459855467953667653894978798833698638878588356346875628939527283866627761726597671516685427174
|
||||||
|
234265787355773655768346666121735692698653744885738497856483393689674898649577997399958433373787955768454347876736595261379656126328146286411
|
||||||
|
112767655742256845212962577375777649885299555457767374476434484654767654957948859747787796354688878783666798563553685971677619173751653125632
|
||||||
|
571453132563374754428433649129699672752544276898858748974354969458677564456979779546475974859365475874946272453658976328163915151248617627547
|
||||||
|
142583162475317422481573625624997475387877377975334869858698855546579585985975987879498939886539444982256287887973954241619679433725388527327
|
||||||
|
533247585173848868728351547857844568874594368494696993398568756785849787865568456854549687887848656666299259336837539132384839771741428127655
|
||||||
|
615468573841357563119491171796494694742954878467956458799956898567956945658585548466878737443834395395589454855236733372996957432151473455417
|
||||||
|
712281822873644374327211127428577898932274866883739393844879649754568787996648688464479984398399388463589596822886624259697865457588148666664
|
||||||
|
136562416585765349961939548589267679836968874647535938986445975695988894954468499449998546743964657957566429465497651995126318134132576252611
|
||||||
|
664553248645533826876894472974728737829658753737385958889458749467497446995476987665554788833743998485535738446299878511223783418241123523523
|
||||||
|
216673485271213882299775989884276937282689933697933446545787966965866999969865545756445677989389673844562259846887466538876636858727352514172
|
||||||
|
561327416424626319323885947575483566432886775386986678477789875855676946594954878464446759874339786347647885563257274772479849452341218853328
|
||||||
|
543414611273635871798538959594987265275776698754487659699789747885978996899658685697449894894533384458736853354975392764758672388138231227341
|
||||||
|
432177431672385492997519159785924344863965869338385868446897566987758776679699779999948444794449339687467966733362773574493894412663521343826
|
||||||
|
347125512661263615493994284268932764773443456439595658497689867498656657588955796748798799774383987946863496648669435744485628519485388635745
|
||||||
|
234414266212352323439914355995663935835737889578994846678946665969895859876758767589746666587937363599875397364293757755772863517557747336667
|
||||||
|
165677453767745981471984424575369862567689838893465684578767899768788798796576788458996788867998737468547692998985973389685897556471872623552
|
||||||
|
116786112155152692399989767286933237247737645595776648974959499775699595868698769845975468987579485487885883286826659428468372838324282111512
|
||||||
|
377586871572362673428351636972532524637489943754658469776969888985756695665668759579764745956864346579749772568358833311888124717127726527183
|
||||||
|
318164852453224592729434559244754674699557743559876747474974585695598957859985857696997477665456486667857796243525567741256626585522827113358
|
||||||
|
256655568346617621446653354665386832434445968933784544487764789798668576865577679764775445666453683457777446985583583616592962898181266224478
|
||||||
|
722447327541895771712452547924633958699394955868486968595868665886977559577966765766677478787645777643444882329378355275571729256528663733353
|
||||||
|
681245847143816872485464897478336665868833439643778745577556798997858795969859958658867557947956848853484479399665572351893714995112671712542
|
||||||
|
311381662366127117979691628467662497783389559654568448976988776969785977759865769596989799759496863598934465593797484374132873555158552238226
|
||||||
|
457474782125292676291123633778348492667699397478487495797899579777688999595566576657978586657959548666375867799586695984632767442686385738552
|
||||||
|
446616157875894869538721247895884644444883958939694686857454797576766596769678977878866756444843564374954453689422974856237432393117533128483
|
||||||
|
328513874786178732292652989455568257546978333547685649556859556989785958697896996969558664777693669444863357795442386542131312425674116545188
|
||||||
|
747847212285726534863559799474986827436555837479976774676546886866957568785596798586957654994685373975436492788443972514832361138572512654161
|
||||||
|
655775232613722364914271538968599287798576387849966696886855689868858988569956769648644589884777963696793654854647956227921717275975785623654
|
||||||
|
133381381437798727198762329677547326989373878353369696599978596599769677757779877555897759958668785498543442888697699371483636586223726547367
|
||||||
|
166558274267818548162234882895355743538677453683879454994868498865956757789887798484954454444478588833833824986689655715894154174185774415242
|
||||||
|
744372761363824188479933164279993635485947644456865846757657575569785868879855879598958794566895394956885434499837577347367422731518858612887
|
||||||
|
542154878866234222341249936289547276863933653697495455886575579875575878577655884578868949868795478447448539675945826676344156515447648384546
|
||||||
|
727648137147279312991745915569869748967897863693484548957585769676995776768899556467797877594595457565597942644325989896333716781667423243534
|
||||||
|
736513883717638924144115229662225798979374855467873564897654895888778776656646759488994944578647478549466472243343448517571862675853473616864
|
||||||
|
472573641838727179484843174326596238323797674954847658846499779979687897698786957488978957887393589648535875663387463691985638774236788623553
|
||||||
|
124821288351532635578793553795832779774448696673767567977447858477887878676469566499588899639674834547757355447365486454925564374273415537754
|
||||||
|
473366376825217384388358298858346676865647498858449537467576484448696554994844568658866985448999588568865694253572422898257449323363556414355
|
||||||
|
756585744556785281389581638793733695364655945467738676966784699696586944796568967556964687873563733383939393423897564823324453861637182853267
|
||||||
|
565377885838215871729589251946467492483786596678474736965759584646969695859846694554478644897956448493988952388686515531438553966563718473673
|
||||||
|
441237555152315781715534724764569644764966484434597935577849549996797944445598866585975464985538857347348739935777224728123383154322783665212
|
||||||
|
251538277583635525788213179949236983839585564657438535396857976586555596886987597784677479797768335698476345286595542471641181174621263365826
|
||||||
|
462645455814621845373415692662396785686584794946537846843758755467475597488876849747653439958865548869549767695386323199852847441248375338541
|
||||||
|
463546443547812219518172999856822775645249657899384888764384466588464496998699844799448386644993497387873285579539449217398533624347675543541
|
||||||
|
627134585837711668423259691198344552573775794347737374846947567564477798747547569756586957548779437697554747233864289854679427672835612465345
|
||||||
|
453427178468376465724244651434249467592372777377954886698995943799758965795489579878489647936487995475548384882447855836557219515272555272172
|
||||||
|
646164887363484557947971139665942397924584239956839476743645386597748689975975793667755335566355545754464596682873886675359686766371416867421
|
||||||
|
242564673372458178195363168781494567985469634643657747396363336558884388469558778894739837494797653627595967524589231722865526482421344174765
|
||||||
|
527234341744655648884683415323364239475568742248669646473336993435343838488698565959659888897554832493926543963268996957491745744384373681642
|
||||||
|
551517286282283171869299626636836973839926825529596737846853348847465543768893358499548363898668447899594793834437575675969522241126258282432
|
||||||
|
615113281186772747348241311277589768978579523525454785944673364478779885777788637938457768565594782776753548337442956913497758522663855544746
|
||||||
|
642722552558282717243186261369979747472328286247489597466575759788373865579784983835765597583957266269348476872977744141394534221775432834361
|
||||||
|
123255132786848881171289778858576544965558689395978795886845857873584539756667349675894535384688837649796799842596341266977334763116825677354
|
||||||
|
135221265824413236323157332895552381288822335555367339575879847894968958335438953379578775739548683874737377552721612721268151575627367374516
|
||||||
|
531372144561436544581261647461429475295794262997752694655885563973854977878549545376756598298288663367593432222189358593241862862567851525633
|
||||||
|
626241253623585223276449612369373315149376774267977495966454874953877799753954666837937985625362576929726958529984811986441465531615443642317
|
||||||
|
122237265686782174111763222458711389313762597662727299449372464353975654883644949566273662646296682598256439817316833461554838162575673712517
|
||||||
|
723263336441628827211586677967134954541492446275676949475759793974657373976875788542576364482493264736749878125328845632357141826286877316536
|
||||||
|
746376624247554234116778248423662686389547589753843874724295634799738747329256738622227935656823782646258367494222758652264524554281143475725
|
||||||
|
247227652554571866348233254561957766785945979683577957537487658236743744853762365675828364963779438767411174735912626572384742318221667753414
|
||||||
|
461752271733674688288542747127735521232319836579345595948435736687542357563568686627638662657552627936242586561889286338386747748155235227226
|
||||||
|
141456214273548658577623736731491554843413163948364432765456955986253284949329344329743583497259864561513822597516642174356653353313422722126
|
||||||
|
577514122213115543664523815812933592181557923163353748687669465747247978699468957873884592954895372236525435898266267231166186788652617642555
|
||||||
|
733555724377412472456818878267576986747564915594433739398666323228924448924829375982299639364766271435835929364781825316741447833326252417676
|
||||||
|
125222215152346652574685537442585295255477117856958664574265466997244968429967625364878556825897669923262572691766582725557644262753327717362
|
||||||
|
467157357433453135876225656776561727957327836923637932444972557496674222793666868922685325945691218298588167748387555736343614515634266527674
|
||||||
|
661776217564727341161434734284475862238735522767927168825678229454593732375258543947793974965685418316392331831342662517514464432121762671112
|
||||||
|
322226175666414714887813726538477315884488153872775481665957678523393653399286989356544792237258381256625891911364264883241763171167313676775
|
||||||
|
535433463745172562637474314438863546768596275157472615456823332796577429439255648883176346627241779499894798781815684141341115432556456643611
|
||||||
|
114516531415276157226232376712646274882692898428926131576766198472672582965649659239179984932272293221585428551187274518216722651334142336632
|
||||||
|
442465354622731723346571118328123567571116964772317433275893126613648877241944321925876477183764936251413286113213668326238173555355732216511
|
||||||
|
464545125331445744558616761437753623789891666294688255519735998824794952561825912628843557695114221545433384531731727161876473665573223373362
|
||||||
|
212622623666153674544543171825717224778543394854587565145835173211764734896255693756825741544633558375382657436484353324273475751235436535462
|
||||||
|
426456174161671373114214337372228811531433159234863841562359873663253579618768533225871676475124418634651463174367571421653316524135337216611
|
||||||
|
113264262762756157661221337642236412865163476628461551865256687522447798169631776999765762811667378264167441455366366874635763265145354445246
|
||||||
|
426635433223761674317156651435514314141128668545421467652684475967588596316618624557527821975129731666663738726663526335152162713322637353345
|
||||||
|
462625221553613622135255778417362232144315611424115765534629998153728136584747684638152634448139174522524258188274866446444754542614324644434
|
||||||
|
636534326173461144145272421245357854354484176813154881324324289844919955923398583536826126465974374482435317112341641177362167413653631136334
|
||||||
|
416121433661766275322466215778242625365252727337453283172471359263773988811988214463424763681262168421538852447148623325417465263633614152511
|
||||||
|
124165661313426677723346621157741741434378575443131887844322537341118644829916279535424761288166365435817422811564415651251116735711112164331
|
||||||
|
662213565461615664773261415161352365348334351167211364117737811331482474651845215456825315271337675186362621741624741731455143163362536213464
|
||||||
|
353163654655614552631221351147137158834856172472651447352645383627716833776783781867423336224623844544643183687212315514251544774456463166616
|
||||||
|
362441211445555544364416561477266288188517416482572255534821166861673587523181878873186281844855832334752187362742345667727277112563315642334
|
||||||
|
431663234654426537411563411631545147111423513725427621386471155234676712466243246352318626253227328241736815415232666553761366744242426616315
|
||||||
|
226531133633364435742641727266657131716261514281311262288684766444656242277146665425754546527885447432126232726412333341234543363451443141151
|
||||||
|
132441514114413263365254644654352543741828713741248814178464374241323848417341456825584538518825768881832262324114555671261641363331666134362
|
||||||
|
214126421452663325372554676727131463574734212374262156347777366377688162741748146151838743887681761444327446474521671324576334665511114122421
|
||||||
|
351531625361155425124432552645227655625173237845122258431184132246265282346434414371684686452682717564246721521767254276776656342611514416424
|
||||||
|
524134632564656514234312513351122255327641524888853223216877477886352121843137683831631511821167821614336237522461471235761565432361122352514
|
||||||
|
345434525245243335351164562536536325371562644423648433177446878843262728235726362818655267541335336453673667665743636625434415221611313542325
|
||||||
|
352232633361461221226332237671657471766723622375425212675228865561486835238657116512354337544131231554276255267433543145221253624656265664213
|
||||||
|
533341362332521262331624612755675274227615131761716775227664373273765866252331525736334615365731142562664711644136322541112142123112632614445
|
||||||
|
335424225554551224465145365617415232333565263422662657463575357742412565884351458348627343152461236262431544374247365213446446134632223333414
|
531
17/src/colormap.rs
Normal file
531
17/src/colormap.rs
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
use termcolor::Color;
|
||||||
|
|
||||||
|
pub struct ColorMap(&'static [Color]);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const COLORMAP_SMOOTH_COOLWARM: ColorMap = ColorMap(&[
|
||||||
|
Color::Rgb(59, 76, 19),
|
||||||
|
Color::Rgb(60, 78, 19),
|
||||||
|
Color::Rgb(61, 80, 19),
|
||||||
|
Color::Rgb(62, 81, 19),
|
||||||
|
Color::Rgb(63, 83, 19),
|
||||||
|
Color::Rgb(64, 85, 20),
|
||||||
|
Color::Rgb(66, 87, 20),
|
||||||
|
Color::Rgb(67, 88, 20),
|
||||||
|
Color::Rgb(68, 90, 20),
|
||||||
|
Color::Rgb(69, 92, 20),
|
||||||
|
Color::Rgb(70, 94, 20),
|
||||||
|
Color::Rgb(72, 95, 20),
|
||||||
|
Color::Rgb(73, 97, 21),
|
||||||
|
Color::Rgb(74, 99, 21),
|
||||||
|
Color::Rgb(75, 100, 21),
|
||||||
|
Color::Rgb(76, 102, 21),
|
||||||
|
Color::Rgb(78, 104, 21),
|
||||||
|
Color::Rgb(79, 106, 21),
|
||||||
|
Color::Rgb(80, 107, 21),
|
||||||
|
Color::Rgb(81, 109, 21),
|
||||||
|
Color::Rgb(83, 111, 22),
|
||||||
|
Color::Rgb(84, 112, 22),
|
||||||
|
Color::Rgb(85, 114, 22),
|
||||||
|
Color::Rgb(86, 116, 22),
|
||||||
|
Color::Rgb(88, 117, 22),
|
||||||
|
Color::Rgb(89, 119, 22),
|
||||||
|
Color::Rgb(90, 120, 22),
|
||||||
|
Color::Rgb(91, 122, 22),
|
||||||
|
Color::Rgb(93, 124, 23),
|
||||||
|
Color::Rgb(94, 125, 23),
|
||||||
|
Color::Rgb(95, 127, 23),
|
||||||
|
Color::Rgb(97, 129, 23),
|
||||||
|
Color::Rgb(98, 130, 23),
|
||||||
|
Color::Rgb(99, 132, 23),
|
||||||
|
Color::Rgb(101, 133, 23),
|
||||||
|
Color::Rgb(102, 135, 23),
|
||||||
|
Color::Rgb(103, 136, 23),
|
||||||
|
Color::Rgb(105, 138, 23),
|
||||||
|
Color::Rgb(106, 140, 24),
|
||||||
|
Color::Rgb(107, 141, 24),
|
||||||
|
Color::Rgb(109, 143, 24),
|
||||||
|
Color::Rgb(110, 144, 24),
|
||||||
|
Color::Rgb(111, 146, 24),
|
||||||
|
Color::Rgb(113, 147, 24),
|
||||||
|
Color::Rgb(114, 149, 24),
|
||||||
|
Color::Rgb(115, 150, 24),
|
||||||
|
Color::Rgb(117, 152, 24),
|
||||||
|
Color::Rgb(118, 153, 24),
|
||||||
|
Color::Rgb(119, 154, 24),
|
||||||
|
Color::Rgb(121, 156, 24),
|
||||||
|
Color::Rgb(122, 157, 24),
|
||||||
|
Color::Rgb(123, 159, 24),
|
||||||
|
Color::Rgb(125, 160, 24),
|
||||||
|
Color::Rgb(126, 162, 25),
|
||||||
|
Color::Rgb(128, 163, 25),
|
||||||
|
Color::Rgb(129, 164, 25),
|
||||||
|
Color::Rgb(130, 166, 25),
|
||||||
|
Color::Rgb(132, 167, 25),
|
||||||
|
Color::Rgb(133, 168, 25),
|
||||||
|
Color::Rgb(134, 170, 25),
|
||||||
|
Color::Rgb(136, 171, 25),
|
||||||
|
Color::Rgb(137, 172, 25),
|
||||||
|
Color::Rgb(139, 174, 25),
|
||||||
|
Color::Rgb(140, 175, 25),
|
||||||
|
Color::Rgb(141, 176, 25),
|
||||||
|
Color::Rgb(143, 177, 25),
|
||||||
|
Color::Rgb(144, 178, 25),
|
||||||
|
Color::Rgb(146, 180, 25),
|
||||||
|
Color::Rgb(147, 181, 25),
|
||||||
|
Color::Rgb(148, 182, 25),
|
||||||
|
Color::Rgb(150, 183, 25),
|
||||||
|
Color::Rgb(151, 184, 25),
|
||||||
|
Color::Rgb(153, 186, 25),
|
||||||
|
Color::Rgb(154, 187, 25),
|
||||||
|
Color::Rgb(155, 188, 25),
|
||||||
|
Color::Rgb(157, 189, 25),
|
||||||
|
Color::Rgb(158, 190, 25),
|
||||||
|
Color::Rgb(159, 191, 25),
|
||||||
|
Color::Rgb(161, 192, 25),
|
||||||
|
Color::Rgb(162, 193, 25),
|
||||||
|
Color::Rgb(163, 194, 25),
|
||||||
|
Color::Rgb(165, 195, 25),
|
||||||
|
Color::Rgb(166, 196, 25),
|
||||||
|
Color::Rgb(168, 197, 25),
|
||||||
|
Color::Rgb(169, 198, 25),
|
||||||
|
Color::Rgb(170, 199, 25),
|
||||||
|
Color::Rgb(172, 200, 25),
|
||||||
|
Color::Rgb(173, 201, 25),
|
||||||
|
Color::Rgb(174, 201, 25),
|
||||||
|
Color::Rgb(176, 202, 25),
|
||||||
|
Color::Rgb(177, 203, 25),
|
||||||
|
Color::Rgb(178, 204, 25),
|
||||||
|
Color::Rgb(180, 205, 25),
|
||||||
|
Color::Rgb(181, 206, 25),
|
||||||
|
Color::Rgb(182, 206, 25),
|
||||||
|
Color::Rgb(183, 207, 24),
|
||||||
|
Color::Rgb(185, 208, 24),
|
||||||
|
Color::Rgb(186, 209, 24),
|
||||||
|
Color::Rgb(187, 209, 24),
|
||||||
|
Color::Rgb(189, 210, 24),
|
||||||
|
Color::Rgb(190, 211, 24),
|
||||||
|
Color::Rgb(191, 211, 24),
|
||||||
|
Color::Rgb(192, 212, 24),
|
||||||
|
Color::Rgb(193, 212, 24),
|
||||||
|
Color::Rgb(195, 213, 24),
|
||||||
|
Color::Rgb(196, 214, 24),
|
||||||
|
Color::Rgb(197, 214, 24),
|
||||||
|
Color::Rgb(198, 215, 24),
|
||||||
|
Color::Rgb(200, 215, 24),
|
||||||
|
Color::Rgb(201, 216, 24),
|
||||||
|
Color::Rgb(202, 216, 23),
|
||||||
|
Color::Rgb(203, 216, 23),
|
||||||
|
Color::Rgb(204, 217, 23),
|
||||||
|
Color::Rgb(205, 217, 23),
|
||||||
|
Color::Rgb(206, 218, 23),
|
||||||
|
Color::Rgb(208, 218, 23),
|
||||||
|
Color::Rgb(209, 218, 23),
|
||||||
|
Color::Rgb(210, 219, 23),
|
||||||
|
Color::Rgb(211, 219, 23),
|
||||||
|
Color::Rgb(212, 219, 23),
|
||||||
|
Color::Rgb(213, 219, 22),
|
||||||
|
Color::Rgb(214, 220, 22),
|
||||||
|
Color::Rgb(215, 220, 22),
|
||||||
|
Color::Rgb(216, 220, 22),
|
||||||
|
Color::Rgb(217, 220, 22),
|
||||||
|
Color::Rgb(218, 220, 22),
|
||||||
|
Color::Rgb(219, 221, 22),
|
||||||
|
Color::Rgb(220, 221, 22),
|
||||||
|
Color::Rgb(221, 220, 22),
|
||||||
|
Color::Rgb(222, 220, 21),
|
||||||
|
Color::Rgb(223, 220, 21),
|
||||||
|
Color::Rgb(225, 219, 21),
|
||||||
|
Color::Rgb(226, 218, 21),
|
||||||
|
Color::Rgb(227, 218, 21),
|
||||||
|
Color::Rgb(228, 217, 21),
|
||||||
|
Color::Rgb(229, 217, 21),
|
||||||
|
Color::Rgb(229, 216, 20),
|
||||||
|
Color::Rgb(230, 216, 20),
|
||||||
|
Color::Rgb(231, 215, 20),
|
||||||
|
Color::Rgb(232, 214, 20),
|
||||||
|
Color::Rgb(233, 214, 20),
|
||||||
|
Color::Rgb(234, 213, 20),
|
||||||
|
Color::Rgb(235, 212, 20),
|
||||||
|
Color::Rgb(235, 211, 19),
|
||||||
|
Color::Rgb(236, 211, 19),
|
||||||
|
Color::Rgb(237, 210, 19),
|
||||||
|
Color::Rgb(238, 209, 19),
|
||||||
|
Color::Rgb(238, 208, 19),
|
||||||
|
Color::Rgb(239, 207, 19),
|
||||||
|
Color::Rgb(239, 206, 18),
|
||||||
|
Color::Rgb(240, 206, 18),
|
||||||
|
Color::Rgb(241, 205, 18),
|
||||||
|
Color::Rgb(241, 204, 18),
|
||||||
|
Color::Rgb(242, 203, 18),
|
||||||
|
Color::Rgb(242, 202, 18),
|
||||||
|
Color::Rgb(243, 201, 18),
|
||||||
|
Color::Rgb(243, 200, 17),
|
||||||
|
Color::Rgb(244, 199, 17),
|
||||||
|
Color::Rgb(244, 198, 17),
|
||||||
|
Color::Rgb(244, 197, 17),
|
||||||
|
Color::Rgb(245, 196, 17),
|
||||||
|
Color::Rgb(245, 195, 17),
|
||||||
|
Color::Rgb(245, 193, 16),
|
||||||
|
Color::Rgb(246, 192, 16),
|
||||||
|
Color::Rgb(246, 191, 16),
|
||||||
|
Color::Rgb(246, 190, 16),
|
||||||
|
Color::Rgb(246, 189, 16),
|
||||||
|
Color::Rgb(247, 188, 16),
|
||||||
|
Color::Rgb(247, 186, 15),
|
||||||
|
Color::Rgb(247, 185, 15),
|
||||||
|
Color::Rgb(247, 184, 15),
|
||||||
|
Color::Rgb(247, 183, 15),
|
||||||
|
Color::Rgb(247, 181, 15),
|
||||||
|
Color::Rgb(247, 180, 15),
|
||||||
|
Color::Rgb(247, 179, 15),
|
||||||
|
Color::Rgb(247, 177, 14),
|
||||||
|
Color::Rgb(247, 176, 14),
|
||||||
|
Color::Rgb(247, 175, 14),
|
||||||
|
Color::Rgb(247, 173, 14),
|
||||||
|
Color::Rgb(247, 172, 14),
|
||||||
|
Color::Rgb(247, 171, 14),
|
||||||
|
Color::Rgb(247, 169, 13),
|
||||||
|
Color::Rgb(247, 168, 13),
|
||||||
|
Color::Rgb(247, 166, 13),
|
||||||
|
Color::Rgb(246, 165, 13),
|
||||||
|
Color::Rgb(246, 163, 13),
|
||||||
|
Color::Rgb(246, 162, 13),
|
||||||
|
Color::Rgb(246, 160, 12),
|
||||||
|
Color::Rgb(245, 159, 12),
|
||||||
|
Color::Rgb(245, 157, 12),
|
||||||
|
Color::Rgb(245, 156, 12),
|
||||||
|
Color::Rgb(244, 154, 12),
|
||||||
|
Color::Rgb(244, 153, 12),
|
||||||
|
Color::Rgb(244, 151, 12),
|
||||||
|
Color::Rgb(243, 149, 11),
|
||||||
|
Color::Rgb(243, 148, 11),
|
||||||
|
Color::Rgb(242, 146, 11),
|
||||||
|
Color::Rgb(242, 144, 11),
|
||||||
|
Color::Rgb(241, 143, 11),
|
||||||
|
Color::Rgb(241, 141, 11),
|
||||||
|
Color::Rgb(240, 139, 11),
|
||||||
|
Color::Rgb(240, 138, 10),
|
||||||
|
Color::Rgb(239, 136, 10),
|
||||||
|
Color::Rgb(238, 134, 10),
|
||||||
|
Color::Rgb(238, 133, 10),
|
||||||
|
Color::Rgb(237, 131, 10),
|
||||||
|
Color::Rgb(237, 129, 10),
|
||||||
|
Color::Rgb(236, 127, 99),
|
||||||
|
Color::Rgb(235, 125, 98),
|
||||||
|
Color::Rgb(234, 124, 96),
|
||||||
|
Color::Rgb(234, 122, 95),
|
||||||
|
Color::Rgb(233, 120, 93),
|
||||||
|
Color::Rgb(232, 118, 92),
|
||||||
|
Color::Rgb(231, 116, 91),
|
||||||
|
Color::Rgb(230, 114, 89),
|
||||||
|
Color::Rgb(229, 112, 88),
|
||||||
|
Color::Rgb(229, 111, 86),
|
||||||
|
Color::Rgb(228, 109, 85),
|
||||||
|
Color::Rgb(227, 107, 84),
|
||||||
|
Color::Rgb(226, 105, 82),
|
||||||
|
Color::Rgb(225, 103, 81),
|
||||||
|
Color::Rgb(224, 101, 79),
|
||||||
|
Color::Rgb(223, 99, 78),
|
||||||
|
Color::Rgb(222, 97, 77),
|
||||||
|
Color::Rgb(221, 95, 75),
|
||||||
|
Color::Rgb(220, 93, 74),
|
||||||
|
Color::Rgb(219, 91, 73),
|
||||||
|
Color::Rgb(218, 89, 71),
|
||||||
|
Color::Rgb(216, 86, 70),
|
||||||
|
Color::Rgb(215, 84, 69),
|
||||||
|
Color::Rgb(214, 82, 68),
|
||||||
|
Color::Rgb(213, 80, 66),
|
||||||
|
Color::Rgb(212, 78, 65),
|
||||||
|
Color::Rgb(211, 76, 64),
|
||||||
|
Color::Rgb(209, 73, 62),
|
||||||
|
Color::Rgb(208, 71, 61),
|
||||||
|
Color::Rgb(207, 69, 60),
|
||||||
|
Color::Rgb(206, 67, 59),
|
||||||
|
Color::Rgb(204, 64, 57),
|
||||||
|
Color::Rgb(203, 62, 56),
|
||||||
|
Color::Rgb(202, 59, 55),
|
||||||
|
Color::Rgb(200, 57, 54),
|
||||||
|
Color::Rgb(199, 54, 53),
|
||||||
|
Color::Rgb(198, 52, 52),
|
||||||
|
Color::Rgb(196, 49, 50),
|
||||||
|
Color::Rgb(195, 46, 49),
|
||||||
|
Color::Rgb(193, 43, 48),
|
||||||
|
Color::Rgb(192, 40, 47),
|
||||||
|
Color::Rgb(191, 37, 46),
|
||||||
|
Color::Rgb(189, 34, 45),
|
||||||
|
Color::Rgb(188, 30, 44),
|
||||||
|
Color::Rgb(186, 26, 43),
|
||||||
|
Color::Rgb(185, 22, 41),
|
||||||
|
Color::Rgb(183, 17, 40),
|
||||||
|
Color::Rgb(182, 11, 39),
|
||||||
|
Color::Rgb(180, 4, 38),
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const COLORMAP_INFERNO: ColorMap = ColorMap(&[
|
||||||
|
Color::Rgb(0, 0, 4),
|
||||||
|
Color::Rgb(1, 0, 5),
|
||||||
|
Color::Rgb(1, 1, 6),
|
||||||
|
Color::Rgb(1, 1, 8),
|
||||||
|
Color::Rgb(2, 1, 10),
|
||||||
|
Color::Rgb(2, 2, 12),
|
||||||
|
Color::Rgb(2, 2, 14),
|
||||||
|
Color::Rgb(3, 2, 16),
|
||||||
|
Color::Rgb(4, 3, 18),
|
||||||
|
Color::Rgb(4, 3, 20),
|
||||||
|
Color::Rgb(5, 4, 23),
|
||||||
|
Color::Rgb(6, 4, 25),
|
||||||
|
Color::Rgb(7, 5, 27),
|
||||||
|
Color::Rgb(8, 5, 29),
|
||||||
|
Color::Rgb(9, 6, 31),
|
||||||
|
Color::Rgb(10, 7, 34),
|
||||||
|
Color::Rgb(11, 7, 36),
|
||||||
|
Color::Rgb(12, 8, 38),
|
||||||
|
Color::Rgb(13, 8, 41),
|
||||||
|
Color::Rgb(14, 9, 43),
|
||||||
|
Color::Rgb(16, 9, 45),
|
||||||
|
Color::Rgb(17, 10, 48),
|
||||||
|
Color::Rgb(18, 10, 50),
|
||||||
|
Color::Rgb(20, 11, 52),
|
||||||
|
Color::Rgb(21, 11, 55),
|
||||||
|
Color::Rgb(22, 11, 57),
|
||||||
|
Color::Rgb(24, 12, 60),
|
||||||
|
Color::Rgb(25, 12, 62),
|
||||||
|
Color::Rgb(27, 12, 65),
|
||||||
|
Color::Rgb(28, 12, 67),
|
||||||
|
Color::Rgb(30, 12, 69),
|
||||||
|
Color::Rgb(31, 12, 72),
|
||||||
|
Color::Rgb(33, 12, 74),
|
||||||
|
Color::Rgb(35, 12, 76),
|
||||||
|
Color::Rgb(36, 12, 79),
|
||||||
|
Color::Rgb(38, 12, 81),
|
||||||
|
Color::Rgb(40, 11, 83),
|
||||||
|
Color::Rgb(41, 11, 85),
|
||||||
|
Color::Rgb(43, 11, 87),
|
||||||
|
Color::Rgb(45, 11, 89),
|
||||||
|
Color::Rgb(47, 10, 91),
|
||||||
|
Color::Rgb(49, 10, 92),
|
||||||
|
Color::Rgb(50, 10, 94),
|
||||||
|
Color::Rgb(52, 10, 95),
|
||||||
|
Color::Rgb(54, 9, 97),
|
||||||
|
Color::Rgb(56, 9, 98),
|
||||||
|
Color::Rgb(57, 9, 99),
|
||||||
|
Color::Rgb(59, 9, 100),
|
||||||
|
Color::Rgb(61, 9, 101),
|
||||||
|
Color::Rgb(62, 9, 102),
|
||||||
|
Color::Rgb(64, 10, 103),
|
||||||
|
Color::Rgb(66, 10, 104),
|
||||||
|
Color::Rgb(68, 10, 104),
|
||||||
|
Color::Rgb(69, 10, 105),
|
||||||
|
Color::Rgb(71, 11, 106),
|
||||||
|
Color::Rgb(73, 11, 106),
|
||||||
|
Color::Rgb(74, 12, 107),
|
||||||
|
Color::Rgb(76, 12, 107),
|
||||||
|
Color::Rgb(77, 13, 108),
|
||||||
|
Color::Rgb(79, 13, 108),
|
||||||
|
Color::Rgb(81, 14, 108),
|
||||||
|
Color::Rgb(82, 14, 109),
|
||||||
|
Color::Rgb(84, 15, 109),
|
||||||
|
Color::Rgb(85, 15, 109),
|
||||||
|
Color::Rgb(87, 16, 110),
|
||||||
|
Color::Rgb(89, 16, 110),
|
||||||
|
Color::Rgb(90, 17, 110),
|
||||||
|
Color::Rgb(92, 18, 110),
|
||||||
|
Color::Rgb(93, 18, 110),
|
||||||
|
Color::Rgb(95, 19, 110),
|
||||||
|
Color::Rgb(97, 19, 110),
|
||||||
|
Color::Rgb(98, 20, 110),
|
||||||
|
Color::Rgb(100, 21, 110),
|
||||||
|
Color::Rgb(101, 21, 110),
|
||||||
|
Color::Rgb(103, 22, 110),
|
||||||
|
Color::Rgb(105, 22, 110),
|
||||||
|
Color::Rgb(106, 23, 110),
|
||||||
|
Color::Rgb(108, 24, 110),
|
||||||
|
Color::Rgb(109, 24, 110),
|
||||||
|
Color::Rgb(111, 25, 110),
|
||||||
|
Color::Rgb(113, 25, 110),
|
||||||
|
Color::Rgb(114, 26, 110),
|
||||||
|
Color::Rgb(116, 26, 110),
|
||||||
|
Color::Rgb(117, 27, 110),
|
||||||
|
Color::Rgb(119, 28, 109),
|
||||||
|
Color::Rgb(120, 28, 109),
|
||||||
|
Color::Rgb(122, 29, 109),
|
||||||
|
Color::Rgb(124, 29, 109),
|
||||||
|
Color::Rgb(125, 30, 109),
|
||||||
|
Color::Rgb(127, 30, 108),
|
||||||
|
Color::Rgb(128, 31, 108),
|
||||||
|
Color::Rgb(130, 32, 108),
|
||||||
|
Color::Rgb(132, 32, 107),
|
||||||
|
Color::Rgb(133, 33, 107),
|
||||||
|
Color::Rgb(135, 33, 107),
|
||||||
|
Color::Rgb(136, 34, 106),
|
||||||
|
Color::Rgb(138, 34, 106),
|
||||||
|
Color::Rgb(140, 35, 105),
|
||||||
|
Color::Rgb(141, 35, 105),
|
||||||
|
Color::Rgb(143, 36, 105),
|
||||||
|
Color::Rgb(144, 37, 104),
|
||||||
|
Color::Rgb(146, 37, 104),
|
||||||
|
Color::Rgb(147, 38, 103),
|
||||||
|
Color::Rgb(149, 38, 103),
|
||||||
|
Color::Rgb(151, 39, 102),
|
||||||
|
Color::Rgb(152, 39, 102),
|
||||||
|
Color::Rgb(154, 40, 101),
|
||||||
|
Color::Rgb(155, 41, 100),
|
||||||
|
Color::Rgb(157, 41, 100),
|
||||||
|
Color::Rgb(159, 42, 99),
|
||||||
|
Color::Rgb(160, 42, 99),
|
||||||
|
Color::Rgb(162, 43, 98),
|
||||||
|
Color::Rgb(163, 44, 97),
|
||||||
|
Color::Rgb(165, 44, 96),
|
||||||
|
Color::Rgb(166, 45, 96),
|
||||||
|
Color::Rgb(168, 46, 95),
|
||||||
|
Color::Rgb(169, 46, 94),
|
||||||
|
Color::Rgb(171, 47, 94),
|
||||||
|
Color::Rgb(173, 48, 93),
|
||||||
|
Color::Rgb(174, 48, 92),
|
||||||
|
Color::Rgb(176, 49, 91),
|
||||||
|
Color::Rgb(177, 50, 90),
|
||||||
|
Color::Rgb(179, 50, 90),
|
||||||
|
Color::Rgb(180, 51, 89),
|
||||||
|
Color::Rgb(182, 52, 88),
|
||||||
|
Color::Rgb(183, 53, 87),
|
||||||
|
Color::Rgb(185, 53, 86),
|
||||||
|
Color::Rgb(186, 54, 85),
|
||||||
|
Color::Rgb(188, 55, 84),
|
||||||
|
Color::Rgb(189, 56, 83),
|
||||||
|
Color::Rgb(191, 57, 82),
|
||||||
|
Color::Rgb(192, 58, 81),
|
||||||
|
Color::Rgb(193, 58, 80),
|
||||||
|
Color::Rgb(195, 59, 79),
|
||||||
|
Color::Rgb(196, 60, 78),
|
||||||
|
Color::Rgb(198, 61, 77),
|
||||||
|
Color::Rgb(199, 62, 76),
|
||||||
|
Color::Rgb(200, 63, 75),
|
||||||
|
Color::Rgb(202, 64, 74),
|
||||||
|
Color::Rgb(203, 65, 73),
|
||||||
|
Color::Rgb(204, 66, 72),
|
||||||
|
Color::Rgb(206, 67, 71),
|
||||||
|
Color::Rgb(207, 68, 70),
|
||||||
|
Color::Rgb(208, 69, 69),
|
||||||
|
Color::Rgb(210, 70, 68),
|
||||||
|
Color::Rgb(211, 71, 67),
|
||||||
|
Color::Rgb(212, 72, 66),
|
||||||
|
Color::Rgb(213, 74, 65),
|
||||||
|
Color::Rgb(215, 75, 63),
|
||||||
|
Color::Rgb(216, 76, 62),
|
||||||
|
Color::Rgb(217, 77, 61),
|
||||||
|
Color::Rgb(218, 78, 60),
|
||||||
|
Color::Rgb(219, 80, 59),
|
||||||
|
Color::Rgb(221, 81, 58),
|
||||||
|
Color::Rgb(222, 82, 56),
|
||||||
|
Color::Rgb(223, 83, 55),
|
||||||
|
Color::Rgb(224, 85, 54),
|
||||||
|
Color::Rgb(225, 86, 53),
|
||||||
|
Color::Rgb(226, 87, 52),
|
||||||
|
Color::Rgb(227, 89, 51),
|
||||||
|
Color::Rgb(228, 90, 49),
|
||||||
|
Color::Rgb(229, 92, 48),
|
||||||
|
Color::Rgb(230, 93, 47),
|
||||||
|
Color::Rgb(231, 94, 46),
|
||||||
|
Color::Rgb(232, 96, 45),
|
||||||
|
Color::Rgb(233, 97, 43),
|
||||||
|
Color::Rgb(234, 99, 42),
|
||||||
|
Color::Rgb(235, 100, 41),
|
||||||
|
Color::Rgb(235, 102, 40),
|
||||||
|
Color::Rgb(236, 103, 38),
|
||||||
|
Color::Rgb(237, 105, 37),
|
||||||
|
Color::Rgb(238, 106, 36),
|
||||||
|
Color::Rgb(239, 108, 35),
|
||||||
|
Color::Rgb(239, 110, 33),
|
||||||
|
Color::Rgb(240, 111, 32),
|
||||||
|
Color::Rgb(241, 113, 31),
|
||||||
|
Color::Rgb(241, 115, 29),
|
||||||
|
Color::Rgb(242, 116, 28),
|
||||||
|
Color::Rgb(243, 118, 27),
|
||||||
|
Color::Rgb(243, 120, 25),
|
||||||
|
Color::Rgb(244, 121, 24),
|
||||||
|
Color::Rgb(245, 123, 23),
|
||||||
|
Color::Rgb(245, 125, 21),
|
||||||
|
Color::Rgb(246, 126, 20),
|
||||||
|
Color::Rgb(246, 128, 19),
|
||||||
|
Color::Rgb(247, 130, 18),
|
||||||
|
Color::Rgb(247, 132, 16),
|
||||||
|
Color::Rgb(248, 133, 15),
|
||||||
|
Color::Rgb(248, 135, 14),
|
||||||
|
Color::Rgb(248, 137, 12),
|
||||||
|
Color::Rgb(249, 139, 11),
|
||||||
|
Color::Rgb(249, 140, 10),
|
||||||
|
Color::Rgb(249, 142, 9),
|
||||||
|
Color::Rgb(250, 144, 8),
|
||||||
|
Color::Rgb(250, 146, 7),
|
||||||
|
Color::Rgb(250, 148, 7),
|
||||||
|
Color::Rgb(251, 150, 6),
|
||||||
|
Color::Rgb(251, 151, 6),
|
||||||
|
Color::Rgb(251, 153, 6),
|
||||||
|
Color::Rgb(251, 155, 6),
|
||||||
|
Color::Rgb(251, 157, 7),
|
||||||
|
Color::Rgb(252, 159, 7),
|
||||||
|
Color::Rgb(252, 161, 8),
|
||||||
|
Color::Rgb(252, 163, 9),
|
||||||
|
Color::Rgb(252, 165, 10),
|
||||||
|
Color::Rgb(252, 166, 12),
|
||||||
|
Color::Rgb(252, 168, 13),
|
||||||
|
Color::Rgb(252, 170, 15),
|
||||||
|
Color::Rgb(252, 172, 17),
|
||||||
|
Color::Rgb(252, 174, 18),
|
||||||
|
Color::Rgb(252, 176, 20),
|
||||||
|
Color::Rgb(252, 178, 22),
|
||||||
|
Color::Rgb(252, 180, 24),
|
||||||
|
Color::Rgb(251, 182, 26),
|
||||||
|
Color::Rgb(251, 184, 29),
|
||||||
|
Color::Rgb(251, 186, 31),
|
||||||
|
Color::Rgb(251, 188, 33),
|
||||||
|
Color::Rgb(251, 190, 35),
|
||||||
|
Color::Rgb(250, 192, 38),
|
||||||
|
Color::Rgb(250, 194, 40),
|
||||||
|
Color::Rgb(250, 196, 42),
|
||||||
|
Color::Rgb(250, 198, 45),
|
||||||
|
Color::Rgb(249, 199, 47),
|
||||||
|
Color::Rgb(249, 201, 50),
|
||||||
|
Color::Rgb(249, 203, 53),
|
||||||
|
Color::Rgb(248, 205, 55),
|
||||||
|
Color::Rgb(248, 207, 58),
|
||||||
|
Color::Rgb(247, 209, 61),
|
||||||
|
Color::Rgb(247, 211, 64),
|
||||||
|
Color::Rgb(246, 213, 67),
|
||||||
|
Color::Rgb(246, 215, 70),
|
||||||
|
Color::Rgb(245, 217, 73),
|
||||||
|
Color::Rgb(245, 219, 76),
|
||||||
|
Color::Rgb(244, 221, 79),
|
||||||
|
Color::Rgb(244, 223, 83),
|
||||||
|
Color::Rgb(244, 225, 86),
|
||||||
|
Color::Rgb(243, 227, 90),
|
||||||
|
Color::Rgb(243, 229, 93),
|
||||||
|
Color::Rgb(242, 230, 97),
|
||||||
|
Color::Rgb(242, 232, 101),
|
||||||
|
Color::Rgb(242, 234, 105),
|
||||||
|
Color::Rgb(241, 236, 109),
|
||||||
|
Color::Rgb(241, 237, 113),
|
||||||
|
Color::Rgb(241, 239, 117),
|
||||||
|
Color::Rgb(241, 241, 121),
|
||||||
|
Color::Rgb(242, 242, 125),
|
||||||
|
Color::Rgb(242, 244, 130),
|
||||||
|
Color::Rgb(243, 245, 134),
|
||||||
|
Color::Rgb(243, 246, 138),
|
||||||
|
Color::Rgb(244, 248, 142),
|
||||||
|
Color::Rgb(245, 249, 146),
|
||||||
|
Color::Rgb(246, 250, 150),
|
||||||
|
Color::Rgb(248, 251, 154),
|
||||||
|
Color::Rgb(249, 252, 157),
|
||||||
|
Color::Rgb(250, 253, 161),
|
||||||
|
Color::Rgb(252, 255, 164),
|
||||||
|
]);
|
||||||
|
|
||||||
|
impl ColorMap {
|
||||||
|
pub fn apply(&self, val: f64) -> Color {
|
||||||
|
assert!(val >= 0.0 && val <= 1.0);
|
||||||
|
let position = (val * 255.0).ceil() as usize;
|
||||||
|
self.0[position]
|
||||||
|
}
|
||||||
|
}
|
481
17/src/main.rs
Normal file
481
17/src/main.rs
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
use colormap::ColorMap;
|
||||||
|
use std::collections::hash_map::RandomState;
|
||||||
|
use std::collections::{BinaryHeap, HashMap};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines, Write};
|
||||||
|
use std::iter::repeat;
|
||||||
|
use std::time::Instant;
|
||||||
|
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||||
|
|
||||||
|
mod colormap;
|
||||||
|
|
||||||
|
const COLORMAP: &ColorMap = &colormap::COLORMAP_INFERNO;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DATA
|
||||||
|
|
||||||
|
const UNPATH_CHAR: char = '█';
|
||||||
|
const UNVISITED_CHAR: char = ' ';
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
enum Direction {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
const fn all() -> &'static [Self; 4] {
|
||||||
|
&[
|
||||||
|
Direction::Left,
|
||||||
|
Direction::Right,
|
||||||
|
Direction::Up,
|
||||||
|
Direction::Down,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const fn opposite(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Direction::Left => Direction::Right,
|
||||||
|
Direction::Right => Direction::Left,
|
||||||
|
Direction::Up => Direction::Down,
|
||||||
|
Direction::Down => Direction::Up,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Direction> for char {
|
||||||
|
fn from(dir: &Direction) -> Self {
|
||||||
|
match dir {
|
||||||
|
Direction::Left => '←',
|
||||||
|
Direction::Right => '→',
|
||||||
|
Direction::Up => '↑',
|
||||||
|
Direction::Down => '↓',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CityMap {
|
||||||
|
map: Vec<Vec<u64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CityMap {
|
||||||
|
fn offset_pos(&self, pos: (usize, usize), dir: &Direction) -> Option<(usize, usize)> {
|
||||||
|
match dir {
|
||||||
|
Direction::Left if pos.0 > 0 => Some((pos.0 - 1, pos.1)),
|
||||||
|
Direction::Right if pos.0 < self.map[0].len() - 1 => Some((pos.0 + 1, pos.1)),
|
||||||
|
Direction::Up if pos.1 > 0 => Some((pos.0, pos.1 - 1)),
|
||||||
|
Direction::Down if pos.1 < self.map.len() - 1 => Some((pos.0, pos.1 + 1)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn print(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let cost_max = *self.map.iter().flat_map(|row| row.iter()).max().unwrap() as f64;
|
||||||
|
|
||||||
|
let mut so_lock = StandardStream::stdout(ColorChoice::Always);
|
||||||
|
for y in 0..self.map.len() {
|
||||||
|
for val in &self.map[y] {
|
||||||
|
so_lock.set_color(
|
||||||
|
ColorSpec::new()
|
||||||
|
.set_bg(Some(COLORMAP.apply(*val as f64 / cost_max)))
|
||||||
|
.set_fg(Some(Color::Black)),
|
||||||
|
)?;
|
||||||
|
so_lock.write_fmt(format_args!("{}", val))?;
|
||||||
|
}
|
||||||
|
so_lock.reset()?;
|
||||||
|
writeln!(so_lock)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = (usize, usize);
|
||||||
|
|
||||||
|
struct WalkCost<'a> {
|
||||||
|
start: Position,
|
||||||
|
cost_from: Vec<Vec<HashMap<(Direction, usize), u64>>>,
|
||||||
|
map: &'a CityMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Move {
|
||||||
|
new_pos: Position,
|
||||||
|
dir: &'static Direction,
|
||||||
|
consecutive: usize,
|
||||||
|
weight: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Move {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.weight == other.weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Move {}
|
||||||
|
|
||||||
|
impl PartialOrd for Move {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Move {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
std::cmp::Reverse(self.weight).cmp(&std::cmp::Reverse(other.weight))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WalkCost<'a> {
|
||||||
|
fn from_map(map: &'a CityMap, start: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
map,
|
||||||
|
start,
|
||||||
|
cost_from: map
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.map(|row| repeat(HashMap::new()).take(row.len()).collect())
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn compute(&mut self) {
|
||||||
|
let mut unvisited_next_moves: BinaryHeap<Move> = BinaryHeap::new();
|
||||||
|
let valid_start_moves: Vec<Move> = Direction::all()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|dir| {
|
||||||
|
self.map.offset_pos(self.start, dir).and_then(|pos| {
|
||||||
|
Some(Move {
|
||||||
|
new_pos: pos,
|
||||||
|
dir,
|
||||||
|
consecutive: 1,
|
||||||
|
weight: self.map.map[pos.1][pos.0],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}) // valid positions
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for m in valid_start_moves {
|
||||||
|
unvisited_next_moves.push(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(cur_move) = unvisited_next_moves.pop() {
|
||||||
|
// we've been here already at a lower cost
|
||||||
|
// if cur_move.weight >= self.cost_to[cur_move.new_pos.1][cur_move.new_pos.0] {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
if let Some(last_weight) = self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.get(&(*cur_move.dir, cur_move.consecutive))
|
||||||
|
{
|
||||||
|
if cur_move.weight < *last_weight {
|
||||||
|
self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.insert((*cur_move.dir, cur_move.consecutive), cur_move.weight);
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
} // visited before at lower cost }
|
||||||
|
} else {
|
||||||
|
self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.insert((*cur_move.dir, cur_move.consecutive), cur_move.weight);
|
||||||
|
}
|
||||||
|
// println!("state at {:?}: {:?}", cur_move, self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]);
|
||||||
|
|
||||||
|
let valid_moves = Direction::all().iter().filter_map(|dir| {
|
||||||
|
self.map
|
||||||
|
.offset_pos(cur_move.new_pos, dir)
|
||||||
|
.and_then(|new_pos| {
|
||||||
|
Some(Move {
|
||||||
|
new_pos,
|
||||||
|
dir,
|
||||||
|
consecutive: if cur_move.dir == dir {
|
||||||
|
cur_move.consecutive + 1
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
weight: cur_move.weight + self.map.map[new_pos.1][new_pos.0],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.filter(|m| m.consecutive != 4 && *m.dir != cur_move.dir.opposite())
|
||||||
|
.filter(|m| {
|
||||||
|
m.weight
|
||||||
|
< *self.cost_from[m.new_pos.1][m.new_pos.0]
|
||||||
|
.get(&(*m.dir, m.consecutive))
|
||||||
|
.unwrap_or(&u64::MAX)
|
||||||
|
})
|
||||||
|
}); // valid positions
|
||||||
|
// println!("valid moves with {:?}", cur_move);
|
||||||
|
for next_move in valid_moves {
|
||||||
|
// println!(" {:?}", next_move);
|
||||||
|
unvisited_next_moves.push(next_move);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WalkCost2<'a> {
|
||||||
|
start: Position,
|
||||||
|
cost_from: Vec<Vec<HashMap<(Direction, usize), u64>>>,
|
||||||
|
map: &'a CityMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WalkCost2<'a> {
|
||||||
|
fn from_map(map: &'a CityMap, start: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
map,
|
||||||
|
start,
|
||||||
|
cost_from: map
|
||||||
|
.map
|
||||||
|
.iter()
|
||||||
|
.map(|row| repeat(HashMap::new()).take(row.len()).collect())
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn min_cost_at(&self, pos: Position) -> Option<&u64> {
|
||||||
|
self.cost_from[pos.1][pos.0].values().min()
|
||||||
|
}
|
||||||
|
fn compute(&mut self, to: Position) {
|
||||||
|
let mut unvisited_next_moves: BinaryHeap<Move> = BinaryHeap::new();
|
||||||
|
let valid_start_moves: Vec<Move> = Direction::all()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|dir| {
|
||||||
|
self.map.offset_pos(self.start, dir).and_then(|pos| {
|
||||||
|
Some(Move {
|
||||||
|
new_pos: pos,
|
||||||
|
dir,
|
||||||
|
consecutive: 1,
|
||||||
|
weight: self.map.map[pos.1][pos.0],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}) // valid positions
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for m in valid_start_moves {
|
||||||
|
unvisited_next_moves.push(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(cur_move) = unvisited_next_moves.pop() {
|
||||||
|
// we've been here already at a lower cost
|
||||||
|
// if cur_move.weight >= self.cost_to[cur_move.new_pos.1][cur_move.new_pos.0] {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
if let Some(last_weight) = self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.get(&(*cur_move.dir, cur_move.consecutive))
|
||||||
|
{
|
||||||
|
if cur_move.weight < *last_weight {
|
||||||
|
self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.insert((*cur_move.dir, cur_move.consecutive), cur_move.weight);
|
||||||
|
// println!("move {:?} inserted {:?}", cur_move, (*cur_move.dir, cur_move.consecutive));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
} // visited before at lower cost }
|
||||||
|
} else {
|
||||||
|
// println!("move {:?} inserted {:?}", cur_move, (*cur_move.dir, cur_move.consecutive));
|
||||||
|
self.cost_from[cur_move.new_pos.1][cur_move.new_pos.0]
|
||||||
|
.insert((*cur_move.dir, cur_move.consecutive), cur_move.weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if cur_move.new_pos == to {
|
||||||
|
// println!("reached end pos {:?} via {:?}", to, cur_move);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let valid_moves = Direction::all().iter().filter_map(|dir| {
|
||||||
|
self.map
|
||||||
|
.offset_pos(cur_move.new_pos, dir)
|
||||||
|
.and_then(|new_pos| {
|
||||||
|
Some(Move {
|
||||||
|
new_pos,
|
||||||
|
dir,
|
||||||
|
consecutive: if cur_move.dir == dir {
|
||||||
|
cur_move.consecutive + 1
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
weight: cur_move.weight + self.map.map[new_pos.1][new_pos.0],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.filter(|m| m.new_pos != self.start)
|
||||||
|
.filter(|m| *m.dir != cur_move.dir.opposite())
|
||||||
|
.filter(|m| {
|
||||||
|
if m.dir == cur_move.dir {
|
||||||
|
m.consecutive < 11
|
||||||
|
} else {
|
||||||
|
cur_move.consecutive >= 4
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(|m| m.new_pos != to || m.consecutive >= 4)
|
||||||
|
.filter(|m| {
|
||||||
|
m.weight
|
||||||
|
< *self.cost_from[m.new_pos.1][m.new_pos.0]
|
||||||
|
.get(&(*m.dir, m.consecutive))
|
||||||
|
.unwrap_or(&u64::MAX)
|
||||||
|
})
|
||||||
|
}); // valid positions
|
||||||
|
// println!("valid moves with {:?}", cur_move);
|
||||||
|
for next_move in valid_moves {
|
||||||
|
// println!(" {:?}", next_move);
|
||||||
|
unvisited_next_moves.push(next_move);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shortest_path_to(&self, to: Position) -> Vec<(Position, Direction)> {
|
||||||
|
let mut path = Vec::new();
|
||||||
|
let mut cur_pos = to;
|
||||||
|
// start at the end, walk backwards
|
||||||
|
while cur_pos != self.start {
|
||||||
|
let (m, _val) = self.cost_from[cur_pos.1][cur_pos.0]
|
||||||
|
.iter()
|
||||||
|
.min_by(|a, b| a.1.cmp(b.1))
|
||||||
|
.unwrap();
|
||||||
|
path.push((cur_pos, m.0));
|
||||||
|
cur_pos = self.map.offset_pos(cur_pos, &m.0.opposite()).unwrap();
|
||||||
|
}
|
||||||
|
path
|
||||||
|
}
|
||||||
|
fn print_path(&self, to: Position) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let path = self.shortest_path_to(to);
|
||||||
|
let map: HashMap<_, _, RandomState> = HashMap::from_iter(path.into_iter());
|
||||||
|
let cost_max_of_min = *self
|
||||||
|
.cost_from
|
||||||
|
.iter()
|
||||||
|
.flat_map(|row| row.iter().filter_map(|cell| cell.values().min()))
|
||||||
|
.max()
|
||||||
|
.unwrap() as f64;
|
||||||
|
let mut so_lock = StandardStream::stdout(ColorChoice::Always);
|
||||||
|
|
||||||
|
for y in 0..self.cost_from.len() {
|
||||||
|
for x in 0..self.map.map[y].len() {
|
||||||
|
let mut color = ColorSpec::new();
|
||||||
|
let c = if let Some(to_dir) = map.get(&(x, y)) {
|
||||||
|
let normalized_cost =
|
||||||
|
*self.min_cost_at((x, y)).unwrap() as f64 / cost_max_of_min;
|
||||||
|
let bg_color = COLORMAP.apply(normalized_cost);
|
||||||
|
let fg_color = if let Color::Rgb(r, g, b) = bg_color {
|
||||||
|
Color::Rgb(255 - r, 255 - g, 255 - b)
|
||||||
|
} else {
|
||||||
|
Color::Black
|
||||||
|
};
|
||||||
|
color.set_fg(Some(fg_color)).set_bg(Some(bg_color)).bold();
|
||||||
|
to_dir.into()
|
||||||
|
} else {
|
||||||
|
if let Some(cost) = &self.min_cost_at((x, y)) {
|
||||||
|
color.set_fg(Some(COLORMAP.apply(**cost as f64 / cost_max_of_min)));
|
||||||
|
UNPATH_CHAR
|
||||||
|
} else {
|
||||||
|
color.set_fg(Some(Color::Black));
|
||||||
|
UNVISITED_CHAR
|
||||||
|
}
|
||||||
|
};
|
||||||
|
so_lock.set_color(&color)?;
|
||||||
|
let mut char_buf = [0u8; 4];
|
||||||
|
c.encode_utf8(&mut char_buf);
|
||||||
|
so_lock.write_all(&char_buf)?;
|
||||||
|
}
|
||||||
|
so_lock.reset()?;
|
||||||
|
writeln!(so_lock)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for CityMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
Self {
|
||||||
|
map: lines
|
||||||
|
.map(|l| l.unwrap().chars().map(|c| c as u64 - '0' as u64).collect())
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let map = CityMap::from(input);
|
||||||
|
let mut costs = WalkCost::from_map(&map, (0, 0));
|
||||||
|
costs.compute();
|
||||||
|
|
||||||
|
// println!("{}", costs);
|
||||||
|
// costs.print_shortest_path((costs.cost_to[0].len() - 1, costs.cost_to.len() - 1));
|
||||||
|
|
||||||
|
*costs.cost_from[costs.cost_from.len() - 1][costs.cost_from[0].len() - 1]
|
||||||
|
.values()
|
||||||
|
.min()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let map = CityMap::from(input);
|
||||||
|
// map.print().unwrap();
|
||||||
|
let mut costs = WalkCost2::from_map(&map, (0, 0));
|
||||||
|
costs.compute((map.map[0].len() - 1, map.map.len() - 1));
|
||||||
|
|
||||||
|
// println!("{}", costs);
|
||||||
|
costs
|
||||||
|
.print_path((costs.cost_from[0].len() - 1, costs.cost_from.len() - 1))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
*costs.cost_from[costs.cost_from.len() - 1][costs.cost_from[0].len() - 1]
|
||||||
|
.values()
|
||||||
|
.min()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"2413432311323
|
||||||
|
3215453535623
|
||||||
|
3255245654254
|
||||||
|
3446585845452
|
||||||
|
4546657867536
|
||||||
|
1438598798454
|
||||||
|
4457876987766
|
||||||
|
3637877979653
|
||||||
|
4654967986887
|
||||||
|
4564679986453
|
||||||
|
1224686865563
|
||||||
|
2546548887735
|
||||||
|
4322674655533";
|
||||||
|
|
||||||
|
const EXAMPLE2: &str = &"111111111111
|
||||||
|
999999999991
|
||||||
|
999999999991
|
||||||
|
999999999991
|
||||||
|
999999999991";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 102);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case(EXAMPLE, 94)]
|
||||||
|
#[test_case(EXAMPLE2, 71)]
|
||||||
|
fn problem2_example(example: &str, expect: u64) {
|
||||||
|
let c = Cursor::new(example);
|
||||||
|
assert_eq!(problem2(c.lines()), expect);
|
||||||
|
}
|
||||||
|
}
|
25
18/Cargo.lock
generated
Normal file
25
18/Cargo.lock
generated
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day18"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
9
18/Cargo.toml
Normal file
9
18/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day18"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
640
18/input
Normal file
640
18/input
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
L 4 (#248a72)
|
||||||
|
U 3 (#295c13)
|
||||||
|
L 4 (#49e802)
|
||||||
|
U 5 (#5ff8b3)
|
||||||
|
R 3 (#0df642)
|
||||||
|
U 2 (#15b973)
|
||||||
|
R 5 (#6cfb92)
|
||||||
|
U 11 (#4e3cd3)
|
||||||
|
L 4 (#422dd0)
|
||||||
|
D 5 (#303fe3)
|
||||||
|
L 7 (#6225e0)
|
||||||
|
D 2 (#58bd63)
|
||||||
|
L 9 (#6225e2)
|
||||||
|
D 8 (#2b1703)
|
||||||
|
L 6 (#422dd2)
|
||||||
|
D 9 (#2eb9b3)
|
||||||
|
L 2 (#10f270)
|
||||||
|
D 10 (#0677b3)
|
||||||
|
L 4 (#190450)
|
||||||
|
U 11 (#55b4e3)
|
||||||
|
L 4 (#361732)
|
||||||
|
U 3 (#034663)
|
||||||
|
L 4 (#37f902)
|
||||||
|
U 6 (#19bb73)
|
||||||
|
R 8 (#6e1030)
|
||||||
|
U 8 (#4cad93)
|
||||||
|
L 4 (#2509d0)
|
||||||
|
U 6 (#1e1e61)
|
||||||
|
L 5 (#3d3b90)
|
||||||
|
U 8 (#28ec81)
|
||||||
|
L 2 (#3f9200)
|
||||||
|
U 5 (#437871)
|
||||||
|
L 6 (#174bc0)
|
||||||
|
D 5 (#3b58a1)
|
||||||
|
L 11 (#064a60)
|
||||||
|
U 5 (#539da3)
|
||||||
|
L 4 (#1ea0d0)
|
||||||
|
D 7 (#1909b3)
|
||||||
|
L 2 (#296a52)
|
||||||
|
D 9 (#6780c3)
|
||||||
|
L 3 (#296a50)
|
||||||
|
U 11 (#356893)
|
||||||
|
L 2 (#0eb430)
|
||||||
|
U 5 (#019203)
|
||||||
|
L 5 (#4eea10)
|
||||||
|
U 4 (#436533)
|
||||||
|
L 4 (#20aeb0)
|
||||||
|
U 4 (#2fb883)
|
||||||
|
L 6 (#5046c0)
|
||||||
|
U 11 (#392293)
|
||||||
|
R 8 (#2567a0)
|
||||||
|
U 3 (#57ee03)
|
||||||
|
R 12 (#270540)
|
||||||
|
U 2 (#358173)
|
||||||
|
R 6 (#289e40)
|
||||||
|
U 2 (#77b991)
|
||||||
|
R 4 (#016c10)
|
||||||
|
U 11 (#351091)
|
||||||
|
R 2 (#714f90)
|
||||||
|
U 6 (#4add71)
|
||||||
|
L 11 (#00eab0)
|
||||||
|
D 5 (#2f8361)
|
||||||
|
L 8 (#192200)
|
||||||
|
U 5 (#1416c1)
|
||||||
|
L 13 (#775d30)
|
||||||
|
U 3 (#3d3d63)
|
||||||
|
L 8 (#6e4710)
|
||||||
|
U 3 (#28cfd3)
|
||||||
|
L 8 (#389880)
|
||||||
|
U 5 (#28cfd1)
|
||||||
|
L 7 (#4cd750)
|
||||||
|
D 5 (#1d56e3)
|
||||||
|
L 3 (#2789e2)
|
||||||
|
D 5 (#5d7573)
|
||||||
|
R 9 (#1b1372)
|
||||||
|
D 5 (#1965a3)
|
||||||
|
R 4 (#111052)
|
||||||
|
D 2 (#5a2861)
|
||||||
|
R 10 (#37f1c2)
|
||||||
|
D 3 (#0b7ad1)
|
||||||
|
R 5 (#012162)
|
||||||
|
U 5 (#226f43)
|
||||||
|
R 4 (#583cd2)
|
||||||
|
D 5 (#4333f3)
|
||||||
|
R 5 (#0eb952)
|
||||||
|
D 3 (#22a273)
|
||||||
|
L 2 (#34c5d0)
|
||||||
|
D 3 (#355f11)
|
||||||
|
L 5 (#13a460)
|
||||||
|
D 4 (#355f13)
|
||||||
|
L 6 (#3e2900)
|
||||||
|
U 4 (#28d423)
|
||||||
|
L 8 (#042432)
|
||||||
|
D 3 (#4378f3)
|
||||||
|
L 6 (#18a200)
|
||||||
|
D 5 (#16a843)
|
||||||
|
L 5 (#18a202)
|
||||||
|
D 7 (#46fdd3)
|
||||||
|
L 5 (#2a4802)
|
||||||
|
D 5 (#2a4d23)
|
||||||
|
L 5 (#6049d2)
|
||||||
|
D 4 (#0a4023)
|
||||||
|
L 4 (#09afb2)
|
||||||
|
U 4 (#687713)
|
||||||
|
L 5 (#4b85f2)
|
||||||
|
D 4 (#0e1a53)
|
||||||
|
L 8 (#331b60)
|
||||||
|
U 6 (#270d83)
|
||||||
|
L 6 (#331b62)
|
||||||
|
U 6 (#25dba3)
|
||||||
|
L 6 (#412e82)
|
||||||
|
D 6 (#5e2e73)
|
||||||
|
L 8 (#1de802)
|
||||||
|
U 6 (#1e7143)
|
||||||
|
L 4 (#4e7e82)
|
||||||
|
U 3 (#160d63)
|
||||||
|
L 5 (#19d230)
|
||||||
|
U 3 (#36a4a3)
|
||||||
|
R 3 (#19d232)
|
||||||
|
U 6 (#4c63b3)
|
||||||
|
R 10 (#0d2862)
|
||||||
|
U 5 (#0ec351)
|
||||||
|
R 11 (#593c62)
|
||||||
|
U 6 (#12de21)
|
||||||
|
R 2 (#08d482)
|
||||||
|
U 4 (#277081)
|
||||||
|
R 3 (#10eee0)
|
||||||
|
U 4 (#382b91)
|
||||||
|
L 4 (#512200)
|
||||||
|
U 7 (#1279f1)
|
||||||
|
L 3 (#229312)
|
||||||
|
U 6 (#422721)
|
||||||
|
R 6 (#71ddd2)
|
||||||
|
U 6 (#093871)
|
||||||
|
R 13 (#0d5622)
|
||||||
|
D 5 (#093873)
|
||||||
|
R 7 (#4c34e2)
|
||||||
|
U 6 (#5b1743)
|
||||||
|
R 2 (#4779a2)
|
||||||
|
D 6 (#1cc6e3)
|
||||||
|
R 7 (#3c13a0)
|
||||||
|
U 5 (#3b60f3)
|
||||||
|
R 4 (#3c13a2)
|
||||||
|
U 9 (#229f83)
|
||||||
|
R 3 (#0a6ff2)
|
||||||
|
D 2 (#06d231)
|
||||||
|
R 8 (#0298b2)
|
||||||
|
D 11 (#4eb6a1)
|
||||||
|
R 7 (#0298b0)
|
||||||
|
U 8 (#438ce1)
|
||||||
|
R 7 (#0e69e2)
|
||||||
|
U 5 (#2d3e73)
|
||||||
|
R 8 (#40b2c2)
|
||||||
|
U 6 (#64cb53)
|
||||||
|
L 2 (#40b2c0)
|
||||||
|
U 3 (#0215c3)
|
||||||
|
L 3 (#2cbf42)
|
||||||
|
U 4 (#00c523)
|
||||||
|
L 7 (#1fc3d2)
|
||||||
|
D 4 (#68a633)
|
||||||
|
L 5 (#1fc3d0)
|
||||||
|
U 5 (#149853)
|
||||||
|
L 5 (#2cbf40)
|
||||||
|
U 9 (#0b9613)
|
||||||
|
L 3 (#1e7f00)
|
||||||
|
U 8 (#2fc533)
|
||||||
|
L 7 (#3d7180)
|
||||||
|
U 3 (#33f3a3)
|
||||||
|
R 9 (#66d340)
|
||||||
|
U 2 (#0fa1f1)
|
||||||
|
R 4 (#0546c0)
|
||||||
|
D 6 (#4c00b3)
|
||||||
|
R 8 (#483b50)
|
||||||
|
U 6 (#4c00b1)
|
||||||
|
R 4 (#2fc7c0)
|
||||||
|
U 2 (#0fa1f3)
|
||||||
|
R 7 (#377280)
|
||||||
|
U 6 (#200c43)
|
||||||
|
R 5 (#429ef0)
|
||||||
|
U 3 (#3a90f1)
|
||||||
|
R 5 (#226142)
|
||||||
|
U 4 (#2740c1)
|
||||||
|
R 5 (#41ac62)
|
||||||
|
U 3 (#275423)
|
||||||
|
R 2 (#3ba072)
|
||||||
|
U 11 (#275421)
|
||||||
|
R 4 (#27ea92)
|
||||||
|
D 8 (#402001)
|
||||||
|
R 2 (#3456c0)
|
||||||
|
D 6 (#5a4541)
|
||||||
|
R 3 (#4d1400)
|
||||||
|
U 4 (#5a4543)
|
||||||
|
R 6 (#462de0)
|
||||||
|
U 8 (#3fcdb1)
|
||||||
|
R 6 (#1f2d90)
|
||||||
|
U 6 (#4e7851)
|
||||||
|
R 3 (#41eb30)
|
||||||
|
D 6 (#4e7853)
|
||||||
|
R 4 (#1aa1c0)
|
||||||
|
D 10 (#0a4073)
|
||||||
|
R 6 (#2134b2)
|
||||||
|
D 7 (#164e43)
|
||||||
|
R 4 (#200c72)
|
||||||
|
D 5 (#3beca3)
|
||||||
|
R 6 (#7445e0)
|
||||||
|
U 3 (#2cda83)
|
||||||
|
R 4 (#7445e2)
|
||||||
|
U 3 (#475553)
|
||||||
|
L 5 (#200c70)
|
||||||
|
U 10 (#23fb33)
|
||||||
|
R 5 (#2134b0)
|
||||||
|
U 7 (#3c98d3)
|
||||||
|
L 4 (#4cfc80)
|
||||||
|
U 5 (#0f0e71)
|
||||||
|
R 8 (#3c1d22)
|
||||||
|
U 10 (#23a311)
|
||||||
|
R 6 (#05da32)
|
||||||
|
D 5 (#6229c1)
|
||||||
|
R 5 (#41f750)
|
||||||
|
D 8 (#1f4191)
|
||||||
|
R 3 (#3530f0)
|
||||||
|
D 13 (#4d3941)
|
||||||
|
R 3 (#6215e0)
|
||||||
|
D 9 (#2fe911)
|
||||||
|
R 6 (#05cf90)
|
||||||
|
U 4 (#25c901)
|
||||||
|
R 2 (#335232)
|
||||||
|
U 12 (#271371)
|
||||||
|
R 2 (#335230)
|
||||||
|
U 5 (#2bd1d1)
|
||||||
|
L 9 (#1ffad0)
|
||||||
|
U 6 (#6f6bc1)
|
||||||
|
R 9 (#099600)
|
||||||
|
U 5 (#13bee1)
|
||||||
|
R 3 (#5aa820)
|
||||||
|
U 3 (#3546c1)
|
||||||
|
R 6 (#4dd5f0)
|
||||||
|
D 11 (#495be1)
|
||||||
|
R 6 (#60c8e0)
|
||||||
|
U 11 (#4bd201)
|
||||||
|
R 4 (#367f30)
|
||||||
|
D 4 (#43dbc1)
|
||||||
|
R 6 (#4bb740)
|
||||||
|
U 12 (#07ce11)
|
||||||
|
R 6 (#4b4d70)
|
||||||
|
D 12 (#3e29e1)
|
||||||
|
R 5 (#313fc0)
|
||||||
|
U 4 (#293d51)
|
||||||
|
R 4 (#1b4860)
|
||||||
|
U 11 (#514571)
|
||||||
|
R 4 (#5c11a2)
|
||||||
|
U 4 (#444841)
|
||||||
|
R 8 (#5c11a0)
|
||||||
|
U 2 (#3e6c51)
|
||||||
|
R 11 (#16dab0)
|
||||||
|
U 7 (#26baf1)
|
||||||
|
R 2 (#32e240)
|
||||||
|
U 5 (#26baf3)
|
||||||
|
R 6 (#2f0a70)
|
||||||
|
U 6 (#11a821)
|
||||||
|
R 3 (#527fc0)
|
||||||
|
U 7 (#468b31)
|
||||||
|
R 6 (#0641a0)
|
||||||
|
U 10 (#20f351)
|
||||||
|
R 7 (#547a90)
|
||||||
|
U 12 (#1dbf11)
|
||||||
|
R 2 (#17d0d2)
|
||||||
|
U 10 (#159981)
|
||||||
|
R 6 (#634e12)
|
||||||
|
U 5 (#4ff021)
|
||||||
|
R 10 (#006122)
|
||||||
|
D 6 (#6589a3)
|
||||||
|
R 3 (#1a74f2)
|
||||||
|
D 2 (#19b911)
|
||||||
|
R 12 (#3ed5f2)
|
||||||
|
D 5 (#28ab31)
|
||||||
|
R 3 (#09dd82)
|
||||||
|
D 5 (#614c01)
|
||||||
|
R 6 (#284d32)
|
||||||
|
D 9 (#06b521)
|
||||||
|
R 8 (#4dfad2)
|
||||||
|
D 7 (#5b0f61)
|
||||||
|
R 2 (#0fff22)
|
||||||
|
D 5 (#1e6ff1)
|
||||||
|
R 2 (#47b352)
|
||||||
|
D 9 (#29c291)
|
||||||
|
R 5 (#352ef2)
|
||||||
|
D 3 (#042d11)
|
||||||
|
R 4 (#262542)
|
||||||
|
D 7 (#042d13)
|
||||||
|
R 4 (#21e8f2)
|
||||||
|
D 3 (#18cc21)
|
||||||
|
R 3 (#16ed70)
|
||||||
|
U 9 (#270ea1)
|
||||||
|
R 7 (#4391e0)
|
||||||
|
U 9 (#270ea3)
|
||||||
|
R 4 (#22bdd0)
|
||||||
|
D 3 (#3b72b1)
|
||||||
|
R 7 (#1fd4b2)
|
||||||
|
D 8 (#01bfe1)
|
||||||
|
L 7 (#3d18a2)
|
||||||
|
D 7 (#20dac1)
|
||||||
|
R 4 (#67d990)
|
||||||
|
D 4 (#1acd93)
|
||||||
|
L 7 (#017410)
|
||||||
|
D 2 (#6e4923)
|
||||||
|
L 7 (#10bdd0)
|
||||||
|
D 13 (#0650b3)
|
||||||
|
L 2 (#072660)
|
||||||
|
U 13 (#221151)
|
||||||
|
L 6 (#41d720)
|
||||||
|
D 3 (#5bc831)
|
||||||
|
L 4 (#252450)
|
||||||
|
D 9 (#118de1)
|
||||||
|
R 6 (#05b1d0)
|
||||||
|
D 4 (#247721)
|
||||||
|
R 9 (#2b6b10)
|
||||||
|
U 4 (#60da41)
|
||||||
|
R 10 (#470c42)
|
||||||
|
D 3 (#4fdc91)
|
||||||
|
R 2 (#470c40)
|
||||||
|
D 8 (#189db1)
|
||||||
|
L 5 (#4a1f70)
|
||||||
|
D 7 (#07e141)
|
||||||
|
L 3 (#2524b0)
|
||||||
|
D 5 (#2a6ce1)
|
||||||
|
L 11 (#1a2e50)
|
||||||
|
D 2 (#4f08c1)
|
||||||
|
L 3 (#3b7ec0)
|
||||||
|
D 9 (#65e011)
|
||||||
|
L 8 (#24b9a0)
|
||||||
|
D 6 (#196c61)
|
||||||
|
L 5 (#540b20)
|
||||||
|
D 6 (#243801)
|
||||||
|
L 2 (#397ce0)
|
||||||
|
D 3 (#411a41)
|
||||||
|
L 12 (#397ce2)
|
||||||
|
D 2 (#526d51)
|
||||||
|
L 2 (#5b5810)
|
||||||
|
D 5 (#2e96d3)
|
||||||
|
L 8 (#6c4f80)
|
||||||
|
U 6 (#274453)
|
||||||
|
L 3 (#077010)
|
||||||
|
U 5 (#37f603)
|
||||||
|
R 5 (#73bf92)
|
||||||
|
U 4 (#29ee73)
|
||||||
|
R 11 (#5ffd40)
|
||||||
|
U 5 (#3e12d3)
|
||||||
|
L 4 (#4b4e32)
|
||||||
|
U 12 (#114e01)
|
||||||
|
L 2 (#45d0b2)
|
||||||
|
U 4 (#114e03)
|
||||||
|
L 6 (#4b8b02)
|
||||||
|
U 9 (#3eff03)
|
||||||
|
L 4 (#6968d0)
|
||||||
|
U 4 (#3d4d33)
|
||||||
|
L 6 (#1dd0e0)
|
||||||
|
D 2 (#436023)
|
||||||
|
L 9 (#58b812)
|
||||||
|
D 6 (#423003)
|
||||||
|
L 7 (#2e81a2)
|
||||||
|
D 3 (#3d9e13)
|
||||||
|
L 11 (#305450)
|
||||||
|
D 6 (#2667f3)
|
||||||
|
L 7 (#3a8470)
|
||||||
|
D 8 (#293191)
|
||||||
|
R 3 (#207ee0)
|
||||||
|
D 4 (#293193)
|
||||||
|
R 3 (#2c4360)
|
||||||
|
D 4 (#2667f1)
|
||||||
|
R 7 (#250ee0)
|
||||||
|
U 4 (#70e1c3)
|
||||||
|
R 4 (#2907d0)
|
||||||
|
D 6 (#0b69a1)
|
||||||
|
R 6 (#3babc0)
|
||||||
|
D 6 (#7698c3)
|
||||||
|
R 2 (#2752c0)
|
||||||
|
D 3 (#7698c1)
|
||||||
|
L 4 (#2dc550)
|
||||||
|
D 11 (#4ec121)
|
||||||
|
L 8 (#199d00)
|
||||||
|
U 11 (#33f261)
|
||||||
|
L 7 (#3b4e30)
|
||||||
|
D 5 (#24e991)
|
||||||
|
L 6 (#0aaeb2)
|
||||||
|
U 9 (#15a993)
|
||||||
|
L 5 (#59ed02)
|
||||||
|
U 2 (#15a991)
|
||||||
|
L 5 (#2c0432)
|
||||||
|
U 10 (#337e81)
|
||||||
|
L 7 (#248670)
|
||||||
|
D 2 (#511d31)
|
||||||
|
L 3 (#52ebc0)
|
||||||
|
D 13 (#511d33)
|
||||||
|
L 4 (#192db0)
|
||||||
|
D 7 (#3dcf11)
|
||||||
|
L 2 (#285030)
|
||||||
|
D 3 (#15acc1)
|
||||||
|
L 6 (#3a6c70)
|
||||||
|
D 5 (#36f281)
|
||||||
|
L 4 (#44fd02)
|
||||||
|
U 5 (#4e8821)
|
||||||
|
L 4 (#473972)
|
||||||
|
U 5 (#2ab9f1)
|
||||||
|
L 8 (#60aaa0)
|
||||||
|
U 5 (#35c651)
|
||||||
|
L 3 (#4736b2)
|
||||||
|
U 10 (#4741d1)
|
||||||
|
L 3 (#1973f2)
|
||||||
|
U 5 (#1b5031)
|
||||||
|
L 3 (#3c6532)
|
||||||
|
D 5 (#49bd31)
|
||||||
|
L 4 (#5e3f60)
|
||||||
|
D 3 (#4a2011)
|
||||||
|
L 4 (#2ba190)
|
||||||
|
D 6 (#4a2013)
|
||||||
|
L 3 (#653430)
|
||||||
|
D 7 (#10dda1)
|
||||||
|
L 11 (#2532d2)
|
||||||
|
D 3 (#675311)
|
||||||
|
L 4 (#27d642)
|
||||||
|
D 6 (#02cae1)
|
||||||
|
L 10 (#466652)
|
||||||
|
D 7 (#34cef3)
|
||||||
|
R 3 (#263692)
|
||||||
|
D 7 (#34cef1)
|
||||||
|
R 8 (#2c59d2)
|
||||||
|
D 5 (#31afe1)
|
||||||
|
L 8 (#091562)
|
||||||
|
D 5 (#12c861)
|
||||||
|
R 4 (#47a772)
|
||||||
|
D 5 (#68a5b1)
|
||||||
|
L 7 (#1f79a2)
|
||||||
|
D 4 (#3b3c13)
|
||||||
|
R 10 (#0e7122)
|
||||||
|
D 4 (#087363)
|
||||||
|
R 4 (#3e26c2)
|
||||||
|
U 13 (#4953f3)
|
||||||
|
R 3 (#5ac862)
|
||||||
|
U 3 (#4953f1)
|
||||||
|
R 3 (#13cfe2)
|
||||||
|
D 5 (#087361)
|
||||||
|
R 11 (#57f7a2)
|
||||||
|
D 4 (#3b3c11)
|
||||||
|
L 11 (#6dcb32)
|
||||||
|
D 7 (#35e653)
|
||||||
|
R 6 (#525282)
|
||||||
|
D 5 (#3dac93)
|
||||||
|
R 9 (#377082)
|
||||||
|
D 6 (#2afda1)
|
||||||
|
R 10 (#3e6422)
|
||||||
|
D 10 (#220471)
|
||||||
|
R 10 (#37ebf2)
|
||||||
|
D 2 (#4d0213)
|
||||||
|
R 5 (#2fa2f2)
|
||||||
|
D 4 (#30df53)
|
||||||
|
R 5 (#617e00)
|
||||||
|
U 6 (#536393)
|
||||||
|
R 5 (#496510)
|
||||||
|
D 6 (#5f6733)
|
||||||
|
R 4 (#3bf9b0)
|
||||||
|
D 3 (#5f6731)
|
||||||
|
R 4 (#48d940)
|
||||||
|
D 3 (#35a5d3)
|
||||||
|
R 4 (#284a82)
|
||||||
|
D 9 (#445b23)
|
||||||
|
L 4 (#2535c2)
|
||||||
|
D 4 (#3f8b43)
|
||||||
|
R 2 (#41a002)
|
||||||
|
D 7 (#20b143)
|
||||||
|
R 3 (#63ae42)
|
||||||
|
U 8 (#328b03)
|
||||||
|
R 9 (#383210)
|
||||||
|
U 3 (#1ce143)
|
||||||
|
R 7 (#383212)
|
||||||
|
U 6 (#2ed603)
|
||||||
|
R 5 (#00c512)
|
||||||
|
U 6 (#6dea43)
|
||||||
|
R 6 (#00c510)
|
||||||
|
U 7 (#0f0643)
|
||||||
|
R 3 (#4292a2)
|
||||||
|
U 7 (#684961)
|
||||||
|
R 3 (#03de80)
|
||||||
|
U 5 (#46e0b1)
|
||||||
|
R 6 (#3d4ae2)
|
||||||
|
D 5 (#1d5fc1)
|
||||||
|
R 7 (#3d4ae0)
|
||||||
|
U 13 (#470ab1)
|
||||||
|
R 5 (#03de82)
|
||||||
|
U 4 (#282c71)
|
||||||
|
R 6 (#5520f2)
|
||||||
|
D 5 (#2f0981)
|
||||||
|
R 2 (#5520f0)
|
||||||
|
D 12 (#4081a1)
|
||||||
|
R 6 (#22a272)
|
||||||
|
U 5 (#284c53)
|
||||||
|
R 8 (#081202)
|
||||||
|
D 5 (#0b7831)
|
||||||
|
R 4 (#3e4552)
|
||||||
|
D 13 (#0b7833)
|
||||||
|
R 5 (#38e092)
|
||||||
|
U 11 (#284c51)
|
||||||
|
R 2 (#550082)
|
||||||
|
U 2 (#175033)
|
||||||
|
R 6 (#036dc2)
|
||||||
|
D 3 (#068791)
|
||||||
|
R 9 (#3ff6f2)
|
||||||
|
D 5 (#4a5783)
|
||||||
|
R 13 (#4d5f92)
|
||||||
|
D 6 (#3e3423)
|
||||||
|
L 12 (#4f62d2)
|
||||||
|
D 7 (#5e4363)
|
||||||
|
L 3 (#0f7032)
|
||||||
|
U 7 (#285261)
|
||||||
|
L 12 (#4ea392)
|
||||||
|
D 5 (#4c2dc1)
|
||||||
|
L 4 (#0d2822)
|
||||||
|
D 5 (#4c2dc3)
|
||||||
|
R 9 (#518da2)
|
||||||
|
D 2 (#41b3b1)
|
||||||
|
R 7 (#023270)
|
||||||
|
D 3 (#13d6e1)
|
||||||
|
R 11 (#0874c0)
|
||||||
|
D 3 (#2026c1)
|
||||||
|
R 4 (#68f3a0)
|
||||||
|
D 7 (#2026c3)
|
||||||
|
L 8 (#208470)
|
||||||
|
D 4 (#09bd81)
|
||||||
|
L 3 (#193a10)
|
||||||
|
D 7 (#5f3491)
|
||||||
|
L 4 (#08cad2)
|
||||||
|
D 10 (#068793)
|
||||||
|
L 10 (#48acb2)
|
||||||
|
D 4 (#20e341)
|
||||||
|
L 7 (#6137a2)
|
||||||
|
D 8 (#20e343)
|
||||||
|
L 7 (#0bf292)
|
||||||
|
D 7 (#5b5f13)
|
||||||
|
L 8 (#2b2532)
|
||||||
|
D 3 (#034073)
|
||||||
|
L 5 (#3c7bb2)
|
||||||
|
D 11 (#09c643)
|
||||||
|
L 3 (#0d6e52)
|
||||||
|
U 3 (#569d23)
|
||||||
|
L 5 (#63fed0)
|
||||||
|
U 4 (#162193)
|
||||||
|
L 4 (#2eb310)
|
||||||
|
U 3 (#655e23)
|
||||||
|
L 10 (#42f8e0)
|
||||||
|
U 4 (#341983)
|
||||||
|
R 14 (#3dbbc0)
|
||||||
|
U 5 (#551b13)
|
||||||
|
L 5 (#2a94f0)
|
||||||
|
U 6 (#05ae53)
|
||||||
|
L 2 (#09db90)
|
||||||
|
U 5 (#2c9e13)
|
||||||
|
L 8 (#4c6d10)
|
||||||
|
D 10 (#40ffb3)
|
||||||
|
L 3 (#306c30)
|
||||||
|
D 2 (#338911)
|
||||||
|
L 6 (#4bed00)
|
||||||
|
D 7 (#338913)
|
||||||
|
R 7 (#12aae0)
|
||||||
|
D 4 (#459613)
|
||||||
|
L 7 (#75d3a2)
|
||||||
|
D 7 (#37ad61)
|
||||||
|
L 6 (#6dcf92)
|
||||||
|
D 4 (#3b7703)
|
||||||
|
R 9 (#0ee2b2)
|
||||||
|
D 4 (#514c13)
|
||||||
|
R 6 (#0ee2b0)
|
||||||
|
D 3 (#2863b3)
|
||||||
|
L 8 (#52eee2)
|
||||||
|
D 8 (#2fc771)
|
||||||
|
L 7 (#5be782)
|
||||||
|
D 4 (#2f39a1)
|
||||||
|
L 6 (#5be780)
|
||||||
|
U 4 (#5625b1)
|
||||||
|
L 2 (#5588c2)
|
||||||
|
U 14 (#37ad63)
|
||||||
|
L 3 (#0681e2)
|
||||||
|
U 4 (#085481)
|
||||||
|
L 3 (#037432)
|
||||||
|
U 12 (#31ed51)
|
||||||
|
L 4 (#6791e2)
|
||||||
|
D 5 (#3546d3)
|
||||||
|
L 6 (#4419e2)
|
||||||
|
D 10 (#3546d1)
|
||||||
|
L 4 (#2c1a72)
|
||||||
|
D 10 (#5bead1)
|
||||||
|
L 3 (#3b3252)
|
||||||
|
D 9 (#3390c1)
|
||||||
|
L 3 (#1d78c2)
|
||||||
|
D 5 (#488d71)
|
||||||
|
R 10 (#244042)
|
||||||
|
D 2 (#10d1e1)
|
||||||
|
R 5 (#3fd582)
|
||||||
|
D 5 (#5025a1)
|
||||||
|
L 3 (#381b70)
|
||||||
|
D 11 (#771831)
|
||||||
|
L 7 (#2abf50)
|
||||||
|
U 11 (#17be81)
|
||||||
|
L 5 (#1eb3c0)
|
||||||
|
D 5 (#3d9c61)
|
||||||
|
L 5 (#5f4de2)
|
||||||
|
D 8 (#278361)
|
||||||
|
L 2 (#2b95b2)
|
||||||
|
D 9 (#2cb0b1)
|
||||||
|
L 4 (#4a0182)
|
||||||
|
D 6 (#2c6bb3)
|
||||||
|
L 2 (#499642)
|
||||||
|
D 5 (#4c76d3)
|
||||||
|
L 8 (#2fe412)
|
||||||
|
U 9 (#07b893)
|
||||||
|
L 2 (#236d52)
|
||||||
|
U 8 (#3956a3)
|
||||||
|
L 7 (#34f252)
|
||||||
|
U 3 (#52bbf1)
|
||||||
|
L 7 (#189470)
|
||||||
|
U 4 (#54b661)
|
||||||
|
L 9 (#189472)
|
||||||
|
U 7 (#0110f1)
|
||||||
|
L 3 (#409bf2)
|
||||||
|
U 3 (#46d3e3)
|
||||||
|
L 5 (#4c0f82)
|
||||||
|
U 11 (#215e73)
|
||||||
|
L 4 (#4c0f80)
|
||||||
|
U 7 (#4050f3)
|
||||||
|
L 9 (#39b192)
|
||||||
|
U 7 (#28b043)
|
||||||
|
L 3 (#011270)
|
||||||
|
U 7 (#1f6693)
|
||||||
|
R 7 (#73c390)
|
||||||
|
U 2 (#2c4113)
|
||||||
|
R 5 (#0321c0)
|
||||||
|
U 8 (#2f2903)
|
||||||
|
L 12 (#5ab560)
|
||||||
|
U 3 (#4dd983)
|
||||||
|
L 6 (#38b7d2)
|
||||||
|
U 12 (#03c8c3)
|
304
18/src/main.rs
Normal file
304
18/src/main.rs
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::LinkedList;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DATA
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
enum Direction {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
enum Turn {
|
||||||
|
LeftNinety,
|
||||||
|
RightNinety,
|
||||||
|
OneEighty,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Direction {
|
||||||
|
const fn all() -> &'static [Self; 4] {
|
||||||
|
&[Direction::Left, Direction::Right, Direction::Up, Direction::Down]
|
||||||
|
}
|
||||||
|
const fn opposite(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Direction::Left => Direction::Right,
|
||||||
|
Direction::Right => Direction::Left,
|
||||||
|
Direction::Up => Direction::Down,
|
||||||
|
Direction::Down => Direction::Up,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fn offset(&self) -> (isize, isize) {
|
||||||
|
match self {
|
||||||
|
Direction::Left => (-1, 0),
|
||||||
|
Direction::Right => (1, 0),
|
||||||
|
Direction::Up => (0, -1),
|
||||||
|
Direction::Down => (0, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn turn_kind(&self, next_dir: Direction) -> Turn {
|
||||||
|
if *self == next_dir {
|
||||||
|
Turn::None
|
||||||
|
} else if self.opposite() == next_dir {
|
||||||
|
Turn::OneEighty
|
||||||
|
} else {
|
||||||
|
match self {
|
||||||
|
Direction::Left if next_dir == Direction::Up => Turn::RightNinety,
|
||||||
|
Direction::Left if next_dir == Direction::Down => Turn::LeftNinety,
|
||||||
|
Direction::Right if next_dir == Direction::Up => Turn::LeftNinety,
|
||||||
|
Direction::Right if next_dir == Direction::Down => Turn::RightNinety,
|
||||||
|
Direction::Up if next_dir == Direction::Left => Turn::LeftNinety,
|
||||||
|
Direction::Up if next_dir == Direction::Right => Turn::RightNinety,
|
||||||
|
Direction::Down if next_dir == Direction::Right => Turn::LeftNinety,
|
||||||
|
Direction::Down if next_dir == Direction::Left => Turn::RightNinety,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Direction {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"L" => Direction::Left,
|
||||||
|
"R" => Direction::Right,
|
||||||
|
"U" => Direction::Up,
|
||||||
|
"D" => Direction::Down,
|
||||||
|
s => panic!("{} is not a valid direction", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Direction> for char {
|
||||||
|
fn from(dir: &Direction) -> Self {
|
||||||
|
match dir {
|
||||||
|
Direction::Left => '←',
|
||||||
|
Direction::Right => '→',
|
||||||
|
Direction::Up => '↑',
|
||||||
|
Direction::Down => '↓',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct DigInstruction {
|
||||||
|
dir: Direction,
|
||||||
|
count: usize,
|
||||||
|
color: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for DigInstruction {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let mut parts = s.split_ascii_whitespace();
|
||||||
|
let (dir, count, color) = (
|
||||||
|
parts.next().unwrap(),
|
||||||
|
parts.next().unwrap(),
|
||||||
|
parts.next().unwrap().chars().skip(2).take(6).collect::<String>(),
|
||||||
|
);
|
||||||
|
Self {
|
||||||
|
dir: dir.into(),
|
||||||
|
count: count.parse().unwrap(),
|
||||||
|
color: color.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DigInstruction {
|
||||||
|
fn part2_transform(&mut self) {
|
||||||
|
let (distance_s, direction_s) = self.color.split_at(5);
|
||||||
|
self.count = usize::from_str_radix(distance_s, 16).unwrap();
|
||||||
|
self.dir = match direction_s {
|
||||||
|
"0" => Direction::Right,
|
||||||
|
"1" => Direction::Down,
|
||||||
|
"2" => Direction::Left,
|
||||||
|
"3" => Direction::Up,
|
||||||
|
s => panic!("`{}` is not a valid direction code", s),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DigPlan {
|
||||||
|
instructions: Vec<DigInstruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DigPlan {
|
||||||
|
fn part2_transform(&mut self) {
|
||||||
|
for i in &mut self.instructions {
|
||||||
|
i.part2_transform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct DigTile {
|
||||||
|
position: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DigTile {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { position: (0, 0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = (isize, isize);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DigHole {
|
||||||
|
tiles_loop: LinkedList<DigTile>,
|
||||||
|
area: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// determinant of positions p1 and p2
|
||||||
|
fn det(p1: Position, p2: Position) -> i64 {
|
||||||
|
((p1.0 * p2.1) - (p1.1 * p2.0)) as i64
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DigHole {
|
||||||
|
fn new() -> Self {
|
||||||
|
DigHole {
|
||||||
|
tiles_loop: LinkedList::new(),
|
||||||
|
area: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn pos_offset_n(&self, pos: Position, offset: (isize, isize), n: usize) -> Position {
|
||||||
|
(pos.0 + offset.0 * n as isize, pos.1 + offset.1 * n as isize)
|
||||||
|
}
|
||||||
|
fn run_plan(&mut self, plan: &DigPlan) {
|
||||||
|
let mut cur_pos = (0, 0);
|
||||||
|
|
||||||
|
self.tiles_loop.push_back(DigTile { position: cur_pos });
|
||||||
|
let mut move_offset;
|
||||||
|
for (idx, i) in plan.instructions.iter().enumerate() {
|
||||||
|
let prev_instruction = if idx > 0 {
|
||||||
|
&plan.instructions[idx - 1]
|
||||||
|
} else {
|
||||||
|
&plan.instructions[plan.instructions.len() - 1]
|
||||||
|
};
|
||||||
|
let Some(next_instruction) = plan.instructions.get(idx + 1).or(Some(&plan.instructions[0])) else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
let cur_turn = prev_instruction.dir.turn_kind(i.dir);
|
||||||
|
let next_turn = i.dir.turn_kind(next_instruction.dir);
|
||||||
|
|
||||||
|
// Point needs to live on the 'outside' corner of the character. to achieve this we need to offset the move
|
||||||
|
// by the following. Found this empirically but there's probably some mathematical principle behind it...
|
||||||
|
move_offset = match (cur_turn, next_turn) {
|
||||||
|
(Turn::RightNinety, Turn::RightNinety) => 1,
|
||||||
|
(Turn::RightNinety, Turn::LeftNinety) => 0,
|
||||||
|
(Turn::LeftNinety, Turn::LeftNinety) => -1,
|
||||||
|
(Turn::LeftNinety, Turn::RightNinety) => 0,
|
||||||
|
t => panic!("turn {:?} not allowed here", t),
|
||||||
|
};
|
||||||
|
|
||||||
|
cur_pos = self.pos_offset_n(cur_pos, i.dir.offset(), (i.count as isize + move_offset) as usize);
|
||||||
|
self.tiles_loop.push_back(DigTile { position: cur_pos });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shoelace formula
|
||||||
|
// https://en.wikipedia.org/wiki/Shoelace_formula
|
||||||
|
let double_area: i64 = self
|
||||||
|
.tiles_loop
|
||||||
|
.iter()
|
||||||
|
.tuple_windows()
|
||||||
|
.map(|(a, b)| det(a.position, b.position))
|
||||||
|
.sum();
|
||||||
|
self.area = (double_area / 2).abs() as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for DigPlan {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
Self {
|
||||||
|
instructions: lines.map(|line| DigInstruction::from(line.unwrap().as_str())).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let plan = DigPlan::from(input);
|
||||||
|
let mut dig = DigHole::new();
|
||||||
|
dig.run_plan(&plan);
|
||||||
|
dig.area
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut plan = DigPlan::from(input);
|
||||||
|
let mut dig = DigHole::new();
|
||||||
|
plan.part2_transform();
|
||||||
|
dig.run_plan(&plan);
|
||||||
|
dig.area
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"R 6 (#70c710)
|
||||||
|
D 5 (#0dc571)
|
||||||
|
L 2 (#5713f0)
|
||||||
|
D 2 (#d2c081)
|
||||||
|
R 2 (#59c680)
|
||||||
|
D 2 (#411b91)
|
||||||
|
L 5 (#8ceee2)
|
||||||
|
U 2 (#caa173)
|
||||||
|
L 1 (#1b58a2)
|
||||||
|
U 2 (#caa171)
|
||||||
|
R 2 (#7807d2)
|
||||||
|
U 3 (#a77fa3)
|
||||||
|
L 2 (#015232)
|
||||||
|
U 2 (#7a21e3)";
|
||||||
|
|
||||||
|
const AREA16_SQUARE: &str = &"R 3 (#000000)
|
||||||
|
D 3 (#000000)
|
||||||
|
L 3 (#000000)
|
||||||
|
U 4 (#000000";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn area16_square() {
|
||||||
|
let c = Cursor::new(AREA16_SQUARE);
|
||||||
|
assert_eq!(problem1(c.lines()), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 62);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 952408144115);
|
||||||
|
}
|
||||||
|
}
|
25
19/Cargo.lock
generated
Normal file
25
19/Cargo.lock
generated
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day19"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
7
19/Cargo.toml
Normal file
7
19/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "day19"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
num-traits = "0.2.17"
|
775
19/input
Normal file
775
19/input
Normal file
@ -0,0 +1,775 @@
|
|||||||
|
kzq{m<596:R,x<1149:R,A}
|
||||||
|
in{s<2440:cd,tgz}
|
||||||
|
rs{m<2118:zx,s>3630:A,m<2297:cx,vfc}
|
||||||
|
hzz{m<2478:A,R}
|
||||||
|
ss{a<692:R,A}
|
||||||
|
sv{x<877:A,m<2320:R,A}
|
||||||
|
ph{x<2510:mf,x>3150:R,m>624:xtc,fr}
|
||||||
|
rg{s>440:hj,a>434:lg,ljm}
|
||||||
|
hdr{m<1158:R,m>1494:vfl,a<1353:A,R}
|
||||||
|
zhp{x>633:A,x<248:R,A}
|
||||||
|
fd{s<1838:A,m<3087:A,a>3495:R,jsg}
|
||||||
|
qvh{x<3002:crs,m<2331:A,s<3294:dh,R}
|
||||||
|
qbr{m>3556:R,m<3200:R,R}
|
||||||
|
sql{m<3219:A,zf}
|
||||||
|
zf{a<633:A,s<1348:A,A}
|
||||||
|
rr{x<3035:A,s<3096:A,a<2451:R,A}
|
||||||
|
bng{s>3079:R,a<724:jd,R}
|
||||||
|
lv{a<3333:tqj,hth}
|
||||||
|
bcp{a>1296:dtp,m>2875:dnq,x>1453:xjl,gp}
|
||||||
|
tz{m>3020:R,R}
|
||||||
|
gnz{m<692:R,m>1130:R,m>877:R,R}
|
||||||
|
xqg{x>3462:A,s<3298:A,s>3449:R,R}
|
||||||
|
pxd{s>1539:jvr,m<2976:frj,x>1748:mr,fts}
|
||||||
|
tj{m>3165:R,m<3044:R,a>1557:R,A}
|
||||||
|
jqm{x<2410:xf,m>3048:zm,zbl}
|
||||||
|
pv{a>2330:R,a>2259:A,x>3069:A,A}
|
||||||
|
qnz{m>1947:bz,x<2553:jr,x<3256:prq,bx}
|
||||||
|
cn{x>2438:nl,s<193:A,R}
|
||||||
|
kkb{s>3372:A,a>295:A,R}
|
||||||
|
rgr{a>707:R,a>400:hrd,npv}
|
||||||
|
klp{s<2137:jzp,x>1502:qnz,xj}
|
||||||
|
fm{m>3258:db,qd}
|
||||||
|
scf{a>490:A,m>3260:R,R}
|
||||||
|
btz{a>3068:dr,a>2668:hfb,m<2408:cs,fgr}
|
||||||
|
xqr{m>2286:A,a<2390:tf,x>3254:R,fkk}
|
||||||
|
tp{x<1044:A,a>2510:A,s<1735:A,A}
|
||||||
|
frj{x>2659:vhd,s>1415:lfl,sll}
|
||||||
|
kcn{s<1967:R,R}
|
||||||
|
vrm{a>1620:R,x>1345:A,s>3219:A,A}
|
||||||
|
vm{x<2777:gnz,m<614:hrg,a>903:shm,R}
|
||||||
|
bqq{a<994:A,m<2065:vrm,s<3419:bnv,zqt}
|
||||||
|
dtp{a>2018:cp,tbq}
|
||||||
|
qk{m>3174:slm,m>2948:jqm,gz}
|
||||||
|
gzq{m>1755:R,A}
|
||||||
|
nl{s>174:A,a<3022:A,m>2165:R,A}
|
||||||
|
mkk{a>2954:A,R}
|
||||||
|
gp{x>808:bng,nmr}
|
||||||
|
khf{m<1278:R,a>264:A,x>3812:A,A}
|
||||||
|
xxf{m>1340:A,s>2282:R,R}
|
||||||
|
bbk{a>1074:gqc,a>616:mdv,pgv}
|
||||||
|
nrp{x<2414:R,mjc}
|
||||||
|
kpt{m<3158:bcp,clt}
|
||||||
|
snl{m<868:km,m<1182:A,x<715:R,A}
|
||||||
|
cfm{s<3832:R,A}
|
||||||
|
pt{m>3354:rkx,A}
|
||||||
|
bz{a>3073:jz,s>2285:A,a>2653:tt,sgd}
|
||||||
|
zp{s>3328:R,m<981:R,A}
|
||||||
|
zkg{a<910:kjc,a<1539:hzz,s<2149:xdc,R}
|
||||||
|
jxm{x>2135:R,m>1114:R,a<668:A,ghm}
|
||||||
|
szq{s<450:cn,s>694:sdd,s>567:cm,lk}
|
||||||
|
vlz{s>584:R,s<287:R,A}
|
||||||
|
fr{s>1707:A,m<281:A,a<1488:R,R}
|
||||||
|
cdh{x>1427:R,x>1191:R,A}
|
||||||
|
brs{s>2803:A,a<821:A,s>2565:R,R}
|
||||||
|
ghm{s<3298:R,m>738:A,x>868:R,R}
|
||||||
|
cdn{s<745:R,a<1738:R,R}
|
||||||
|
vgc{s>3045:A,s>2796:R,A}
|
||||||
|
mjc{m<1443:R,a<1751:R,a<2183:A,R}
|
||||||
|
rhs{a<1453:A,m>933:kg,A}
|
||||||
|
vgh{m>3481:zmk,x>2384:ng,s<3473:pt,xvj}
|
||||||
|
lfb{x>1099:A,A}
|
||||||
|
cb{a<2973:qkv,x>2753:knq,R}
|
||||||
|
vd{a<1578:zbh,x>2560:A,s<1772:R,A}
|
||||||
|
dh{m<2492:R,m>2532:A,A}
|
||||||
|
tqj{m>1459:R,m>649:R,m>261:A,A}
|
||||||
|
sch{m<1650:R,A}
|
||||||
|
brm{x<2245:rm,vsm}
|
||||||
|
xqc{x>1906:R,s<2586:R,m>1404:R,A}
|
||||||
|
vmx{m<2123:qsd,s<2169:R,s<2335:R,A}
|
||||||
|
nrj{s>2051:ml,a<3354:A,x<772:tjm,czr}
|
||||||
|
zpq{a<805:R,s<2733:A,x<2371:R,R}
|
||||||
|
lq{m<2008:nxh,m<2296:vmx,zkg}
|
||||||
|
lfn{m>2015:R,A}
|
||||||
|
vhv{s>2798:A,m<2650:R,hsz}
|
||||||
|
rxq{a>2045:A,a>2002:A,R}
|
||||||
|
gv{x>3571:R,m>3216:A,R}
|
||||||
|
kjg{x>2443:R,s>3563:A,A}
|
||||||
|
qv{a>903:A,a<755:A,m<2822:R,A}
|
||||||
|
dqb{s<1310:A,s<1331:R,s<1351:R,A}
|
||||||
|
pll{s<1875:R,s<1928:A,a>3979:A,R}
|
||||||
|
cct{x>2015:cb,m<1524:vqc,a>3121:sdz,rs}
|
||||||
|
dq{a>3084:R,a>2989:A,x<1241:A,R}
|
||||||
|
xzx{a>2077:A,a<2023:A,a>2046:A,R}
|
||||||
|
nmr{s>3420:R,A}
|
||||||
|
klr{m<1060:A,m>1274:A,ms}
|
||||||
|
dr{s>1739:qvk,m<2207:R,a>3629:R,gk}
|
||||||
|
qvk{s<1772:A,a>3599:R,R}
|
||||||
|
gbj{a>855:R,m>2778:R,A}
|
||||||
|
drj{s<2725:R,A}
|
||||||
|
th{s<219:R,s>361:R,R}
|
||||||
|
dd{x<1745:zgq,a<2006:R,s<3396:tlq,vn}
|
||||||
|
cpr{x<2287:R,a>3768:R,A}
|
||||||
|
ntn{a<1603:R,x<3513:A,x<3736:R,A}
|
||||||
|
zlg{a<2254:xbz,m>1915:xqr,qhg}
|
||||||
|
mv{m<1685:A,s<2921:A,s<3099:nrm,A}
|
||||||
|
tnz{m>1738:R,R}
|
||||||
|
hql{m<1446:rj,qn}
|
||||||
|
bxk{x>1683:A,m<3826:R,x>1019:A,R}
|
||||||
|
pg{x>2110:A,A}
|
||||||
|
vsm{m<1847:R,x<2870:A,R}
|
||||||
|
qcs{m>3409:xh,x<948:A,x>1273:R,R}
|
||||||
|
zxz{a<961:gzj,x>900:bg,m<796:nn,A}
|
||||||
|
mp{a>2922:R,x<1561:A,A}
|
||||||
|
nb{m>1334:lq,a<942:kjq,s<2216:vcc,zd}
|
||||||
|
kjc{x>2597:R,m<2416:R,s<2114:R,R}
|
||||||
|
nz{a>349:A,x<1677:R,A}
|
||||||
|
cj{x<2805:kjg,x<3336:A,R}
|
||||||
|
kq{m<1306:R,s<3407:gmg,A}
|
||||||
|
jp{x<2530:hd,pmn}
|
||||||
|
vhj{s<2857:A,s<3029:A,x<3204:A,A}
|
||||||
|
zcr{s>3421:R,A}
|
||||||
|
kgq{m<2273:bqq,m>2432:mmf,x>1209:zxp,dzs}
|
||||||
|
crs{a<302:R,A}
|
||||||
|
fq{m>2037:vgj,m<1874:kfg,m>1968:jx,dtq}
|
||||||
|
rjx{x<2876:sf,xlc}
|
||||||
|
qsg{x>2668:A,s<2509:R,R}
|
||||||
|
gz{a<1575:tvn,a<1927:ljt,a>2208:vmj,nqk}
|
||||||
|
fzj{s>2118:A,R}
|
||||||
|
jtn{s<3102:A,m<2129:R,s>3609:A,R}
|
||||||
|
htb{x<1752:lf,s<2690:zb,a>3052:ntg,chm}
|
||||||
|
nqk{m>2784:A,x>2006:rxq,xzx}
|
||||||
|
ktz{a>1145:lnr,zz}
|
||||||
|
cl{s>2245:R,A}
|
||||||
|
pp{x>3144:R,a>1054:A,A}
|
||||||
|
km{s<3596:R,a<217:R,a<378:A,A}
|
||||||
|
btd{a>328:R,x>3186:R,s<2776:R,R}
|
||||||
|
nv{a<3170:A,x<1822:A,R}
|
||||||
|
zqt{a<1992:R,s>3757:A,R}
|
||||||
|
zvh{x<3431:A,x<3695:R,a<181:A,khf}
|
||||||
|
rjc{s>3558:rxs,ngt}
|
||||||
|
fvr{s<1819:A,a>3820:R,A}
|
||||||
|
gdh{a<1044:A,m>3889:R,a<1313:A,R}
|
||||||
|
xjl{m>2748:zfc,x>2350:hkv,qdk}
|
||||||
|
dzs{a<1516:tbs,m<2379:zcr,x>802:A,lvn}
|
||||||
|
hnk{m<1382:cqm,x<618:R,m>2969:A,ck}
|
||||||
|
sl{s<2067:R,rq}
|
||||||
|
bn{m>2044:R,x>1947:R,s>2494:A,A}
|
||||||
|
klj{m>595:zs,a>1587:A,A}
|
||||||
|
hd{m<814:rt,hdr}
|
||||||
|
pm{x>1330:rjf,s>3318:snl,m<757:lgm,jhh}
|
||||||
|
xn{m>894:R,s<486:R,A}
|
||||||
|
zxp{s>3057:mnb,A}
|
||||||
|
bt{x>2338:R,s<2515:R,A}
|
||||||
|
qdh{x<1435:dfm,m>3320:sn,m<2950:knb,xcq}
|
||||||
|
zsf{x>3119:R,s<3965:A,R}
|
||||||
|
lxs{x<1891:R,R}
|
||||||
|
fp{a>839:A,a<370:A,x>3697:R,A}
|
||||||
|
fb{x>1576:A,x>1383:R,R}
|
||||||
|
ssq{x>1389:R,x<683:A,R}
|
||||||
|
psl{s>1912:nb,mdx}
|
||||||
|
gzd{a<286:R,m>2048:R,A}
|
||||||
|
cm{x<2249:R,R}
|
||||||
|
ps{m<3057:A,a<192:A,R}
|
||||||
|
ql{x<1455:R,s<2316:A,dz}
|
||||||
|
tl{s>2746:R,a<2925:jth,s<2631:R,dq}
|
||||||
|
fl{m<871:R,R}
|
||||||
|
dnd{s<3340:R,a<1631:A,R}
|
||||||
|
hpk{x<2148:nbd,kq}
|
||||||
|
hrd{m>2977:A,R}
|
||||||
|
cqm{a<3300:A,s<2326:R,R}
|
||||||
|
vhx{a>264:sx,czq}
|
||||||
|
hpb{m<1744:bkc,x<1249:cf,vkm}
|
||||||
|
ms{x>3633:R,a>279:A,x>3536:A,A}
|
||||||
|
qkk{a<2687:A,s<2740:R,A}
|
||||||
|
vfc{a<2771:R,A}
|
||||||
|
rjf{s<3472:br,x<1970:A,a>216:R,A}
|
||||||
|
xbz{x<3190:lkc,gvr}
|
||||||
|
mx{s>1027:R,A}
|
||||||
|
fxr{a<3952:R,R}
|
||||||
|
sz{m>3436:R,a>3677:R,a<3578:A,R}
|
||||||
|
qsd{s>2211:A,s>2062:A,x<1916:R,R}
|
||||||
|
jxd{a>3568:A,x>2134:R,hr}
|
||||||
|
xlc{m<3646:ntn,m>3749:vb,a<829:hmk,gc}
|
||||||
|
zmb{x<854:A,tv}
|
||||||
|
dxx{a>796:brs,m<1206:gq,R}
|
||||||
|
jj{m<1020:xhs,a<758:ghs,dxx}
|
||||||
|
jd{s>2702:A,a>437:A,x<1198:A,A}
|
||||||
|
vb{a<1183:A,x>3584:R,R}
|
||||||
|
zg{a<1774:R,rp}
|
||||||
|
fjl{m<1926:A,A}
|
||||||
|
sx{m>412:rlx,m<224:hsm,ts}
|
||||||
|
clt{m>3707:kbk,vgh}
|
||||||
|
sdd{x>1333:A,s>792:ffv,qc}
|
||||||
|
ltl{s<2747:A,A}
|
||||||
|
qd{a<1088:A,a>1543:R,R}
|
||||||
|
lnr{s>1491:A,tgm}
|
||||||
|
hr{s<2837:A,R}
|
||||||
|
tbn{m>1412:A,x<1334:ltl,bbq}
|
||||||
|
db{x<1961:R,R}
|
||||||
|
dfm{m>3324:R,A}
|
||||||
|
mdx{s>1504:cc,sb}
|
||||||
|
xvj{x<1523:R,R}
|
||||||
|
zm{x>3061:txs,x<2826:R,R}
|
||||||
|
bkc{s<3439:R,s<3712:R,R}
|
||||||
|
sp{a>996:A,R}
|
||||||
|
ftd{x>2631:R,m>2447:R,x>2241:R,R}
|
||||||
|
qxl{m>591:R,x>508:A,R}
|
||||||
|
ngs{x<1410:R,A}
|
||||||
|
nvl{m>836:R,A}
|
||||||
|
kbd{m>2655:jxd,shz}
|
||||||
|
bzz{m>2969:R,A}
|
||||||
|
hth{x>532:R,x<263:A,A}
|
||||||
|
dtq{x<1785:fjl,qpt}
|
||||||
|
qbz{m<1913:kkb,m<2018:R,x<2884:tvj,gzd}
|
||||||
|
tr{x<1816:zxz,s<3159:gj,a>942:vtz,vm}
|
||||||
|
pdr{a>3495:R,x<960:A,A}
|
||||||
|
sfd{m<1983:R,a>3730:A,A}
|
||||||
|
qm{a<3400:A,R}
|
||||||
|
vlx{x<1628:R,x>2516:A,R}
|
||||||
|
ztb{s<1848:A,s<1862:R,A}
|
||||||
|
tlq{m<3961:A,A}
|
||||||
|
mtx{x<628:R,s<2839:A,R}
|
||||||
|
dp{m<631:R,x>3424:R,A}
|
||||||
|
bch{x>544:R,s<1473:A,A}
|
||||||
|
qkv{s>3614:A,a<2756:R,A}
|
||||||
|
tlz{s<1526:R,A}
|
||||||
|
nr{a<1406:R,s>1965:ls,a<1804:R,kmj}
|
||||||
|
rn{m<3158:R,x>1428:R,A}
|
||||||
|
fn{s>2334:R,R}
|
||||||
|
fv{s>496:R,m>2847:A,R}
|
||||||
|
kdt{x<1651:qx,mn}
|
||||||
|
dt{s<1907:R,A}
|
||||||
|
fxp{s>1444:R,x<1151:R,s<1432:R,A}
|
||||||
|
skp{s<2684:ff,a>3661:grc,kbd}
|
||||||
|
sf{a<1342:R,R}
|
||||||
|
vn{x<2642:A,m>3964:A,x>3188:R,R}
|
||||||
|
cc{m<1326:ph,vd}
|
||||||
|
st{m>2033:kv,x>2199:mh,qs}
|
||||||
|
tt{s<2228:R,m>2870:A,x<2943:R,A}
|
||||||
|
zxc{x<2549:A,a<790:fl,a>821:hs,rv}
|
||||||
|
nzg{a>721:R,a<709:R,m<1312:R,R}
|
||||||
|
dpm{x<2029:dvz,tkb}
|
||||||
|
xzp{x<1033:zhp,m<3650:vk,s>1404:cdh,R}
|
||||||
|
kmt{x>1508:A,m>3316:sdt,ngs}
|
||||||
|
jr{x<2063:zvg,x<2340:A,m>945:cl,R}
|
||||||
|
slv{m<658:A,m>699:R,x<1549:R,R}
|
||||||
|
txs{x>3387:R,x>3223:A,A}
|
||||||
|
jbj{x<1080:R,R}
|
||||||
|
slm{s>2107:qgv,x>1425:pbp,nr}
|
||||||
|
xj{s<2246:lv,hnk}
|
||||||
|
rxs{a>3208:R,s>3711:tz,bvt}
|
||||||
|
sgd{m>2799:R,m<2302:A,s>2226:A,A}
|
||||||
|
gng{m>1061:xqc,m>382:A,s<2565:A,rkh}
|
||||||
|
tq{m>3700:R,m>3578:A,m<3552:R,R}
|
||||||
|
gqc{m<751:vc,m<1228:trs,qln}
|
||||||
|
bzg{a<3173:A,x>2040:A,A}
|
||||||
|
gr{s>1874:A,A}
|
||||||
|
sm{x>1443:fc,m<3252:pqp,lh}
|
||||||
|
vt{x<324:sch,m<2405:zdb,s<2751:A,mtx}
|
||||||
|
rrz{a<2925:A,m<1807:A,A}
|
||||||
|
dvm{s>3793:R,a<714:R,a>723:A,R}
|
||||||
|
ns{a>216:fzj,s<2226:A,pl}
|
||||||
|
tsn{m<1180:R,x<1442:ss,a<693:A,dvm}
|
||||||
|
lgm{m<295:mt,qxl}
|
||||||
|
gq{a>772:R,s>2860:A,A}
|
||||||
|
tv{x<1247:R,m>2373:A,R}
|
||||||
|
shm{a>923:R,R}
|
||||||
|
tc{m>1326:pd,x<2176:A,A}
|
||||||
|
zs{a>956:R,x<1552:A,m<1047:A,A}
|
||||||
|
kbk{a<1245:zr,m>3892:dd,a>1823:hf,rkz}
|
||||||
|
gc{s>1625:A,x<3456:R,A}
|
||||||
|
vv{m<1670:jp,a<1470:tvs,dx}
|
||||||
|
dv{a<3900:dt,x<2401:R,a>3952:pll,A}
|
||||||
|
rh{x>1522:md,zmb}
|
||||||
|
bv{s<813:R,x<1898:A,m<2291:A,A}
|
||||||
|
dfs{a>2165:A,x<2625:A,m<905:A,R}
|
||||||
|
sq{m<1537:A,a>3700:R,s>3518:R,R}
|
||||||
|
zbh{m>1984:R,s>1714:A,s>1589:R,A}
|
||||||
|
pmn{x>3353:mxr,xn}
|
||||||
|
fc{m<3293:A,R}
|
||||||
|
hj{m>2607:nz,bv}
|
||||||
|
cjt{s<3222:R,a>778:A,R}
|
||||||
|
md{a<2755:A,a<2974:bqz,m<1812:A,R}
|
||||||
|
jcn{x<3486:A,A}
|
||||||
|
tm{x<1626:R,x>2473:A,R}
|
||||||
|
rp{s<2043:A,A}
|
||||||
|
dtt{x<2469:A,x>2652:A,R}
|
||||||
|
rkh{a<3899:R,a<3939:A,a>3972:A,R}
|
||||||
|
vtz{x<3222:jnj,A}
|
||||||
|
dz{a>1273:R,x<2592:R,a>1109:R,A}
|
||||||
|
zbl{x<3369:A,a<1301:A,A}
|
||||||
|
xcc{x<1386:R,x>2717:A,A}
|
||||||
|
snz{x>1513:R,A}
|
||||||
|
pnp{m>2870:R,s<1615:R,A}
|
||||||
|
nzs{x<2228:svh,a>3290:drm,qck}
|
||||||
|
dx{m<2704:st,bnq}
|
||||||
|
ml{m>2093:A,m<723:R,x>705:A,A}
|
||||||
|
nrm{x<2693:R,x>3329:R,a<1508:A,R}
|
||||||
|
ls{a>2023:R,x<645:A,x<1062:R,R}
|
||||||
|
zbk{s<3432:A,R}
|
||||||
|
pcx{a>133:A,R}
|
||||||
|
xc{a<2881:A,m>2239:R,R}
|
||||||
|
bvt{x>2521:R,m>3250:A,A}
|
||||||
|
vfl{a>1549:A,A}
|
||||||
|
gb{s>2827:fxr,a<3925:vp,tk}
|
||||||
|
nt{a<3562:R,s>1880:R,A}
|
||||||
|
qh{s<2766:R,m>1823:R,m<1032:R,R}
|
||||||
|
vkb{m>3657:R,a<1604:A,R}
|
||||||
|
qdk{a>446:vrt,a>237:R,A}
|
||||||
|
nx{s<3053:A,x>2661:A,s<3652:A,A}
|
||||||
|
ffv{m>2118:A,x<591:A,R}
|
||||||
|
gnx{m>3550:A,s>340:R,A}
|
||||||
|
xdc{s<2011:R,a<1886:A,m<2525:R,R}
|
||||||
|
rnx{x>1741:A,R}
|
||||||
|
vgj{a<1194:R,a>1316:A,mjf}
|
||||||
|
rz{m<245:A,R}
|
||||||
|
jzp{x<1378:nrj,qm}
|
||||||
|
dhz{m<2327:dnd,x<3029:ftd,m<2461:R,A}
|
||||||
|
mmf{x>1349:R,m>2512:A,R}
|
||||||
|
chm{m<1360:sh,a>2753:dmf,x<2850:zdz,rd}
|
||||||
|
bb{a<1712:R,s<1716:A,fgd}
|
||||||
|
lfl{s>1480:R,fxp}
|
||||||
|
vkm{a<944:fb,cdz}
|
||||||
|
shz{x>2518:R,s>2824:pdr,x<1098:A,R}
|
||||||
|
lvn{a<1975:A,A}
|
||||||
|
ng{m<3372:pjq,R}
|
||||||
|
ntg{x<2896:bvx,hql}
|
||||||
|
qck{a>2892:R,x>2827:gx,m<1542:njr,R}
|
||||||
|
xg{m<274:R,R}
|
||||||
|
qs{a<1914:cdn,R}
|
||||||
|
bd{m>3657:jbj,m<3576:R,x>715:hk,R}
|
||||||
|
mnb{m>2328:A,s<3622:A,a<1275:A,A}
|
||||||
|
lkc{s>3247:R,A}
|
||||||
|
jz{a<3649:A,a<3878:R,R}
|
||||||
|
pgv{x<2543:pm,m<747:vhx,s<3269:kb,hx}
|
||||||
|
vfk{s>2335:sd,R}
|
||||||
|
mxr{s<525:pz,fp}
|
||||||
|
qln{s<3057:tbn,m>1379:nrp,tc}
|
||||||
|
hsm{a<391:A,R}
|
||||||
|
mdv{a>842:tr,s<3143:jj,mfx}
|
||||||
|
tgm{x<1435:R,A}
|
||||||
|
bj{x>2353:R,A}
|
||||||
|
frk{s>1770:A,lfb}
|
||||||
|
tnt{a>228:R,x<307:A,A}
|
||||||
|
bx{s<2240:R,m>928:gf,x<3724:gm,fn}
|
||||||
|
vr{s<3307:R,m>3549:R,A}
|
||||||
|
zd{a<1856:ql,vfk}
|
||||||
|
jth{s<2601:A,A}
|
||||||
|
tbq{s>3089:A,s<2692:bzz,A}
|
||||||
|
zz{x>1544:tlz,bch}
|
||||||
|
mq{m>1048:R,s<3046:dfs,m<905:nvl,R}
|
||||||
|
xsb{a>968:A,s>3282:R,R}
|
||||||
|
ctf{m>2182:dhz,s>3326:cj,m<1769:mv,xxb}
|
||||||
|
cd{a>2405:qjl,s<1247:vv,m<2651:psl,cz}
|
||||||
|
sdt{m<3413:A,s<1386:A,R}
|
||||||
|
nm{m>1061:A,m<861:R,a<1430:R,zp}
|
||||||
|
kbp{a>257:R,R}
|
||||||
|
czq{s>3301:A,pcx}
|
||||||
|
rv{x<3177:R,x<3631:R,m>605:R,R}
|
||||||
|
lg{x<2664:A,fqp}
|
||||||
|
rq{s<2141:R,x<1452:A,x<2322:A,A}
|
||||||
|
rkx{m>3406:R,s>2856:R,a>1356:R,R}
|
||||||
|
rxz{a>3491:ft,m>1104:R,s<1879:A,A}
|
||||||
|
tqc{s>2638:A,R}
|
||||||
|
kb{m<1115:btd,a<356:zvh,nh}
|
||||||
|
svh{m>2131:A,s>1205:A,sdj}
|
||||||
|
gzj{s>3413:R,m<563:R,R}
|
||||||
|
tgz{a>2498:nc,m<1536:bbk,m>2606:kpt,dpm}
|
||||||
|
nc{s>2973:mml,a>3390:skp,htb}
|
||||||
|
zr{m>3877:A,a<786:zbk,sp}
|
||||||
|
hf{m<3830:A,R}
|
||||||
|
rj{s>2812:A,R}
|
||||||
|
lvf{s<2217:ghz,m<352:fg,s<2328:R,R}
|
||||||
|
tvn{x<1573:A,ct}
|
||||||
|
pqp{a<1606:A,s>1424:R,x>1211:A,A}
|
||||||
|
fpm{a<3321:A,a>3380:A,R}
|
||||||
|
lpq{a<2688:A,m>550:A,R}
|
||||||
|
skb{a>496:R,a>370:A,m>3052:A,R}
|
||||||
|
vqc{a>2824:A,mdj}
|
||||||
|
sk{s>3032:R,a>1895:kzq,A}
|
||||||
|
fqp{x<3283:R,x>3734:R,m>2573:A,A}
|
||||||
|
kv{x<1403:R,A}
|
||||||
|
jhh{a<365:zv,s>2937:R,a<532:A,A}
|
||||||
|
qx{m<216:A,m<345:A,R}
|
||||||
|
tvj{m>2055:R,x>2595:R,R}
|
||||||
|
fkk{s<3440:A,R}
|
||||||
|
nh{s>2904:R,x>3474:A,R}
|
||||||
|
bnq{x<1726:qcs,x>2609:xjj,pg}
|
||||||
|
bhv{s<1815:btz,a<3302:rh,m<1426:xs,dfq}
|
||||||
|
grc{a>3883:gb,a>3753:brm,a<3710:vhv,xr}
|
||||||
|
pl{x<1731:R,a<138:R,m<1085:R,R}
|
||||||
|
ngt{x>2573:xqg,a>3461:sz,m>3259:vr,vmf}
|
||||||
|
jnq{m<2176:R,m>2968:R,x>3137:A,R}
|
||||||
|
sb{m>1679:lfn,s>1408:snz,klj}
|
||||||
|
jvr{a>1008:bb,s<1695:np,ln}
|
||||||
|
kjq{m<593:lvf,m<873:bcs,a>378:djc,ns}
|
||||||
|
hh{s>2869:R,A}
|
||||||
|
kj{x>1634:rrz,s<2750:A,m>2365:mp,R}
|
||||||
|
xf{m<3098:A,m<3128:cr,a<995:rn,vj}
|
||||||
|
zv{x<860:A,a>221:R,x>1038:A,R}
|
||||||
|
rm{a>3836:A,A}
|
||||||
|
tbs{a>927:A,R}
|
||||||
|
gm{m<317:A,A}
|
||||||
|
sdz{s>3569:R,m<1986:tnz,fpm}
|
||||||
|
lf{x<960:vt,x<1466:tl,kj}
|
||||||
|
qhg{m<1782:vgc,a<2401:A,rr}
|
||||||
|
nxh{a<1275:R,gzq}
|
||||||
|
tk{x<2449:A,R}
|
||||||
|
cp{s<3395:R,s>3741:cfm,tm}
|
||||||
|
zdb{x>591:A,s<2781:A,R}
|
||||||
|
mhm{x<3419:R,x<3710:A,m>2686:A,A}
|
||||||
|
pz{m>885:R,a<1395:A,R}
|
||||||
|
jxl{a<1824:rz,A}
|
||||||
|
vmr{a>570:jqd,m>2081:qvh,m>1814:qbz,dkx}
|
||||||
|
kmj{s<1935:R,A}
|
||||||
|
prq{m>920:xxf,R}
|
||||||
|
cf{s>3313:A,x>700:A,m>1872:A,R}
|
||||||
|
qgv{a>1042:vlx,a>596:rqd,R}
|
||||||
|
mr{x>3011:gv,x>2379:mjx,fm}
|
||||||
|
cx{a>2892:A,A}
|
||||||
|
xz{m>2929:R,s<2814:R,s>2986:A,A}
|
||||||
|
ck{x<994:A,s>2364:A,m>2064:A,R}
|
||||||
|
zdd{s>911:nzs,szq}
|
||||||
|
vj{s>2138:A,m>3156:A,R}
|
||||||
|
jnj{a<996:A,s<3488:R,R}
|
||||||
|
kfg{s<786:qtq,A}
|
||||||
|
tjm{s<2018:R,s<2038:R,R}
|
||||||
|
dkx{x>2834:R,x<2537:R,nx}
|
||||||
|
zfc{m<2823:gbj,crk}
|
||||||
|
ff{m>1893:dc,a>3780:gng,xjz}
|
||||||
|
vmf{x<1019:A,A}
|
||||||
|
ghs{a<703:A,a>738:R,nzg}
|
||||||
|
gs{a<393:R,a<477:R,s<3909:R,zsf}
|
||||||
|
zvg{s>2319:A,x>1801:A,A}
|
||||||
|
gk{x<2559:R,A}
|
||||||
|
xjz{s<2581:R,x>2364:R,a<3606:A,tqc}
|
||||||
|
sd{x<2625:R,A}
|
||||||
|
mdj{s>3552:A,x>946:A,R}
|
||||||
|
nbd{x<1042:sq,m<915:A,tmj}
|
||||||
|
tmj{m>1880:A,x>1503:R,A}
|
||||||
|
drm{x>3299:R,s<1171:mx,R}
|
||||||
|
cs{m>1405:A,x>2157:A,tp}
|
||||||
|
xtc{x<2884:R,A}
|
||||||
|
gj{a>929:vhj,a<885:R,A}
|
||||||
|
mml{m>2426:rjc,a>3449:hpk,cct}
|
||||||
|
hfb{x<1738:xc,R}
|
||||||
|
vk{m<3572:A,m>3601:A,s>1380:R,R}
|
||||||
|
dmf{a<2866:A,R}
|
||||||
|
jx{m<1993:R,R}
|
||||||
|
vz{m<408:R,A}
|
||||||
|
cr{m>3114:R,x<927:A,R}
|
||||||
|
rqd{a>827:R,m<3616:A,R}
|
||||||
|
hxm{a<2012:A,a<2147:R,s>1974:R,R}
|
||||||
|
fgr{m>3145:A,R}
|
||||||
|
ljm{a>175:th,x>2267:R,s>203:A,R}
|
||||||
|
sh{x<2556:A,s<2802:qkk,x>3244:R,lpq}
|
||||||
|
mh{x<3136:R,jcn}
|
||||||
|
jcv{x>3293:A,A}
|
||||||
|
xh{m<3719:A,x<825:A,R}
|
||||||
|
nn{s>3158:R,a>1035:A,m>397:A,A}
|
||||||
|
np{m<3051:pnp,scf}
|
||||||
|
xd{m<3074:A,s<2935:A,a>2618:A,R}
|
||||||
|
njr{m>623:R,x<2518:A,R}
|
||||||
|
vmj{x>1396:pv,a<2288:bfk,R}
|
||||||
|
rt{a>991:xg,a>395:R,a>238:A,vz}
|
||||||
|
lmf{a<941:tq,s<1601:R,R}
|
||||||
|
zdz{s>2837:R,m<2501:cvx,a<2586:R,A}
|
||||||
|
gmg{a>3638:A,a>3540:R,A}
|
||||||
|
zmk{m>3609:vkb,jc}
|
||||||
|
skj{a>908:R,a>564:R,x<489:tnt,R}
|
||||||
|
mb{m>3811:ktz,x<1811:gl,rjx}
|
||||||
|
rl{x<2034:R,m>1003:A,a<3236:A,R}
|
||||||
|
dvz{m>1954:kgq,hpb}
|
||||||
|
hmk{x>3265:R,s>1639:A,s>1393:R,R}
|
||||||
|
dfq{s>1884:hjr,a>3606:bq,m<2391:hvz,fd}
|
||||||
|
jqd{x<2830:cjt,jtn}
|
||||||
|
vhd{m>2806:pp,a<962:dsd,A}
|
||||||
|
knb{a>1140:R,qv}
|
||||||
|
br{x<1778:R,R}
|
||||||
|
zkt{s>3133:R,m<3860:R,A}
|
||||||
|
zgq{a>1715:R,m<3933:R,A}
|
||||||
|
xjj{a<1879:R,x>3421:qbr,x<3014:R,R}
|
||||||
|
bg{m<731:A,m<1261:R,a<1026:A,A}
|
||||||
|
ct{x<2963:A,s<2119:R,x>3312:A,A}
|
||||||
|
bvx{x>2177:R,m<1910:rl,x>1943:bzg,nv}
|
||||||
|
hg{x>2696:jnq,x>2077:bt,bn}
|
||||||
|
hs{x<3271:R,A}
|
||||||
|
tvs{a<654:rg,m<2741:fq,qdh}
|
||||||
|
qtq{a<982:R,a<1234:A,R}
|
||||||
|
gcg{m>3101:R,a<480:R,A}
|
||||||
|
vp{a>3910:R,s>2776:A,a>3898:A,A}
|
||||||
|
pd{x>1921:A,A}
|
||||||
|
xt{a>967:R,m>3516:A,a>776:R,A}
|
||||||
|
qc{a>3321:R,A}
|
||||||
|
tkb{a<1063:vmr,a>1959:zlg,ctf}
|
||||||
|
bcs{s>2230:lxs,s>2030:R,m<743:slv,A}
|
||||||
|
qn{a<3266:A,a>3348:R,m<2667:R,A}
|
||||||
|
cvx{x>2282:A,m<2005:R,a<2628:A,R}
|
||||||
|
hrg{m>356:R,s>3696:R,A}
|
||||||
|
hvz{s<1848:A,a<3490:A,s<1870:A,xcc}
|
||||||
|
lh{s>1362:R,x>1231:R,a>1747:R,R}
|
||||||
|
vc{m<422:jxl,x>2315:zdg,sk}
|
||||||
|
fts{x<952:skj,a>1143:sm,x<1335:sql,kmt}
|
||||||
|
jsg{x>2596:R,x>1393:A,m>3518:R,A}
|
||||||
|
hk{x>1083:R,m>3604:R,A}
|
||||||
|
mt{s>2812:R,x<595:R,s>2688:R,A}
|
||||||
|
cdz{x>1644:R,m>1862:R,A}
|
||||||
|
pxv{a<3725:nt,a<3830:A,A}
|
||||||
|
njd{m<2225:R,mkk}
|
||||||
|
mjx{s<1366:dqb,tj}
|
||||||
|
bfk{a>2248:R,R}
|
||||||
|
xs{m<518:pxv,a<3589:rxz,a>3783:dv,gr}
|
||||||
|
djc{s>2174:A,js}
|
||||||
|
zx{x<1016:A,x<1528:R,R}
|
||||||
|
mzd{a>2015:R,R}
|
||||||
|
knq{a>3143:R,x>3377:R,R}
|
||||||
|
bq{s>1846:A,s>1827:cpr,fvr}
|
||||||
|
zdg{s>3443:A,a>1681:mzd,s<2909:dp,A}
|
||||||
|
sll{m<2763:R,s<1342:ssq,R}
|
||||||
|
ft{m<1121:A,s>1882:A,s>1847:R,R}
|
||||||
|
dnq{x>1487:bl,s<3256:tpk,m<3063:rgr,gmd}
|
||||||
|
bqz{a>2865:R,A}
|
||||||
|
sdj{m>1268:A,s<1037:R,a<3341:A,R}
|
||||||
|
dc{s>2554:A,m<2684:R,qsg}
|
||||||
|
bbq{s>2709:A,s>2586:A,R}
|
||||||
|
js{m<1039:A,A}
|
||||||
|
hjr{x<1882:R,s>1927:R,jcv}
|
||||||
|
lk{a>3257:bj,a>2920:A,m>1832:fv,R}
|
||||||
|
ts{a>401:R,a<339:A,s<3429:A,R}
|
||||||
|
xr{x<1991:sv,s<2852:qh,s<2893:hh,sfd}
|
||||||
|
bl{m<2988:A,a>784:xsb,a>295:skb,ps}
|
||||||
|
kg{x<1065:R,x>1534:A,R}
|
||||||
|
gf{x<3539:A,a<3041:R,R}
|
||||||
|
ckj{s<2886:A,s>2893:A,A}
|
||||||
|
fg{s<2314:A,m<139:R,x>1421:A,R}
|
||||||
|
mn{x<3000:A,m>315:R,m<177:A,R}
|
||||||
|
vrt{s>3263:A,a<878:R,x>2044:A,R}
|
||||||
|
npv{x<687:R,A}
|
||||||
|
ljt{x<2374:R,A}
|
||||||
|
pbp{a>1398:hxm,a>588:xt,a<333:kcn,R}
|
||||||
|
fgd{s>1796:R,x>2219:R,m<3069:A,R}
|
||||||
|
xhs{a<752:R,zpq}
|
||||||
|
tf{m<2132:A,m>2187:A,A}
|
||||||
|
qjl{s<1624:zdd,s>1981:klp,bhv}
|
||||||
|
gx{s<1192:A,s>1376:R,R}
|
||||||
|
hsz{m>3435:R,s<2747:A,A}
|
||||||
|
rkz{a>1486:bxk,m<3808:R,a>1388:A,zkt}
|
||||||
|
mjf{x>2320:A,x<1139:A,R}
|
||||||
|
gl{a>1425:bd,s>1660:frk,s>1500:lmf,xzp}
|
||||||
|
gvr{m<2241:R,R}
|
||||||
|
bnv{s<3071:R,R}
|
||||||
|
vcc{m<618:sl,x>2269:zg,rhs}
|
||||||
|
ghz{x>1927:A,a<394:A,m<231:A,R}
|
||||||
|
crk{m<2842:R,x>2970:A,x<2213:R,R}
|
||||||
|
mfx{a>731:zxc,m<547:kdt,s>3502:tsn,jxm}
|
||||||
|
pjq{m<3273:A,a<945:A,A}
|
||||||
|
tpk{m>2975:drj,xz}
|
||||||
|
qpt{x>2909:A,a>991:A,a<810:R,R}
|
||||||
|
jc{m>3552:R,R}
|
||||||
|
rd{s<2850:R,x>3613:A,s>2904:xd,ckj}
|
||||||
|
rlx{x>3373:R,A}
|
||||||
|
hkv{a>502:mhm,s>3324:R,A}
|
||||||
|
dsd{s<1357:R,x<3340:R,R}
|
||||||
|
ln{s>1813:ztb,m>3116:rnx,A}
|
||||||
|
czr{m>2538:R,A}
|
||||||
|
xxb{s>2993:R,x>2787:R,dtt}
|
||||||
|
mf{s<1679:A,m<538:A,R}
|
||||||
|
zb{s>2579:njd,hg}
|
||||||
|
sn{m>3668:gdh,x>2740:A,s>624:R,gnx}
|
||||||
|
trs{a<1933:nm,mq}
|
||||||
|
xcq{m>3184:vlz,x<2483:R,R}
|
||||||
|
hx{s>3738:gs,x<3448:kbp,klr}
|
||||||
|
cz{s>1882:qk,m<3508:pxd,mb}
|
||||||
|
gmd{x>924:A,x<437:A,gcg}
|
||||||
|
|
||||||
|
{x=363,m=218,a=594,s=411}
|
||||||
|
{x=973,m=37,a=2533,s=132}
|
||||||
|
{x=2768,m=1537,a=645,s=580}
|
||||||
|
{x=2079,m=168,a=502,s=656}
|
||||||
|
{x=38,m=145,a=3452,s=1162}
|
||||||
|
{x=70,m=1238,a=99,s=560}
|
||||||
|
{x=1261,m=1540,a=283,s=28}
|
||||||
|
{x=1194,m=780,a=1538,s=2681}
|
||||||
|
{x=1236,m=1847,a=1403,s=1086}
|
||||||
|
{x=2227,m=163,a=716,s=410}
|
||||||
|
{x=9,m=369,a=572,s=1418}
|
||||||
|
{x=201,m=1472,a=943,s=3541}
|
||||||
|
{x=2730,m=1777,a=127,s=3031}
|
||||||
|
{x=329,m=139,a=1310,s=2983}
|
||||||
|
{x=54,m=981,a=1378,s=783}
|
||||||
|
{x=658,m=410,a=482,s=490}
|
||||||
|
{x=1555,m=1246,a=365,s=2769}
|
||||||
|
{x=1075,m=95,a=806,s=750}
|
||||||
|
{x=408,m=125,a=2296,s=1599}
|
||||||
|
{x=715,m=1257,a=1287,s=1638}
|
||||||
|
{x=63,m=1295,a=169,s=1802}
|
||||||
|
{x=2068,m=4,a=768,s=365}
|
||||||
|
{x=1390,m=3366,a=1730,s=1631}
|
||||||
|
{x=1900,m=622,a=761,s=1108}
|
||||||
|
{x=1857,m=678,a=136,s=965}
|
||||||
|
{x=3295,m=47,a=303,s=63}
|
||||||
|
{x=2853,m=700,a=315,s=647}
|
||||||
|
{x=379,m=304,a=914,s=59}
|
||||||
|
{x=2591,m=385,a=1410,s=1473}
|
||||||
|
{x=140,m=1237,a=769,s=2670}
|
||||||
|
{x=747,m=395,a=1988,s=633}
|
||||||
|
{x=30,m=381,a=1966,s=2597}
|
||||||
|
{x=1969,m=1191,a=501,s=328}
|
||||||
|
{x=127,m=1200,a=47,s=2408}
|
||||||
|
{x=1409,m=2136,a=205,s=3122}
|
||||||
|
{x=150,m=88,a=1082,s=3059}
|
||||||
|
{x=320,m=2917,a=1371,s=22}
|
||||||
|
{x=2237,m=1186,a=466,s=2252}
|
||||||
|
{x=2460,m=7,a=1758,s=874}
|
||||||
|
{x=421,m=126,a=1338,s=1479}
|
||||||
|
{x=150,m=675,a=2555,s=267}
|
||||||
|
{x=1007,m=1178,a=2927,s=2435}
|
||||||
|
{x=902,m=190,a=77,s=1279}
|
||||||
|
{x=1393,m=716,a=686,s=569}
|
||||||
|
{x=339,m=1199,a=275,s=338}
|
||||||
|
{x=116,m=1997,a=739,s=142}
|
||||||
|
{x=1332,m=69,a=74,s=1953}
|
||||||
|
{x=2324,m=2089,a=101,s=1595}
|
||||||
|
{x=2966,m=696,a=305,s=1221}
|
||||||
|
{x=810,m=1860,a=141,s=49}
|
||||||
|
{x=995,m=382,a=1020,s=756}
|
||||||
|
{x=899,m=133,a=746,s=952}
|
||||||
|
{x=325,m=1880,a=554,s=1749}
|
||||||
|
{x=506,m=1478,a=897,s=597}
|
||||||
|
{x=659,m=424,a=20,s=1447}
|
||||||
|
{x=4,m=310,a=1121,s=286}
|
||||||
|
{x=3357,m=396,a=1204,s=2886}
|
||||||
|
{x=1209,m=614,a=2397,s=408}
|
||||||
|
{x=505,m=339,a=72,s=709}
|
||||||
|
{x=3478,m=1412,a=1777,s=1}
|
||||||
|
{x=2271,m=136,a=83,s=477}
|
||||||
|
{x=3008,m=280,a=2167,s=1522}
|
||||||
|
{x=543,m=772,a=433,s=3560}
|
||||||
|
{x=227,m=2037,a=1444,s=272}
|
||||||
|
{x=869,m=80,a=2585,s=1212}
|
||||||
|
{x=893,m=1207,a=124,s=126}
|
||||||
|
{x=2178,m=2030,a=3000,s=1438}
|
||||||
|
{x=450,m=1798,a=1307,s=2147}
|
||||||
|
{x=469,m=1554,a=1080,s=393}
|
||||||
|
{x=49,m=389,a=813,s=39}
|
||||||
|
{x=3041,m=607,a=379,s=1435}
|
||||||
|
{x=62,m=121,a=47,s=2394}
|
||||||
|
{x=1589,m=2474,a=1599,s=3}
|
||||||
|
{x=439,m=1493,a=284,s=3}
|
||||||
|
{x=619,m=1377,a=1107,s=3452}
|
||||||
|
{x=1802,m=1132,a=851,s=111}
|
||||||
|
{x=2154,m=464,a=2611,s=2147}
|
||||||
|
{x=843,m=423,a=355,s=838}
|
||||||
|
{x=3,m=423,a=139,s=857}
|
||||||
|
{x=42,m=843,a=2219,s=3695}
|
||||||
|
{x=1068,m=575,a=88,s=222}
|
||||||
|
{x=3097,m=238,a=913,s=2452}
|
||||||
|
{x=109,m=206,a=291,s=728}
|
||||||
|
{x=3635,m=1815,a=26,s=19}
|
||||||
|
{x=49,m=115,a=2998,s=26}
|
||||||
|
{x=2093,m=391,a=267,s=2896}
|
||||||
|
{x=282,m=2364,a=62,s=62}
|
||||||
|
{x=361,m=719,a=1679,s=137}
|
||||||
|
{x=631,m=1131,a=203,s=2281}
|
||||||
|
{x=794,m=1004,a=868,s=636}
|
||||||
|
{x=1702,m=415,a=35,s=236}
|
||||||
|
{x=63,m=1690,a=682,s=2009}
|
||||||
|
{x=1815,m=3459,a=144,s=374}
|
||||||
|
{x=91,m=590,a=1651,s=1681}
|
||||||
|
{x=1561,m=2303,a=307,s=1463}
|
||||||
|
{x=842,m=927,a=868,s=455}
|
||||||
|
{x=51,m=23,a=427,s=247}
|
||||||
|
{x=2431,m=187,a=267,s=184}
|
||||||
|
{x=1596,m=1904,a=668,s=1553}
|
||||||
|
{x=922,m=1435,a=336,s=1301}
|
||||||
|
{x=1038,m=1632,a=220,s=117}
|
||||||
|
{x=1935,m=1433,a=2988,s=316}
|
||||||
|
{x=21,m=1158,a=1988,s=1242}
|
||||||
|
{x=840,m=1272,a=418,s=1198}
|
||||||
|
{x=1227,m=1811,a=158,s=10}
|
||||||
|
{x=1836,m=56,a=19,s=1573}
|
||||||
|
{x=461,m=621,a=532,s=92}
|
||||||
|
{x=2082,m=1292,a=1032,s=322}
|
||||||
|
{x=2094,m=249,a=865,s=2030}
|
||||||
|
{x=1092,m=265,a=1745,s=1720}
|
||||||
|
{x=2361,m=1087,a=209,s=1934}
|
||||||
|
{x=92,m=111,a=3188,s=2172}
|
||||||
|
{x=248,m=2163,a=1351,s=1194}
|
||||||
|
{x=1675,m=2194,a=324,s=1764}
|
||||||
|
{x=2148,m=3124,a=854,s=1823}
|
||||||
|
{x=520,m=617,a=649,s=49}
|
||||||
|
{x=2497,m=12,a=270,s=161}
|
||||||
|
{x=248,m=2,a=1026,s=1196}
|
||||||
|
{x=367,m=860,a=1141,s=61}
|
||||||
|
{x=411,m=90,a=3401,s=2156}
|
||||||
|
{x=284,m=265,a=421,s=866}
|
||||||
|
{x=2152,m=2245,a=1206,s=1056}
|
||||||
|
{x=1578,m=74,a=93,s=1494}
|
||||||
|
{x=225,m=50,a=2223,s=1888}
|
||||||
|
{x=2448,m=372,a=587,s=820}
|
||||||
|
{x=1222,m=215,a=31,s=1753}
|
||||||
|
{x=2906,m=1170,a=1120,s=291}
|
||||||
|
{x=1253,m=329,a=478,s=2489}
|
||||||
|
{x=563,m=150,a=103,s=1051}
|
||||||
|
{x=212,m=980,a=1325,s=882}
|
||||||
|
{x=580,m=754,a=555,s=1470}
|
||||||
|
{x=522,m=397,a=1018,s=763}
|
||||||
|
{x=2327,m=1100,a=975,s=511}
|
||||||
|
{x=324,m=1719,a=48,s=569}
|
||||||
|
{x=1872,m=3353,a=54,s=1330}
|
||||||
|
{x=2082,m=1209,a=2390,s=747}
|
||||||
|
{x=1510,m=2290,a=591,s=45}
|
||||||
|
{x=60,m=1482,a=924,s=598}
|
||||||
|
{x=775,m=675,a=1635,s=1560}
|
||||||
|
{x=316,m=170,a=168,s=1335}
|
||||||
|
{x=1821,m=79,a=2073,s=92}
|
||||||
|
{x=612,m=1814,a=1651,s=3496}
|
||||||
|
{x=116,m=2643,a=1073,s=301}
|
||||||
|
{x=313,m=92,a=2892,s=109}
|
||||||
|
{x=1109,m=279,a=701,s=763}
|
||||||
|
{x=86,m=214,a=1910,s=99}
|
||||||
|
{x=1049,m=320,a=530,s=216}
|
||||||
|
{x=192,m=366,a=887,s=1516}
|
||||||
|
{x=353,m=107,a=257,s=225}
|
||||||
|
{x=117,m=72,a=810,s=147}
|
||||||
|
{x=341,m=17,a=190,s=2748}
|
||||||
|
{x=1397,m=572,a=2275,s=1494}
|
||||||
|
{x=386,m=1691,a=346,s=985}
|
||||||
|
{x=603,m=584,a=1464,s=291}
|
||||||
|
{x=49,m=46,a=2277,s=1200}
|
||||||
|
{x=3116,m=1,a=500,s=166}
|
||||||
|
{x=310,m=1054,a=1271,s=1423}
|
||||||
|
{x=1690,m=721,a=1555,s=232}
|
||||||
|
{x=1713,m=2002,a=1132,s=611}
|
||||||
|
{x=229,m=1721,a=1590,s=42}
|
||||||
|
{x=16,m=1444,a=2296,s=144}
|
||||||
|
{x=371,m=339,a=1073,s=1585}
|
||||||
|
{x=1025,m=10,a=491,s=196}
|
||||||
|
{x=58,m=1161,a=492,s=1401}
|
||||||
|
{x=305,m=1366,a=919,s=236}
|
||||||
|
{x=1427,m=654,a=2052,s=2399}
|
||||||
|
{x=1312,m=723,a=408,s=173}
|
||||||
|
{x=589,m=703,a=29,s=126}
|
||||||
|
{x=2609,m=1461,a=266,s=129}
|
||||||
|
{x=299,m=253,a=857,s=2220}
|
||||||
|
{x=259,m=600,a=494,s=546}
|
||||||
|
{x=2978,m=988,a=1660,s=2661}
|
||||||
|
{x=193,m=478,a=213,s=1631}
|
||||||
|
{x=3378,m=2275,a=534,s=2317}
|
||||||
|
{x=654,m=2641,a=284,s=1768}
|
||||||
|
{x=50,m=76,a=672,s=120}
|
||||||
|
{x=85,m=630,a=1446,s=1321}
|
||||||
|
{x=306,m=986,a=808,s=1724}
|
||||||
|
{x=782,m=1554,a=741,s=2220}
|
||||||
|
{x=1115,m=48,a=3283,s=958}
|
||||||
|
{x=214,m=2498,a=996,s=981}
|
||||||
|
{x=1437,m=53,a=2052,s=914}
|
||||||
|
{x=3256,m=441,a=47,s=108}
|
||||||
|
{x=689,m=1954,a=60,s=133}
|
||||||
|
{x=1,m=2270,a=903,s=13}
|
||||||
|
{x=2373,m=956,a=2739,s=860}
|
||||||
|
{x=1270,m=357,a=2115,s=1868}
|
||||||
|
{x=114,m=587,a=349,s=62}
|
||||||
|
{x=186,m=491,a=464,s=46}
|
||||||
|
{x=2001,m=99,a=649,s=1854}
|
||||||
|
{x=408,m=386,a=681,s=774}
|
||||||
|
{x=697,m=775,a=2740,s=1582}
|
||||||
|
{x=525,m=2075,a=11,s=822}
|
||||||
|
{x=621,m=1069,a=233,s=255}
|
||||||
|
{x=979,m=2750,a=241,s=199}
|
||||||
|
{x=2006,m=665,a=2211,s=1776}
|
||||||
|
{x=483,m=213,a=2042,s=67}
|
||||||
|
{x=1181,m=1199,a=1513,s=919}
|
||||||
|
{x=1378,m=274,a=438,s=546}
|
||||||
|
{x=59,m=224,a=3034,s=254}
|
392
19/src/main.rs
Normal file
392
19/src/main.rs
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::ops::{Range, IndexMut, Index};
|
||||||
|
use std::time::Instant;
|
||||||
|
use num_traits::Num;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// DATA
|
||||||
|
|
||||||
|
const INPUT_RANGE: Range<u64> = 1..4001;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct RulePredicate {
|
||||||
|
op: PredicateOperator,
|
||||||
|
var: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum RuleAction {
|
||||||
|
Terminate(bool),
|
||||||
|
Jump(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for RuleAction {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
match s {
|
||||||
|
"A" => Self::Terminate(true),
|
||||||
|
"R" => Self::Terminate(false),
|
||||||
|
s => Self::Jump(s.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Rule {
|
||||||
|
pred: RulePredicate,
|
||||||
|
action: RuleAction,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum PredicateOperator {
|
||||||
|
Always,
|
||||||
|
Lt(u64),
|
||||||
|
Gt(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct XmasRanges {
|
||||||
|
ranges: [Vec<Range<u64>>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XmasRanges {
|
||||||
|
fn none() -> XmasRanges {
|
||||||
|
Self {
|
||||||
|
ranges: [vec![0..0], vec![0..0], vec![0..0], vec![0..0]],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn all() -> XmasRanges {
|
||||||
|
Self {
|
||||||
|
ranges: [
|
||||||
|
vec![INPUT_RANGE],
|
||||||
|
vec![INPUT_RANGE],
|
||||||
|
vec![INPUT_RANGE],
|
||||||
|
vec![INPUT_RANGE],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn idx(c: char) -> usize {
|
||||||
|
match c {
|
||||||
|
'x' => 0,
|
||||||
|
'm' => 1,
|
||||||
|
'a' => 2,
|
||||||
|
's' => 3,
|
||||||
|
c => panic!("`{}` is not a valid xmas char", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn insert(&mut self, c: char, v: Vec<Range<u64>>) {
|
||||||
|
self.ranges[Self::idx(c)] = v;
|
||||||
|
}
|
||||||
|
fn count_states(&self) -> u64 {
|
||||||
|
self.ranges
|
||||||
|
.iter()
|
||||||
|
.map(|ranges| ranges.iter().map(|range| range.end - range.start).sum::<u64>())
|
||||||
|
.product()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<char> for XmasRanges {
|
||||||
|
type Output = Vec<Range<u64>>;
|
||||||
|
fn index(&self, index: char) -> &Self::Output {
|
||||||
|
&self.ranges[Self::idx(index)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<char> for XmasRanges {
|
||||||
|
fn index_mut(&mut self, index: char) -> &mut Self::Output {
|
||||||
|
&mut self.ranges[Self::idx(index)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn range_overlap<T: Num + Ord + Copy>(r1: &Range<T>, r2: &Range<T>) -> Option<Range<T>> {
|
||||||
|
let new_start = std::cmp::max(r1.start, r2.start);
|
||||||
|
let new_end = std::cmp::min(r1.end - T::one(), r2.end - T::one());
|
||||||
|
|
||||||
|
if new_start <= std::cmp::min(r1.end - T::one(), r2.end - T::one()) && new_end >= std::cmp::max(r1.start, r2.start)
|
||||||
|
{
|
||||||
|
Some(new_start..new_end + T::one())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn range_exclude<T: Num + Ord + Copy>(keep: &Range<T>, exclude: &Range<T>) -> Vec<Range<T>> {
|
||||||
|
let mut residual = Vec::new();
|
||||||
|
if let Some(overlap) = range_overlap(keep, exclude) {
|
||||||
|
if keep.start < overlap.start {
|
||||||
|
residual.push(keep.start..overlap.start);
|
||||||
|
}
|
||||||
|
if keep.end > overlap.end {
|
||||||
|
residual.push(overlap.end..keep.end);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
residual.push(keep.clone());
|
||||||
|
}
|
||||||
|
residual
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for PredicateOperator {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let (op_s, val_s) = s.split_at(1);
|
||||||
|
match op_s {
|
||||||
|
"<" => PredicateOperator::Lt(val_s.parse().unwrap()),
|
||||||
|
">" => PredicateOperator::Gt(val_s.parse().unwrap()),
|
||||||
|
s => panic!("unknown operator {}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for RulePredicate {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let (var_s, pred_s) = s.split_at(1);
|
||||||
|
Self {
|
||||||
|
op: pred_s.into(),
|
||||||
|
var: var_s.chars().next().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RulePredicate {
|
||||||
|
fn check(&self, part: &Part) -> bool {
|
||||||
|
match self.op {
|
||||||
|
PredicateOperator::Always => true,
|
||||||
|
PredicateOperator::Gt(val) => part.0[&self.var] > val,
|
||||||
|
PredicateOperator::Lt(val) => part.0[&self.var] < val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn matching_range(&self) -> Range<u64> {
|
||||||
|
match self.op {
|
||||||
|
PredicateOperator::Always => INPUT_RANGE,
|
||||||
|
PredicateOperator::Gt(val) => val + 1..INPUT_RANGE.end,
|
||||||
|
PredicateOperator::Lt(val) => INPUT_RANGE.start..val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Rule {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
if let Some((predicate_s, action_s)) = s.split_once(':') {
|
||||||
|
Self {
|
||||||
|
pred: predicate_s.into(),
|
||||||
|
action: action_s.into(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Self {
|
||||||
|
pred: RulePredicate {
|
||||||
|
op: PredicateOperator::Always,
|
||||||
|
var: '\0',
|
||||||
|
},
|
||||||
|
action: s.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rule {
|
||||||
|
fn predicate_result(&self, ranges: XmasRanges) -> (XmasRanges, XmasRanges) {
|
||||||
|
if let PredicateOperator::Always = self.pred.op {
|
||||||
|
(ranges, XmasRanges::none())
|
||||||
|
} else {
|
||||||
|
let (mut matching, mut unmatching) = (ranges.clone(), ranges.clone());
|
||||||
|
let relevant_ranges = &ranges[self.pred.var];
|
||||||
|
matching.insert(
|
||||||
|
self.pred.var,
|
||||||
|
relevant_ranges
|
||||||
|
.iter()
|
||||||
|
.filter_map(|range| range_overlap(range, &self.pred.matching_range()))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
unmatching.insert(
|
||||||
|
self.pred.var,
|
||||||
|
relevant_ranges
|
||||||
|
.iter()
|
||||||
|
.flat_map(|range| range_exclude(range, &self.pred.matching_range()))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
(matching, unmatching)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn possible_ranges(&self, wfs: &Workflows, ranges: XmasRanges) -> (u64, XmasRanges) {
|
||||||
|
let (matching, unmatching) = self.predicate_result(ranges);
|
||||||
|
match &self.action {
|
||||||
|
RuleAction::Terminate(true) => (matching.count_states(), unmatching),
|
||||||
|
RuleAction::Terminate(false) => (0, unmatching),
|
||||||
|
RuleAction::Jump(wf) => (wfs.0[wf].possible_ranges(wfs, matching), unmatching),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Workflow {
|
||||||
|
name: String,
|
||||||
|
rules: Vec<Rule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Workflow {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let (name_s, rest_s) = s.split_once('{').unwrap();
|
||||||
|
let rules = rest_s.split_once('}').unwrap().0.split(',').map(|r| r.into()).collect();
|
||||||
|
Self {
|
||||||
|
name: name_s.into(),
|
||||||
|
rules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Workflow {
|
||||||
|
fn execute(&self, part: &Part) -> RuleAction {
|
||||||
|
for r in &self.rules {
|
||||||
|
if r.pred.check(part) {
|
||||||
|
return r.action.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("unhandled part {:?}", part);
|
||||||
|
}
|
||||||
|
fn possible_ranges(&self, wfs: &Workflows, mut ranges: XmasRanges) -> u64 {
|
||||||
|
let mut accum = 0u64;
|
||||||
|
for r in &self.rules {
|
||||||
|
let count;
|
||||||
|
(count, ranges) = r.possible_ranges(wfs, ranges);
|
||||||
|
accum += count
|
||||||
|
}
|
||||||
|
accum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Workflows {
|
||||||
|
fn execute(&self, part: &Part) -> bool {
|
||||||
|
let mut action = RuleAction::Jump("in".into());
|
||||||
|
loop {
|
||||||
|
match &action {
|
||||||
|
RuleAction::Terminate(b) => return *b,
|
||||||
|
RuleAction::Jump(j) => {
|
||||||
|
let next_workflow = &self.0[j];
|
||||||
|
action = next_workflow.execute(part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_possible_states(&self) -> u64 {
|
||||||
|
self.0["in".into()].possible_ranges(self, XmasRanges::all())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Workflows(HashMap<String, Workflow>);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Part(HashMap<char, u64>);
|
||||||
|
|
||||||
|
impl From<&str> for Part {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let (_, vars_s) = s.split_once('{').unwrap();
|
||||||
|
let vars = vars_s.split_once('}').unwrap().0.split(',');
|
||||||
|
let mut part = HashMap::new();
|
||||||
|
for var in vars {
|
||||||
|
let (name, val) = var.split_once('=').unwrap();
|
||||||
|
part.insert(name.chars().next().unwrap(), val.parse().unwrap());
|
||||||
|
}
|
||||||
|
Self(part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parts = Vec<Part>;
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(mut input: Lines<T>) -> u64 {
|
||||||
|
let mut wfs = Workflows(HashMap::new());
|
||||||
|
let mut parts: Parts = Vec::new();
|
||||||
|
while let Some(Ok(line)) = input.next() {
|
||||||
|
if line != "" {
|
||||||
|
let wf: Workflow = line.as_str().into();
|
||||||
|
wfs.0.insert(wf.name.clone(), wf);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while let Some(Ok(line)) = input.next() {
|
||||||
|
parts.push(line.as_str().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
parts
|
||||||
|
.iter()
|
||||||
|
.filter(|part| wfs.execute(part))
|
||||||
|
.map(|part| part.0.values().sum::<u64>())
|
||||||
|
.sum::<u64>()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(mut input: Lines<T>) -> u64 {
|
||||||
|
let mut wfs = Workflows(HashMap::new());
|
||||||
|
let mut parts: Parts = Vec::new();
|
||||||
|
while let Some(Ok(line)) = input.next() {
|
||||||
|
if line != "" {
|
||||||
|
let wf: Workflow = line.as_str().into();
|
||||||
|
wfs.0.insert(wf.name.clone(), wf);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while let Some(Ok(line)) = input.next() {
|
||||||
|
parts.push(line.as_str().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
wfs.count_possible_states()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
const EXAMPLE: &str = &"px{a<2006:qkq,m>2090:A,rfg}
|
||||||
|
pv{a>1716:R,A}
|
||||||
|
lnx{m>1548:A,A}
|
||||||
|
rfg{s<537:gd,x>2440:R,A}
|
||||||
|
qs{s>3448:A,lnx}
|
||||||
|
qkq{x<1416:A,crn}
|
||||||
|
crn{x>2662:A,R}
|
||||||
|
in{s<1351:px,qqz}
|
||||||
|
qqz{s>2770:qs,m<1801:hdj,R}
|
||||||
|
gd{a>3333:R,R}
|
||||||
|
hdj{m>838:A,pv}
|
||||||
|
|
||||||
|
{x=787,m=2655,a=1222,s=2876}
|
||||||
|
{x=1679,m=44,a=2067,s=496}
|
||||||
|
{x=2036,m=264,a=79,s=2244}
|
||||||
|
{x=2461,m=1339,a=466,s=291}
|
||||||
|
{x=2127,m=1623,a=2188,s=1013}";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 19114);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 167409079868000);
|
||||||
|
}
|
||||||
|
}
|
201
20/Cargo.lock
generated
Normal file
201
20/Cargo.lock
generated
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day20"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex",
|
||||||
|
"num",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex-proc_macros",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex-proc_macros"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.41"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
10
20/Cargo.toml
Normal file
10
20/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day20"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lazy-regex = "3.1.0"
|
||||||
|
num = "0.4.1"
|
58
20/input
Normal file
58
20/input
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
%hm -> cr
|
||||||
|
%qc -> nd
|
||||||
|
&dh -> rm
|
||||||
|
%ph -> zz
|
||||||
|
%ps -> kc, dt
|
||||||
|
%qb -> dt
|
||||||
|
%jl -> vt, tb
|
||||||
|
%fh -> dm, gr
|
||||||
|
broadcaster -> np, mg, vd, xr
|
||||||
|
%zz -> sq
|
||||||
|
&rm -> rx
|
||||||
|
%nd -> br
|
||||||
|
%nx -> vr, vt
|
||||||
|
%qf -> dt, dv
|
||||||
|
%np -> xm, ph
|
||||||
|
%dm -> nf, gr
|
||||||
|
%sq -> kj
|
||||||
|
%bv -> fp, xm
|
||||||
|
%br -> kt
|
||||||
|
%mg -> dz, gr
|
||||||
|
&dt -> vd, dv, dh, hm, ks, hd, kq
|
||||||
|
%ks -> qf
|
||||||
|
&qd -> rm
|
||||||
|
%xr -> vt, rn
|
||||||
|
%vr -> tg, vt
|
||||||
|
%lc -> xm
|
||||||
|
%tq -> gr, fh
|
||||||
|
%cr -> kq, dt
|
||||||
|
%vd -> dt, ks
|
||||||
|
%tb -> nx
|
||||||
|
%dz -> gr, fd
|
||||||
|
&gr -> dp, mg, fd, qn
|
||||||
|
%nf -> gr
|
||||||
|
%dv -> hm
|
||||||
|
%qj -> lc, xm
|
||||||
|
%kc -> dt, gf
|
||||||
|
%gf -> dt, qb
|
||||||
|
%vh -> xm, sv
|
||||||
|
%sr -> vt
|
||||||
|
%fp -> qg, xm
|
||||||
|
%kj -> vh
|
||||||
|
%pc -> tq, gr
|
||||||
|
%kq -> hd
|
||||||
|
%xd -> xg, gr
|
||||||
|
%tg -> sr, vt
|
||||||
|
&bb -> rm
|
||||||
|
%rn -> vt, qc
|
||||||
|
%hd -> ps
|
||||||
|
%qg -> xm, qj
|
||||||
|
&dp -> rm
|
||||||
|
%qn -> pc
|
||||||
|
%kt -> jl
|
||||||
|
%sv -> bv
|
||||||
|
&vt -> bb, nd, qc, xr, br, tb, kt
|
||||||
|
%fd -> mx
|
||||||
|
&xm -> zz, sv, sq, ph, kj, np, qd
|
||||||
|
%xg -> gr, qn
|
||||||
|
%mx -> gr, xd
|
362
20/src/main.rs
Normal file
362
20/src/main.rs
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
use std::collections::{BinaryHeap, HashMap, VecDeque};
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use lazy_regex::lazy_regex;
|
||||||
|
use num::integer::lcm;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
const MODULE_PATTERN: lazy_regex::Lazy<lazy_regex::Regex> = lazy_regex!("^([%&]?)([a-z]+) -> ([a-z, ]+)$");
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
enum PulseType {
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for PulseType {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
match value {
|
||||||
|
true => PulseType::High,
|
||||||
|
false => PulseType::Low,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PulseType> for bool {
|
||||||
|
fn from(value: PulseType) -> Self {
|
||||||
|
match value {
|
||||||
|
PulseType::High => true,
|
||||||
|
PulseType::Low => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PulseType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
PulseType::Low => f.write_str("low"),
|
||||||
|
PulseType::High => f.write_str("high"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum ModuleKind {
|
||||||
|
FlipFlop,
|
||||||
|
Conjunction,
|
||||||
|
Broadcast,
|
||||||
|
Button,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Module {
|
||||||
|
name: String,
|
||||||
|
kind: Option<ModuleKind>,
|
||||||
|
inputs: Vec<String>,
|
||||||
|
outputs: Vec<String>,
|
||||||
|
on: bool,
|
||||||
|
last_input_states: Vec<PulseType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for Module {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
// the only states that change are 'on' and 'last_input_states', the rest are constant once created
|
||||||
|
self.on.hash(state);
|
||||||
|
self.last_input_states.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
fn new(name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
kind: None,
|
||||||
|
inputs: Vec::new(),
|
||||||
|
outputs: Vec::new(),
|
||||||
|
on: false,
|
||||||
|
last_input_states: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn source_idx(&self, name: &str) -> usize {
|
||||||
|
self.inputs.iter().position(|in_name| in_name == name).unwrap()
|
||||||
|
}
|
||||||
|
fn with_kind(name: String, kind: ModuleKind) -> Self {
|
||||||
|
let mut m = Self::new(name);
|
||||||
|
m.kind = Some(kind);
|
||||||
|
m
|
||||||
|
}
|
||||||
|
fn and_destinations(mut self, destinations: &str) -> Self {
|
||||||
|
for dest in destinations.split(", ") {
|
||||||
|
self.outputs.push(dest.into());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn and_source(mut self, source: String) -> Self {
|
||||||
|
self.add_source(source);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn add_source(&mut self, source: String) {
|
||||||
|
self.inputs.push(source);
|
||||||
|
self.last_input_states.push(PulseType::Low);
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
// relevant state is on and last_input_states
|
||||||
|
self.on = false;
|
||||||
|
for input in &mut self.last_input_states {
|
||||||
|
*input = PulseType::Low;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn state_space(&self) -> u128 {
|
||||||
|
match self.kind {
|
||||||
|
Some(ModuleKind::Broadcast) | Some(ModuleKind::Button) => 1,
|
||||||
|
Some(ModuleKind::FlipFlop) => 2,
|
||||||
|
Some(ModuleKind::Conjunction) => 1 << self.last_input_states.len(), // 2^n
|
||||||
|
None => 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Module {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
let Some(re_result) = MODULE_PATTERN.captures(s) else {
|
||||||
|
panic!("unparseable module: {}", s);
|
||||||
|
};
|
||||||
|
let (_, [kind, name, destinations]) = re_result.extract();
|
||||||
|
if name == "broadcaster" {
|
||||||
|
return Module::with_kind(name.into(), ModuleKind::Broadcast).and_destinations(destinations);
|
||||||
|
};
|
||||||
|
match kind {
|
||||||
|
"%" => Module::with_kind(name.into(), ModuleKind::FlipFlop).and_destinations(destinations),
|
||||||
|
"&" => Module::with_kind(name.into(), ModuleKind::Conjunction).and_destinations(destinations),
|
||||||
|
_ => panic!("invalid module kind {}", kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Job {
|
||||||
|
signal: PulseType,
|
||||||
|
targets: Vec<String>,
|
||||||
|
from: String,
|
||||||
|
priority: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Job {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.priority == other.priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for Job {}
|
||||||
|
|
||||||
|
impl PartialOrd for Job {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
other.priority.partial_cmp(&self.priority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Job {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Machine {
|
||||||
|
modules: HashMap<String, Module>,
|
||||||
|
work_queue: BinaryHeap<Job>,
|
||||||
|
count_low: u64,
|
||||||
|
count_high: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Machine {
|
||||||
|
fn from(mut lines: Lines<T>) -> Self {
|
||||||
|
let mut modules = HashMap::from([(
|
||||||
|
"button".into(),
|
||||||
|
Module::with_kind("button".into(), ModuleKind::Button).and_destinations("broadcaster"),
|
||||||
|
)]);
|
||||||
|
while let Some(Ok(line)) = lines.next() {
|
||||||
|
let mut module = Module::from(line.as_str());
|
||||||
|
for output in &module.outputs {
|
||||||
|
if let Some(output_mod) = modules.get_mut(output) {
|
||||||
|
// already exists, push to input list
|
||||||
|
output_mod.add_source(module.name.to_owned());
|
||||||
|
} else {
|
||||||
|
// forward declaration of 'unknown' modules
|
||||||
|
modules.insert(
|
||||||
|
output.clone(),
|
||||||
|
Module::new(output.clone()).and_source(module.name.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(existing_mod) = modules.get(&module.name) {
|
||||||
|
module.inputs = existing_mod.inputs.clone(); // might have been pre-prepared, the rest we take ours
|
||||||
|
module.last_input_states = existing_mod.last_input_states.clone();
|
||||||
|
}
|
||||||
|
modules.insert(module.name.clone(), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
Machine {
|
||||||
|
modules,
|
||||||
|
work_queue: BinaryHeap::new(),
|
||||||
|
count_low: 0,
|
||||||
|
count_high: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Machine {
|
||||||
|
fn press_button(&mut self) {
|
||||||
|
self.send_pulse(PulseType::Low, "broadcaster", "button", 1);
|
||||||
|
}
|
||||||
|
fn send_pulse(&mut self, signal: PulseType, target: &str, from: &str, priority: usize) {
|
||||||
|
// count pulse when it is received
|
||||||
|
match signal {
|
||||||
|
PulseType::Low => self.count_low += 1,
|
||||||
|
PulseType::High => self.count_high += 1,
|
||||||
|
};
|
||||||
|
match self.modules[target].kind {
|
||||||
|
Some(ModuleKind::Button) | Some(ModuleKind::Broadcast) => {
|
||||||
|
self.send_all_outputs(PulseType::Low, target, priority)
|
||||||
|
}
|
||||||
|
Some(ModuleKind::FlipFlop) => match signal {
|
||||||
|
PulseType::High => (),
|
||||||
|
PulseType::Low => {
|
||||||
|
let new_state = !self.modules.get_mut(target).unwrap().on;
|
||||||
|
self.modules.get_mut(target).unwrap().on = new_state;
|
||||||
|
self.send_all_outputs(new_state.into(), target, priority)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(ModuleKind::Conjunction) => {
|
||||||
|
let target_m = self.modules.get_mut(target).unwrap();
|
||||||
|
let source_idx = target_m.source_idx(from);
|
||||||
|
target_m.last_input_states[source_idx] = signal;
|
||||||
|
if target_m.last_input_states.iter().all(|state| *state == PulseType::High) {
|
||||||
|
self.send_all_outputs(PulseType::Low, target, priority)
|
||||||
|
} else {
|
||||||
|
self.send_all_outputs(PulseType::High, target, priority)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn send_all_outputs(&mut self, signal: PulseType, from: &str, priority: usize) {
|
||||||
|
self.work_queue.push(Job {
|
||||||
|
signal,
|
||||||
|
targets: self.modules[from].outputs.iter().map(|op| op.to_owned()).collect(),
|
||||||
|
from: from.to_owned(),
|
||||||
|
priority: priority + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn run(&mut self) {
|
||||||
|
while let Some(job) = self.work_queue.pop() {
|
||||||
|
for target in job.targets {
|
||||||
|
self.send_pulse(job.signal, &target, &job.from, job.priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// the number of cycles it took until the target sends a low pulse, or None if the target node sent no low pulses but the job finished
|
||||||
|
fn time_to_state(&mut self, goal:&str, state: PulseType) -> Option<u64> {
|
||||||
|
while let Some(job) = self.work_queue.pop() {
|
||||||
|
if job.from == goal && job.signal == state {
|
||||||
|
return Some(self.count_high + self.count_low);
|
||||||
|
}
|
||||||
|
for target in job.targets {
|
||||||
|
self.send_pulse(job.signal, &target, &job.from, job.priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn reset(&mut self) {
|
||||||
|
for (_name, m) in &mut self.modules {
|
||||||
|
m.reset();
|
||||||
|
}
|
||||||
|
self.count_low = 0;
|
||||||
|
self.count_high = 0;
|
||||||
|
}
|
||||||
|
fn state_space(&self) -> u128 {
|
||||||
|
self.modules.values().map(|m| m.state_space()).product()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
const PROBLEM1_ITERATIONS: usize = 1000;
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut machine = Machine::from(input);
|
||||||
|
for _ in 0..PROBLEM1_ITERATIONS {
|
||||||
|
machine.press_button();
|
||||||
|
machine.run();
|
||||||
|
}
|
||||||
|
machine.count_low * machine.count_high
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u128 {
|
||||||
|
let mut machine = Machine::from(input);
|
||||||
|
println!("STATES: {}", machine.state_space());
|
||||||
|
// Find the rx module and look at its parent(s)
|
||||||
|
let rx = &machine.modules["rx"];
|
||||||
|
// my input has a single conjunction as parent, todo implement other possibilities
|
||||||
|
let con = &machine.modules[&rx.inputs[0]];
|
||||||
|
|
||||||
|
// for each input, find how long it takes for it to be High, so the conjunction sends a low to rx
|
||||||
|
let mut cycles: Vec<_> = Vec::new();
|
||||||
|
for input in con.inputs.clone() {
|
||||||
|
print!("searching distance to {}...", input);
|
||||||
|
machine.reset();
|
||||||
|
let mut button_count = 0;
|
||||||
|
loop {
|
||||||
|
machine.press_button();
|
||||||
|
button_count += 1;
|
||||||
|
if let Some(distance) = machine.time_to_state(&input, PulseType::High) {
|
||||||
|
println!("got {} pulses, {} button presses", distance, button_count);
|
||||||
|
cycles.push(button_count as u128);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cycles.iter().fold(1, |accum, cycle| lcm(accum, *cycle))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"broadcaster -> a
|
||||||
|
%a -> inv, con
|
||||||
|
&inv -> b
|
||||||
|
%b -> con
|
||||||
|
&con -> output";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 11687500);
|
||||||
|
}
|
||||||
|
}
|
465
21/Cargo.lock
generated
Normal file
465
21/Cargo.lock
generated
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"unicode-width",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"indicatif",
|
||||||
|
"polyfit-rs",
|
||||||
|
"primes",
|
||||||
|
"rayon",
|
||||||
|
"test-case",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.17.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"instant",
|
||||||
|
"number_prefix",
|
||||||
|
"portable-atomic",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.151"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra"
|
||||||
|
version = "0.31.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20bd243ab3dbb395b39ee730402d2e5405e448c75133ec49cc977762c4cba3d1"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"matrixmultiply",
|
||||||
|
"nalgebra-macros",
|
||||||
|
"num-complex",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"simba",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polyfit-rs"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab98d9704c7300e37472a6790a447eaf501d664a1889737faa53c26790d2b697"
|
||||||
|
dependencies = [
|
||||||
|
"nalgebra",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primes"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68a61082d8bceecd71a3870e9162002bb75f7ba9c7aa8b76227e887782fef9c8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.70"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "safe_arch"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simba"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f3fd720c48c53cace224ae62bef1bbff363a70c68c4802a78b5cc6159618176"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"num-complex",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
"wide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||||
|
dependencies = [
|
||||||
|
"test-case-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-core"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.42",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case-macros"
|
||||||
|
version = "3.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.42",
|
||||||
|
"test-case-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wide"
|
||||||
|
version = "0.7.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"safe_arch",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
13
21/Cargo.toml
Normal file
13
21/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "day21"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
indicatif = "0.17.7"
|
||||||
|
polyfit-rs = "0.2.1"
|
||||||
|
primes = "0.3.0"
|
||||||
|
rayon = "1.8.0"
|
||||||
|
test-case = "3.3.1"
|
131
21/input
Normal file
131
21/input
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
...................................................................................................................................
|
||||||
|
..............#...#........#...............#.#.......#....##...........#.#..#......#.....#.........#..##...........................
|
||||||
|
.#..##..##..#......#.#.#...##......###...##......#.#..#...................#.....#..........#..#................#...#..........#....
|
||||||
|
.....................#..#.......#.....##.........#.......................................#........#....#.#..........#.#......#.#...
|
||||||
|
......##...#.....#.......#...#..###..........#..........#......................#........#.............#.....#........#....#........
|
||||||
|
.................##.................#...#.........#................................#........#...........#............#........#....
|
||||||
|
..............#.#....#........##.....##..........#.............##.............#...#......#..##..........#.........#.....#...#..#...
|
||||||
|
..#....#.......#...##..#......#.........#.#..#....#.#..............#........#...#...#...............#.#.....#..#..##......#...#....
|
||||||
|
...#......##...##..#...#..........#...#..........#..............#...#..........#..#..#..#........#.#.#.#.#...........###...........
|
||||||
|
.#.#.#...#.#...##............................................#......................#...#......#......##.#.........................
|
||||||
|
.##.#.........#...#..................##...........#............#..................###...#...........#.................#....#.......
|
||||||
|
.....................#...#.#................#................#.#........................#...#...##....##....#.#...#.........#...#..
|
||||||
|
...#.......#...#.........................#.#..................#........##..........................#......##....##............#....
|
||||||
|
......................#.....................#...............#.......#.#...................#...............#...#........#.##......#.
|
||||||
|
............................#..........................#........#....#.##..#.......#.##..#...#.#..#...............#.#..#....#......
|
||||||
|
.......................................................#.#..#.#....#......................#............#....#..#.......#.........#.
|
||||||
|
.....##........#...............#.......#...............#.#..........##..#...................#................#..#...#.#....#...###.
|
||||||
|
....#.....................##................#.......#.......#...#.#...#...............#................#...............##..........
|
||||||
|
....#........#..#.......#.#.#........................#.#...........#.......#..#.........#....#.......#........#.#.#................
|
||||||
|
......###.....#..#...........#.....#..#..#........#......#.#........###.....##............#..#...........#.........................
|
||||||
|
.....#...........#...................#..#..........#..#...###.#.........#.##...............#..##..........#.........#..............
|
||||||
|
.#.........#....#............#.##..........................##.....#........#....#.............#.......#...#..............##.#......
|
||||||
|
.#..#...#.......#...#.......##.......#.#.............................#...#...#.#...........#...#.................#.........#.#.#...
|
||||||
|
...#....................#.....##..............#.................#.................#............#......#....#.......#.........#.....
|
||||||
|
.......#...#.............#.##...#.#...................#.....#..#........#................................#.............#..#...##...
|
||||||
|
...#.###..............#....#........................#......#...#.........#......#.#....................#........#...#...#.......#..
|
||||||
|
............#.#...#...........................#....###.###...#........#..#........#...................##.....###......#........#...
|
||||||
|
.....#...#................#.##..##..................#....#.........#............##...................##................#.....#.....
|
||||||
|
.#....#..............##...#..................#......#..........##.#....#......##.#...............#....##..............#....#.......
|
||||||
|
....#.#.##...........##.....#...........#.........#...#........#..#.......#......#................#.#...#....#...#.................
|
||||||
|
.......#...#...#...#..#.......#..........#..................#..#........#..#.#.....#.#.....................##......................
|
||||||
|
.....##.........#.......##...#.............#.##.#.#...#.##.#...#......#...#....#.......#..#.........#...........#.##.###.#.....#...
|
||||||
|
...................#.#.......................#.....#.#......#.....##...#.#....#..#..........#...........#..##....#...#.......#.#...
|
||||||
|
.....#..#..#.........#...#.#.........#...#.#...##...#......##........#...............#.......#................#.....#...#.#........
|
||||||
|
........#.....###.....................#.........#.........#.........#....##............#..##.............#.........#..#.......#....
|
||||||
|
.#.........#....##..##.................#...#................................#...#.....#.........#.......#............#....#......#.
|
||||||
|
..#.........#.......#..................#..#.#...#........#.#.......#...##.#........#..........#.#..........#..#.....#.........#....
|
||||||
|
..#...............#...................##.#.......#...#..........#....................##.........#.................#..#......##..#..
|
||||||
|
.#........#.......#............##...........##........#.......................#................#....................#...###......#.
|
||||||
|
........###..........#..............#.............#..#.#.#............##...............#........#...#........#...................#.
|
||||||
|
...#............................#...##.##........#......#..#...................#.#.....#...#.##...............#........#...#.......
|
||||||
|
..#...##....................#.....##......#.......#..........#......#.........#...#..............#..............#..................
|
||||||
|
.....#..#....................#....###.....#..#.............#...#....#................#.....#.....................#........#........
|
||||||
|
.....#.#...#.....#..............##............#....##.#....#.#........##...........#....#.........................#....#......##...
|
||||||
|
....#..#.....##...........#.#.#.#............#....#.....#.........#........................##.......#.#..............##...#........
|
||||||
|
...............#..............#................................#....#........#.......#.......##......#.#............#......#....#..
|
||||||
|
.#......#....##........#.............#..#.#.............#...#..#.........#.........#................#..................#...........
|
||||||
|
.........#..............#....#......#.....##......#............#....#.........#....#...................#....#.........#......#..#..
|
||||||
|
..............................#....#.#........#.#.....#..#.................#....#...#..........#............##.......#.#.#....#....
|
||||||
|
.#..................#....#..#.......#.##..............#...#.......#................#...............................................
|
||||||
|
.#..##.........................#.....###......#....#......#.....#............#.#......##......##......##....#..........##.....#....
|
||||||
|
..........................##.#.....#..........................................#.#..#....#..#..................#...........#........
|
||||||
|
..##.....#.......#....#.........#..........#....................#.........#........###........................#..........#.........
|
||||||
|
.#.#...............#..........#.......#.....#....##.#..#.##...............#...#...#.#......#.......#.......#.#.............#....##.
|
||||||
|
..................#...............##.........##..#........#..#..........#.....................#............................#.......
|
||||||
|
.....#................#...##.......##.........#.....#.#....#.#........#...#..#....#..............#..#....#....#....#...............
|
||||||
|
..##.#........#...............#.#..#...................##...#......#.#...#..#.....##.................##...#.#...................#..
|
||||||
|
...#...............#......#.....#.......#......#.........#...#......#...#..#....#..#......#.......#.......#...#.##.#...........##..
|
||||||
|
..............##..........##..........#..##...............#...........##..#..#..#.#.......#...#.............#......................
|
||||||
|
..........#.#........................#...#.#..#.#...##..#.#.#.#.......#....#.#.#..............#...#...#........###..##...........#.
|
||||||
|
......................#...#.#..##.....#....#.....###.#..#.....#..........#........#...........##...#..#...........##..#............
|
||||||
|
..................................####.#..............#.................#........#.#............##......#.#..........#.............
|
||||||
|
..................#..........#.............................#...........#..#..#......#................#.......##...##..#............
|
||||||
|
....................#...#....#.#.#.##......#................#.................#...........#....#..........#....#...##.###..........
|
||||||
|
.................#.......#...#............###.###..#.......#......#.......#..##......#.#.....#.....................#...............
|
||||||
|
.................................................................S.................................................................
|
||||||
|
.......##...........#.........###.......#....###.#.#....#.#....#....#........#.......#...#...#.#.........#...................#.....
|
||||||
|
.......#...............#............#...#..#.......##...#...#.#............#.............#......##..........#..............#.......
|
||||||
|
.......##.........#.....................##...#...#.................#...#.......#..####......#.....#..............#..##.............
|
||||||
|
........#..#.............#.#..##..............#...#.............#.....#......#...#.#.......#...............##...##.................
|
||||||
|
.........#..#...#..#.#..#..#...................##......#.....#..#...##..............#......#..........#.##...#.#.##.#..............
|
||||||
|
..............#..........#....................................#.........#.......#..#............##................#................
|
||||||
|
...........#...#.....#.........#....#..###....#...#.......#....#...............##.....#.......#.#.....#.#....#.#..#................
|
||||||
|
..#...................#........###..............#.#................#...###...##.............#.###......#...#...#.....#..........#..
|
||||||
|
.#.#............#.....#....###......................................#..........................#..................#................
|
||||||
|
................#..#...#................#.................##.................##..........#.......#...#.............#...............
|
||||||
|
.....##...........#....#.......#......#.#.....#.....#................#.....#.........#..#.................#........#........#......
|
||||||
|
.#.#.............#..#.#..............#.....#..#.#.....#..#......#.........#.....#.#......#..#.......#.#......##............#..#....
|
||||||
|
...................#............#....#...........#........#...................#.....##..............#........###...............#...
|
||||||
|
......###..........###.#.......#.................................................#..#.........#.#...#.........#.#..........#.#.....
|
||||||
|
..#.................#..#..#...#............#...#...#..##.#....##..#..................##.....#......#.........................#...#.
|
||||||
|
......................#.#.....#.#...#.......##...........#...#....#.............#.......#.............#.#.#.#......................
|
||||||
|
......#..#.#..........#....#.........#......#................#.........##.#....#.......#........#.#....................#......#....
|
||||||
|
..#....#....#...............#..........#...#.#......#...................#.........#..#.#......#..#.........................##....#.
|
||||||
|
..............#..........##......#.##...#...#.#................#...#..#.......#.#.....#........#...###..##.........#..##.........#.
|
||||||
|
........##...........................##.......#.#..................#........#.......#.#........#.........................##....#...
|
||||||
|
..#.#...........#.......................#.#.....#....#.....#...............####...#..............#...#....................#.#......
|
||||||
|
.......#...#....#.#.......#####...##.....#.#.......#....#.#........#................................#.##..........##....#..#.......
|
||||||
|
.........#.....#................##.#..................#.....................#...#................#.###.#.......###....#............
|
||||||
|
............#.#....#........#....#..................#...##.............#............#.......#.....#..#............##...............
|
||||||
|
....#.....#..........#..............#...#...#........##.....#.#....#....#........##.............................#.#.......#........
|
||||||
|
..#..#.#.......#.................#................................#......##.#..#..............#.#................#...#.#...........
|
||||||
|
.....#.....#........................#..#................#......#.......#.........###.#.#.........#.........#.....#.......#.........
|
||||||
|
.......#.......................................#.......#...............#.#..###...#.#.##.......#...........#.#.....#.##........#...
|
||||||
|
......##.........#.................................#.........#........##.#................#.#...#.............#...#..#........#....
|
||||||
|
......#.....#.#.......#...........#..#...........#.........#..#.#.......#.........##.....#....#.#...............#...#...#....#...#.
|
||||||
|
..#...#.#....#....#..............................#..#...#.......#.#.#..##..................#...............#......#..###..#.#......
|
||||||
|
.....#...#..#......#.....##...............#..........#..#.#####.......#...........#...................#.....#...#.........#..#.#...
|
||||||
|
.................#.......#..................#........#.......##...##.#....#.#.............#.............#....#....#................
|
||||||
|
...........####..#.....#....#.............#.......#...#..#.....#.............#...#....#.............#.#....#.#.............#.......
|
||||||
|
...#..#..#...#...#.#.....#.......................#....#..###.###.....#.........#....................#....#..#............#.....#...
|
||||||
|
.#.##....##...#......#.#.....#......................#.##..................#........#..#................#.#.......#.............#...
|
||||||
|
....##........#.......#..#..#............#..#..#..#...#......###..#..#..#...##...............................#.#........#......#.#.
|
||||||
|
..#..#..........#..........#..#.#.............#.....#...........#.##.......#............................#...........#...#..........
|
||||||
|
..#.#..#...#....#.....#.....#...#................#.....#.....#....#..#...#..#....#....#.....................#....#.................
|
||||||
|
.......#........#...#.............#.................#...#.#.....#.#....#..........#......................#..#............#.........
|
||||||
|
....#........#........#..............#.........................#...................#..........#.........#..#.........#.............
|
||||||
|
................#........#.........#............................#.#.............#..##.......#......#..#.................#......#.#.
|
||||||
|
..#.....#.........#...#..#.#.........................#...#...#...........#.....#...........#........#.............#.....#........#.
|
||||||
|
....#...#....#......#....#...#..#.................#...##.....#.#............................##...#...#..##.#.....................#.
|
||||||
|
...#..##...............#............................#...........#......#.#.....#............#........#.##................#.........
|
||||||
|
................#..#.............#..#..............#.#....#...#.#...#...#.#.##.............................#..#...........#........
|
||||||
|
.......#.......#....###............#.#.#.....................#.#..#....#.................##.....#.#..........##..#......#..........
|
||||||
|
.......#..........##.#.......#.##...#...............##.....#..........#................#............#...#........#........#........
|
||||||
|
...###.#.............................#.....#.#............##..#...#.....###..........#...............................#.....#....#..
|
||||||
|
....###.#...#.......#.##........#......#..##.#..........#.#...#.#....#.#..............##....#..#...#...........#...#.#..#..........
|
||||||
|
.....#....#.#..##.....#..........#..#...##..............#.......#.......#.............#..#.....#.......#.....#...##...###.......#..
|
||||||
|
........##...#...##..#.#.....#..........................#.#.#..#..#...................#....#....#..#....#..........#....##.........
|
||||||
|
...........##.....#...#........##..#........#....#..........#..#...............................................#......#.#.......#..
|
||||||
|
...#..##.........##....#...........##...#.......##.........#........#...........#........#.#.##...........#....#.....###...#.......
|
||||||
|
...#...#........................#..#...#..#........................................#......#..#...#.#....#...........#..............
|
||||||
|
...#..#.......#..#......##...................#...............#.....#.#.............#.....#.........#.#..##.....#..........#..#.....
|
||||||
|
....###....#..#.....#.#........#.##.......##...#...............#...............###.###.#...#............##.....#.................#.
|
||||||
|
....#...#.........#.##............#.....#........#............................................##.#......#..##.........#....###..#..
|
||||||
|
............#...##..#..........#........#.......#.#..........................#..#.#.......#......#.......................##.#..#...
|
||||||
|
....#......#....#....#..#.....#........#......#....#..#.#..............................#..#....#............#....#.................
|
||||||
|
..#.............#...#......#...#.....................#.##...............................##...#.......#........................#.##.
|
||||||
|
....#....##........#..............#....#.......#.....................................#........#........#...##..........#...........
|
||||||
|
....#.#.##..#..#....................#.................#.##.............#....#....#.............###...#...#..##....#.....##.........
|
||||||
|
.............#.......#...............#........#.#.....#..#.#................#.....#..##.....#....#...............#....#......#...#.
|
||||||
|
...................................................................................................................................
|
230
21/src/main.rs
Normal file
230
21/src/main.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
use core::panic;
|
||||||
|
use indicatif::{ProgressBar, ProgressStyle};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
type Position = (isize, isize);
|
||||||
|
type WrappedPosition = (usize, usize);
|
||||||
|
type Offset = (isize, isize);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct MapTile {
|
||||||
|
c: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapTile {
|
||||||
|
fn new(c: char) -> Self {
|
||||||
|
Self { c }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GardenMap {
|
||||||
|
map: Vec<Vec<MapTile>>,
|
||||||
|
start: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for GardenMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let map = lines
|
||||||
|
.map(|line| line.unwrap().chars().map(|c| MapTile::new(c)).collect())
|
||||||
|
.collect();
|
||||||
|
let mut new = Self { map, start: (0, 0) };
|
||||||
|
new.find_start();
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ADJACENCIES: [Offset; 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
|
|
||||||
|
impl GardenMap {
|
||||||
|
fn wrap_pos(&self, pos: &Position) -> WrappedPosition {
|
||||||
|
let (width, height) = (self.width() as isize, self.height() as isize);
|
||||||
|
(
|
||||||
|
if pos.0 < 0 {
|
||||||
|
(pos.0 + (-pos.0 / width + 1) * width) as usize % self.width()
|
||||||
|
} else {
|
||||||
|
pos.0 as usize % self.width()
|
||||||
|
},
|
||||||
|
if pos.1 < 0 {
|
||||||
|
(pos.1 + (-pos.1 / height + 1) * height) as usize % self.height()
|
||||||
|
} else {
|
||||||
|
pos.1 as usize % self.height()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn width(&self) -> usize {
|
||||||
|
self.map[0].len()
|
||||||
|
}
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
self.map.len()
|
||||||
|
}
|
||||||
|
fn at(&self, pos: &Position) -> &MapTile {
|
||||||
|
let pos = self.wrap_pos(pos);
|
||||||
|
&self.map[pos.1][pos.0]
|
||||||
|
}
|
||||||
|
// return the valid 'moves' from pos
|
||||||
|
fn adjacent_to(&self, pos: &Position) -> Vec<Position> {
|
||||||
|
ADJACENCIES
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ofs| self.offset_pos(pos, ofs))
|
||||||
|
.filter(|pos| self.at(pos).c != '#')
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn offset_pos(&self, pos: &Position, ofs: &Offset) -> Option<Position> {
|
||||||
|
let new_pos = (pos.0 as isize + ofs.0, pos.1 as isize + ofs.1);
|
||||||
|
return Some((new_pos.0, new_pos.1));
|
||||||
|
}
|
||||||
|
fn find_start(&mut self) {
|
||||||
|
for (y, row) in self.map.iter().enumerate() {
|
||||||
|
for (x, tile) in row.iter().enumerate() {
|
||||||
|
if tile.c == 'S' {
|
||||||
|
self.start = (x as isize, y as isize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("didn't find the start square!");
|
||||||
|
}
|
||||||
|
fn reachable_after(&self, from: &Position, n: usize) -> u64 {
|
||||||
|
let bar = ProgressBar::new(n as u64).with_style(
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
let mut visited_after: Vec<HashSet<Position>> = Vec::new();
|
||||||
|
visited_after.push(HashSet::from([*from]));
|
||||||
|
for i in 1..n+1 {
|
||||||
|
visited_after.push(
|
||||||
|
visited_after[i - 1]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|last| self.adjacent_to(last))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
bar.inc(1);
|
||||||
|
// if primes::is_prime(i as u64) {
|
||||||
|
// println!("count after {} steps: {}", i, visited_after[i].len());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
visited_after[n].len() as u64
|
||||||
|
}
|
||||||
|
fn reachable_count_after(&self, from: &Position, n: usize) -> u64 {
|
||||||
|
let dim = self.width() as f64;
|
||||||
|
let target_mod = (n % self.width()) as f64;
|
||||||
|
let x_values:Vec<f64> = vec![target_mod, target_mod + dim, target_mod + 2.*dim];
|
||||||
|
let y_values:Vec<f64> = x_values.iter().map(|n| self.reachable_after(from, *n as usize) as f64).collect();
|
||||||
|
|
||||||
|
let coeffs = polyfit_rs::polyfit_rs::polyfit(
|
||||||
|
&x_values,
|
||||||
|
&y_values,
|
||||||
|
2,
|
||||||
|
).unwrap();
|
||||||
|
println!("values: x: {:?} y: {:?}", x_values, y_values);
|
||||||
|
println!("coefficients: {:?}", coeffs);
|
||||||
|
|
||||||
|
let f_n= n as f64;
|
||||||
|
let result = coeffs[0] + coeffs[1] * f_n + coeffs[2] * f_n.powf(2.0);
|
||||||
|
|
||||||
|
result.round() as u64
|
||||||
|
}
|
||||||
|
fn draw_with_bounds(&self, from: &Position, to: &Position) {
|
||||||
|
for row in from.1..to.1 + 1 {
|
||||||
|
for col in from.0..to.0 + 1 {
|
||||||
|
print!("{}", self.at(&(col, row)).c);
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn print_visited(map: &GardenMap, visited: &Vec<Vec<bool>>) {
|
||||||
|
// for (y, row) in visited.iter().enumerate() {
|
||||||
|
// for (x, cell) in row.iter().enumerate() {
|
||||||
|
// print!("{}", if *cell { 'O' } else { map.at(&(x, y)).c });
|
||||||
|
// }
|
||||||
|
// println!();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1_impl<T: BufRead>(input: Lines<T>, n: usize) -> u64 {
|
||||||
|
let map = GardenMap::from(input);
|
||||||
|
// println!("map: {:?} start: {:?}", map.map, &map.start);
|
||||||
|
// map.draw_with_bounds(
|
||||||
|
// &(-(map.width() as isize), -(map.height() as isize)),
|
||||||
|
// &(map.width() as isize * 2 + 1, map.height() as isize * 2 + 1),
|
||||||
|
// );
|
||||||
|
map.reachable_count_after(&map.start, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, 26501365)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"...........
|
||||||
|
.....###.#.
|
||||||
|
.###.##..#.
|
||||||
|
..#.#...#..
|
||||||
|
....#.#....
|
||||||
|
.##..S####.
|
||||||
|
.##..#...#.
|
||||||
|
.......##..
|
||||||
|
.##.#.####.
|
||||||
|
.##..##.##.
|
||||||
|
...........";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), 6), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case(6, 16)]
|
||||||
|
#[test_case(10, 50)]
|
||||||
|
#[test_case(50, 1594)]
|
||||||
|
#[test_case(100, 6536)]
|
||||||
|
#[test_case(500, 167004)]
|
||||||
|
fn problem2_example(n: usize, expect: u64) {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), n), expect);
|
||||||
|
}
|
||||||
|
}
|
128
22/Cargo.lock
generated
Normal file
128
22/Cargo.lock
generated
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day22"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"ndarray",
|
||||||
|
"petgraph",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
11
22/Cargo.toml
Normal file
11
22/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day22"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
ndarray = "0.15.6"
|
||||||
|
petgraph = "0.6.4"
|
385
22/src/main.rs
Normal file
385
22/src/main.rs
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use petgraph::visit::{IntoNodeReferences, Walker};
|
||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::fmt::{Display, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Clone, Debug)]
|
||||||
|
struct Coord {
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
z: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Coord {
|
||||||
|
type Err = Box<dyn std::error::Error>;
|
||||||
|
fn from_str(value: &str) -> Result<Self, Self::Err> {
|
||||||
|
let (x, y, z) = value.split(',').next_tuple().unwrap();
|
||||||
|
Ok(Self {
|
||||||
|
x: x.parse()?,
|
||||||
|
y: y.parse()?,
|
||||||
|
z: z.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
|
struct BrickBlock {
|
||||||
|
c1: Coord,
|
||||||
|
c2: Coord,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for BrickBlock {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"[{},{},{} - {},{},{}]",
|
||||||
|
self.c1.x, self.c1.y, self.c1.z, self.c2.x, self.c2.y, self.c2.z
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrickBlock {
|
||||||
|
fn bottom_z_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.z, self.c2.z)
|
||||||
|
}
|
||||||
|
fn top_z_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.z, self.c2.z)
|
||||||
|
}
|
||||||
|
fn bottom_x_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.x, self.c2.x)
|
||||||
|
}
|
||||||
|
fn top_x_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.x, self.c2.x)
|
||||||
|
}
|
||||||
|
fn bottom_y_plane(&self) -> usize {
|
||||||
|
std::cmp::min(self.c1.y, self.c2.y)
|
||||||
|
}
|
||||||
|
fn top_y_plane(&self) -> usize {
|
||||||
|
std::cmp::max(self.c1.y, self.c2.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for BrickBlock {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let (c1, c2) = value.split_once('~').unwrap();
|
||||||
|
Self {
|
||||||
|
c1: c1.parse().unwrap(),
|
||||||
|
c2: c2.parse().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for BrickBlock {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(other.bottom_z_plane().cmp(&self.bottom_z_plane()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note this is a reversed ordering
|
||||||
|
impl Ord for BrickBlock {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.bottom_z_plane().cmp(&other.bottom_z_plane())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockMap = Array3<MapTile>;
|
||||||
|
type MapTile = Option<BrickBlock>;
|
||||||
|
|
||||||
|
struct BlockPile {
|
||||||
|
blocks: Vec<BrickBlock>,
|
||||||
|
block_map: Array3<MapTile>,
|
||||||
|
bounds: (usize, usize, usize),
|
||||||
|
graph: Graph<BrickBlock, (), Directed, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockPile {
|
||||||
|
fn remove_block(&mut self, block: &BrickBlock) {
|
||||||
|
// loop over the (inclusive) bounding coordinates and remove them all from the map
|
||||||
|
self.block_map
|
||||||
|
.slice_mut(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.bottom_z_plane()..block.top_z_plane() + 1,
|
||||||
|
])
|
||||||
|
.fill(None);
|
||||||
|
self.blocks.remove(self.blocks.iter().position(|b| b == block).unwrap());
|
||||||
|
}
|
||||||
|
fn add_block(&mut self, block: &BrickBlock) {
|
||||||
|
// loop over the (inclusive) bounding coordinates and remove them all from the map
|
||||||
|
self.block_map
|
||||||
|
.slice_mut(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.bottom_z_plane()..block.top_z_plane() + 1,
|
||||||
|
])
|
||||||
|
.fill(Some(block.to_owned()));
|
||||||
|
self.blocks.push(block.clone());
|
||||||
|
}
|
||||||
|
fn blocks_directly_above(&self, block: &BrickBlock) -> Vec<BrickBlock> {
|
||||||
|
// find the top plane of the block
|
||||||
|
// get the array range of all squares at z_plane + 1 within the bounds of x & y
|
||||||
|
// i think there is a built in way in ndarray to do this...
|
||||||
|
let directly_above = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
block.top_z_plane() + 1..std::cmp::min(block.top_z_plane() + 2, self.bounds.2)
|
||||||
|
]);
|
||||||
|
|
||||||
|
directly_above.iter().filter_map(|v| v.clone()).unique().collect()
|
||||||
|
}
|
||||||
|
fn supported_by(&self, block: &BrickBlock) -> usize {
|
||||||
|
let z_plane = std::cmp::min(block.c1.z, block.c2.z);
|
||||||
|
// get the slice of tiles below us
|
||||||
|
let directly_below = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
z_plane - 1..z_plane // the layer below
|
||||||
|
]);
|
||||||
|
directly_below.iter().filter_map(|v| v.clone()).unique().count()
|
||||||
|
}
|
||||||
|
fn blocks_above_will_move_if_we_are_gone(&mut self, block: &BrickBlock) -> bool {
|
||||||
|
self.blocks_directly_above(&block)
|
||||||
|
.iter()
|
||||||
|
.map(|b| self.supported_by(b))
|
||||||
|
.any(|b| b == 1) // block we support will move if we are their only support
|
||||||
|
}
|
||||||
|
fn blocks_supported_by_at_all(&self, block: &BrickBlock) -> Vec<BrickBlock> {
|
||||||
|
self.blocks_directly_above(&block).iter().map(|b| b.clone()).collect()
|
||||||
|
}
|
||||||
|
/// Find the plane of the first block directly below us
|
||||||
|
fn supporting_plane(&self, block: &BrickBlock) -> Option<usize> {
|
||||||
|
// find the bottom plane of ourselves
|
||||||
|
let z_plane = std::cmp::min(block.c1.z, block.c2.z);
|
||||||
|
// get the slice of tiles below us
|
||||||
|
let directly_below = self.block_map.slice(s![
|
||||||
|
block.bottom_x_plane()..block.top_x_plane() + 1,
|
||||||
|
block.bottom_y_plane()..block.top_y_plane() + 1,
|
||||||
|
1..z_plane // don't include our own plane
|
||||||
|
]);
|
||||||
|
// find the highest top z value of those
|
||||||
|
let block_below = directly_below
|
||||||
|
.indexed_iter()
|
||||||
|
.filter_map(|(idx, v)| if let Some(val) = v { Some((idx, val)) } else { None })
|
||||||
|
.max_by_key(|(_idx, v)| v.top_z_plane());
|
||||||
|
|
||||||
|
if let Some(block) = block_below {
|
||||||
|
Some(block.1.top_z_plane())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_blocks(&mut self) {
|
||||||
|
// VecDeque doesn't sort and Vec isn't convenient for pushback and popfront, so eh... use a heap.
|
||||||
|
let mut blocks_to_move = BinaryHeap::from(self.blocks.clone());
|
||||||
|
while let Some(mut block) = blocks_to_move.pop() {
|
||||||
|
let z_move = match self.supporting_plane(&block) {
|
||||||
|
Some(z) if z + 1 != block.bottom_z_plane() => block.bottom_z_plane() - (z + 1),
|
||||||
|
None if block.bottom_z_plane() != 1 => block.bottom_z_plane() - 1,
|
||||||
|
_ => {
|
||||||
|
continue;
|
||||||
|
} // we are in position already with nothing below us
|
||||||
|
};
|
||||||
|
self.remove_block(&block);
|
||||||
|
block.c1.z -= z_move;
|
||||||
|
block.c2.z -= z_move;
|
||||||
|
self.add_block(&block);
|
||||||
|
blocks_to_move.push(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn build_graph(&mut self) {
|
||||||
|
self.blocks.sort_by_key(|b| b.bottom_z_plane());
|
||||||
|
for b in 0..self.blocks.len() {
|
||||||
|
self.graph.add_node(self.blocks[b].clone());
|
||||||
|
}
|
||||||
|
for b in 0..self.blocks.len() {
|
||||||
|
let block = &self.blocks[b];
|
||||||
|
let depends_on_us = self.blocks_supported_by_at_all(block);
|
||||||
|
for dependent in depends_on_us {
|
||||||
|
self.graph.add_edge(
|
||||||
|
b.into(),
|
||||||
|
self.blocks.iter().position(|b| b == &dependent).unwrap().into(),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for BlockPile {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let blocks = lines.map(|line| BrickBlock::from(line.unwrap().as_str())).collect_vec();
|
||||||
|
let mut bounds = (0, 0, 0);
|
||||||
|
for block in &blocks {
|
||||||
|
bounds.0 = std::cmp::max(block.top_x_plane() + 1, bounds.0);
|
||||||
|
bounds.1 = std::cmp::max(block.top_y_plane() + 1, bounds.1);
|
||||||
|
bounds.2 = std::cmp::max(block.top_z_plane() + 1, bounds.2);
|
||||||
|
}
|
||||||
|
let mut new = BlockPile {
|
||||||
|
blocks: Vec::new(),
|
||||||
|
bounds,
|
||||||
|
block_map: BlockMap::from_elem(bounds, None),
|
||||||
|
graph: Graph::default(),
|
||||||
|
};
|
||||||
|
for block in blocks {
|
||||||
|
new.add_block(&block);
|
||||||
|
}
|
||||||
|
|
||||||
|
new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BlockPile {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for z in (0..self.bounds.2).rev() {
|
||||||
|
let z_plane = self.block_map.slice(s![.., .., z..z+1]);
|
||||||
|
if z_plane.iter().all(|b| b.is_none()) { continue };
|
||||||
|
for i in 0..self.bounds.0 {
|
||||||
|
// XZ view
|
||||||
|
let y = z_plane.slice(s![i..i + 1, .., ..]);
|
||||||
|
f.write_char(
|
||||||
|
match y.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) {
|
||||||
|
None => ' ',
|
||||||
|
Some(0) | Some(1) => '█',
|
||||||
|
Some(2) | Some(3) => '▓',
|
||||||
|
Some(4) | Some(5) => '▒',
|
||||||
|
Some(6) | Some(7) => '░',
|
||||||
|
_ => '░',
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
write!(f, " {} ", z)?;
|
||||||
|
for y in 0..self.bounds.1 {
|
||||||
|
let x = z_plane.slice(s![.., y..y + 1, ..]);
|
||||||
|
f.write_char(
|
||||||
|
match x.iter().enumerate().find_map(|(idx, val)| val.is_some().then(|| idx)) {
|
||||||
|
None => ' ',
|
||||||
|
Some(0) | Some(1) => '█',
|
||||||
|
Some(2) | Some(3) => '▓',
|
||||||
|
Some(4) | Some(5) => '▒',
|
||||||
|
Some(6) | Some(7) => '░',
|
||||||
|
_ => '░',
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
writeln!(f, " {}", z)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut pile = BlockPile::from(input);
|
||||||
|
println!("{}", pile);
|
||||||
|
println!("dropping blocks!");
|
||||||
|
pile.drop_blocks();
|
||||||
|
println!("{}", pile);
|
||||||
|
|
||||||
|
let blocks = pile.blocks.clone();
|
||||||
|
let removable: Vec<_> = blocks
|
||||||
|
.iter()
|
||||||
|
.filter(|b| !pile.blocks_above_will_move_if_we_are_gone(*b))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
removable.len() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut pile = BlockPile::from(input);
|
||||||
|
pile.drop_blocks();
|
||||||
|
pile.build_graph();
|
||||||
|
|
||||||
|
println!("{}", pile);
|
||||||
|
|
||||||
|
let mut accum = 0;
|
||||||
|
let fixed_nodes = pile
|
||||||
|
.graph
|
||||||
|
.node_references()
|
||||||
|
.filter(|(_idx, b)| b.bottom_z_plane() == 1)
|
||||||
|
.map(|(idx, _b)| idx)
|
||||||
|
.collect_vec();
|
||||||
|
for node in pile.graph.node_indices() {
|
||||||
|
// remove links to node's neighbors
|
||||||
|
let dependents = pile.graph.neighbors(node).collect_vec();
|
||||||
|
let edges = pile.graph.edges(node).map(|v| v.id()).collect_vec();
|
||||||
|
for edge in edges {
|
||||||
|
pile.graph.remove_edge(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find how many nodes are reachable from z = 1 - these won't move
|
||||||
|
let safe_blocks = fixed_nodes
|
||||||
|
.iter()
|
||||||
|
.flat_map(|origin| {
|
||||||
|
Bfs::new(&pile.graph, *origin)
|
||||||
|
.iter(&pile.graph)
|
||||||
|
.map(|n| pile.graph[n].clone())
|
||||||
|
})
|
||||||
|
.unique()
|
||||||
|
.count();
|
||||||
|
// we are looking for the nodes that *will* disintegrate
|
||||||
|
accum += pile.graph.node_count() - safe_blocks;
|
||||||
|
// put the graph back how it was
|
||||||
|
for neigh in dependents {
|
||||||
|
pile.graph.add_edge(node, neigh, ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accum as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"1,0,1~1,2,1
|
||||||
|
0,0,2~2,0,2
|
||||||
|
0,2,3~2,2,3
|
||||||
|
0,0,4~0,2,4
|
||||||
|
2,0,5~2,2,5
|
||||||
|
0,1,6~2,1,6
|
||||||
|
1,1,8~1,1,9";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 7);
|
||||||
|
}
|
||||||
|
}
|
128
23/Cargo.lock
generated
Normal file
128
23/Cargo.lock
generated
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"ndarray",
|
||||||
|
"petgraph",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
11
23/Cargo.toml
Normal file
11
23/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "day23"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
ndarray = "0.15.6"
|
||||||
|
petgraph = "0.6.4"
|
326
23/src/main.rs
Normal file
326
23/src/main.rs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use ndarray::prelude::*;
|
||||||
|
use petgraph::algo::all_simple_paths;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::fmt::{Debug, Display, Write};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Node {
|
||||||
|
c: char,
|
||||||
|
pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Node {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({},{})", self.pos.0, self.pos.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Node {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "({},{})", self.pos.0, self.pos.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position = (usize, usize);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ForestMap {
|
||||||
|
map: Array2<char>,
|
||||||
|
indexes: HashMap<Position, NodeIndex>,
|
||||||
|
graph: StableDiGraph<Node, u64>,
|
||||||
|
start: Position,
|
||||||
|
end: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ADJACENCIES: [(isize, isize); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
|
||||||
|
|
||||||
|
fn offset_pos(map: &Array2<char>, pos: Position, ofs: (isize, isize)) -> Option<Position> {
|
||||||
|
let new_pos = (pos.0 as isize + ofs.0, pos.1 as isize + ofs.1);
|
||||||
|
if new_pos.0 >= 0
|
||||||
|
&& new_pos.0 < map.len_of(Axis(0)) as isize
|
||||||
|
&& new_pos.1 >= 0
|
||||||
|
&& new_pos.1 < map.len_of(Axis(1)) as isize
|
||||||
|
{
|
||||||
|
Some((new_pos.0 as usize, new_pos.1 as usize))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjacent_to(map: &Array2<char>, pos: Position) -> Vec<Position> {
|
||||||
|
ADJACENCIES
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ofs| offset_pos(map, pos, *ofs))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for ForestMap {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let rows = lines.map(|line| line.unwrap().chars().collect_vec()).collect_vec();
|
||||||
|
let map = Array::from_shape_vec([rows[0].len(), rows.len()], rows.into_iter().flatten().collect_vec())
|
||||||
|
.unwrap()
|
||||||
|
.reversed_axes();
|
||||||
|
let start = (map.slice(s![.., 0]).iter().position(|c| *c == '.').unwrap(), 0);
|
||||||
|
let end = (
|
||||||
|
map.slice(s![.., map.len_of(Axis(1)) - 1])
|
||||||
|
.iter()
|
||||||
|
.position(|c| *c == '.')
|
||||||
|
.unwrap(),
|
||||||
|
map.len_of(Axis(1)) - 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut graph = StableGraph::default();
|
||||||
|
let mut indexes = HashMap::new();
|
||||||
|
for (pos, c) in map.indexed_iter() {
|
||||||
|
if *c != '#' {
|
||||||
|
indexes.insert(pos, graph.add_node(Node { c: *c, pos }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
map,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
graph,
|
||||||
|
indexes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ForestMap {
|
||||||
|
fn build_graph(&mut self) {
|
||||||
|
for (pos, c) in self.map.indexed_iter() {
|
||||||
|
match c {
|
||||||
|
'#' => continue,
|
||||||
|
'.' => {
|
||||||
|
adjacent_to(&self.map, pos).iter().for_each(|adj| {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[adj], 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
'^' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (0, -1)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'>' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (1, 0)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'v' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (0, 1)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'<' => {
|
||||||
|
if let Some(adj) = offset_pos(&self.map, pos, (-1, 0)) {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[&adj], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c => panic!("invalid map character {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_graph2(&mut self) {
|
||||||
|
for (pos, c) in self.map.indexed_iter() {
|
||||||
|
match c {
|
||||||
|
'#' => continue,
|
||||||
|
'.' | '^' | '>' | 'v' | '<' => {
|
||||||
|
adjacent_to(&self.map, pos).iter().for_each(|adj| {
|
||||||
|
if self.indexes.contains_key(&adj) {
|
||||||
|
self.graph.add_edge(self.indexes[&pos], self.indexes[adj], 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
c => panic!("invalid map character {}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cull nodes that don't change the topology of the graph and combine their cost
|
||||||
|
fn simplify_graph(&mut self) {
|
||||||
|
let mut idxs: Vec<_> = self
|
||||||
|
.graph
|
||||||
|
.neighbors(self.indexes[&self.start])
|
||||||
|
.map(|idx| (self.indexes[&self.start], idx))
|
||||||
|
.collect();
|
||||||
|
let mut visited = HashSet::from([self.indexes[&self.start]]);
|
||||||
|
while let Some((last_idx, cur_idx)) = idxs.pop() {
|
||||||
|
if !visited.insert(cur_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let our_neighbors = self.graph.neighbors(cur_idx).collect_vec();
|
||||||
|
|
||||||
|
// if we have exactly 2 neighbours, then one is where we came from, and we can shortcut this node with a
|
||||||
|
// pair of new edges A <-> C and break the existing 4 edges between them
|
||||||
|
if our_neighbors.len() == 2 {
|
||||||
|
let next_idx = our_neighbors.iter().find(|n| **n != last_idx).unwrap();
|
||||||
|
|
||||||
|
// remove the 4 existing edges
|
||||||
|
// careful of order of operations, as removing edges invalidates edge indexes
|
||||||
|
let forward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(cur_idx, *next_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let last_forward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(last_idx, cur_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let backward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(cur_idx, last_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let next_backward_cost = self
|
||||||
|
.graph
|
||||||
|
.remove_edge(self.graph.find_edge(*next_idx, cur_idx).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
let new_forward_cost = forward_cost + last_forward_cost;
|
||||||
|
let new_backward_cost = backward_cost + next_backward_cost;
|
||||||
|
|
||||||
|
// add edge from last to next
|
||||||
|
self.graph.add_edge(last_idx, *next_idx, new_forward_cost);
|
||||||
|
self.graph.add_edge(*next_idx, last_idx, new_backward_cost);
|
||||||
|
|
||||||
|
self.graph.remove_node(cur_idx);
|
||||||
|
// push the next node
|
||||||
|
idxs.push((last_idx, *next_idx));
|
||||||
|
} else {
|
||||||
|
// don't do anything about nodes with > 2 edges, just push them onto the stack, if there are some
|
||||||
|
idxs.append(
|
||||||
|
&mut self
|
||||||
|
.graph
|
||||||
|
.neighbors(cur_idx)
|
||||||
|
.into_iter()
|
||||||
|
.map(|next_idx| (cur_idx, next_idx))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for ForestMap {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for y in 0..self.map.len_of(Axis(1)) {
|
||||||
|
for c in self.map.index_axis(Axis(1), y) {
|
||||||
|
f.write_char(*c)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut map = ForestMap::from(input);
|
||||||
|
map.build_graph();
|
||||||
|
// println!("{:?}", map);
|
||||||
|
let paths = all_simple_paths::<Vec<_>, _>(&map.graph, map.indexes[&map.start], map.indexes[&map.end], 0, None)
|
||||||
|
.collect_vec();
|
||||||
|
let longest = paths.iter().max_by_key(|path| path.len()).unwrap();
|
||||||
|
|
||||||
|
longest.len() as u64 - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_path_length(map: &ForestMap, path: &Vec<NodeIndex>) -> u64 {
|
||||||
|
path.iter().tuple_windows().fold(0, |accum, (prev, next)| {
|
||||||
|
accum + map.graph[map.graph.find_edge(*prev, *next).unwrap()]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let mut map = ForestMap::from(input);
|
||||||
|
map.build_graph2();
|
||||||
|
map.simplify_graph();
|
||||||
|
|
||||||
|
let paths = all_simple_paths::<Vec<_>, _>(&map.graph, map.indexes[&map.start], map.indexes[&map.end], 0, None)
|
||||||
|
.collect_vec();
|
||||||
|
let longest = paths.iter().max_by_key(|path| calc_path_length(&map, &path)).unwrap();
|
||||||
|
longest.iter().tuple_windows().fold(0, |accum, (prev, next)| {
|
||||||
|
accum + map.graph[map.graph.find_edge(*prev, *next).unwrap()]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"#.#####################
|
||||||
|
#.......#########...###
|
||||||
|
#######.#########.#.###
|
||||||
|
###.....#.>.>.###.#.###
|
||||||
|
###v#####.#v#.###.#.###
|
||||||
|
###.>...#.#.#.....#...#
|
||||||
|
###v###.#.#.#########.#
|
||||||
|
###...#.#.#.......#...#
|
||||||
|
#####.#.#.#######.#.###
|
||||||
|
#.....#.#.#.......#...#
|
||||||
|
#.#####.#.#.#########v#
|
||||||
|
#.#...#...#...###...>.#
|
||||||
|
#.#.#v#######v###.###v#
|
||||||
|
#...#.>.#...>.>.#.###.#
|
||||||
|
#####v#.#.###v#.#.###.#
|
||||||
|
#.....#...#...#.#.#...#
|
||||||
|
#.#########.###.#.#.###
|
||||||
|
#...###...#...#...#.###
|
||||||
|
###.###.#.###v#####v###
|
||||||
|
#...#...#.#.>.>.#.>.###
|
||||||
|
#.###.###.#.###.#.#v###
|
||||||
|
#.....###...###...#...#
|
||||||
|
#####################.#";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 94);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 154);
|
||||||
|
}
|
||||||
|
}
|
134
24/Cargo.lock
generated
Normal file
134
24/Cargo.lock
generated
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day24"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"lazy-regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c"
|
||||||
|
dependencies = [
|
||||||
|
"lazy-regex-proc_macros",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-regex-proc_macros"
|
||||||
|
version = "3.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.71"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
10
24/Cargo.toml
Normal file
10
24/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "day24"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.12.0"
|
||||||
|
lazy-regex = "3.1.0"
|
24
24/cheat.py
Normal file
24
24/cheat.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from z3 import *
|
||||||
|
|
||||||
|
rx, ry, rz = Ints('rx ry rz')
|
||||||
|
rvx, rvy, rvz = Ints('rvx rvy rvz')
|
||||||
|
t0, t1, t2 = Ints('t0 t1 t2')
|
||||||
|
answer = Int('answer')
|
||||||
|
|
||||||
|
solve(
|
||||||
|
rx + t0 * rvx == 225415405941969 + t0 * 23,
|
||||||
|
ry + t0 * rvy == 400648127977931 + t0 * -204,
|
||||||
|
rz + t0 * rvz == 79201130433258 + t0 * 617,
|
||||||
|
|
||||||
|
rx + t1 * rvx == 353783687623292 + t1 * -80,
|
||||||
|
ry + t1 * rvy == 138575899489956 + t1 * 156,
|
||||||
|
rz + t1 * rvz == 318416438572569 + t1 * 21,
|
||||||
|
|
||||||
|
rx + t2 * rvx == 215751176267772 + t2 * -120,
|
||||||
|
ry + t2 * rvy == 376619563956940 + t2 * 126,
|
||||||
|
rz + t2 * rvz == 230133299986253 + t2 * -352,
|
||||||
|
|
||||||
|
answer == rx + ry + rz,
|
||||||
|
)
|
205
24/src/main.rs
Normal file
205
24/src/main.rs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
use itertools::Itertools;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::ops::Index;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Vec3 {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
z: f64,
|
||||||
|
}
|
||||||
|
impl Debug for Vec3 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}, {}, {}", self.x, self.y, self.z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Vec2 {
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
}
|
||||||
|
impl Debug for Vec2 {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}, {}", self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
|
||||||
|
struct Hailstone {
|
||||||
|
pos: Vec3,
|
||||||
|
vel: Vec3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hailstone {
|
||||||
|
fn xy_vel_angle(&self) -> f64 {
|
||||||
|
(self.vel.y / self.vel.x).atan()
|
||||||
|
}
|
||||||
|
fn xy_vel_abs(&self) -> f64 {
|
||||||
|
(self.vel.x.powi(2) + self.vel.y.powi(2)).sqrt()
|
||||||
|
}
|
||||||
|
fn xy_slope(&self) -> f64 {
|
||||||
|
self.vel.y / self.vel.x
|
||||||
|
}
|
||||||
|
fn y_crossing(&self) -> f64 {
|
||||||
|
self.pos.y - self.xy_slope() * self.pos.x
|
||||||
|
}
|
||||||
|
fn xy_poi(&self, other: &Hailstone) -> Option<Vec2> {
|
||||||
|
let our_slope = self.xy_slope();
|
||||||
|
let other_slope = other.xy_slope();
|
||||||
|
if our_slope == other_slope || our_slope * other_slope == -1. {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let our_yint = self.y_crossing();
|
||||||
|
let other_yint = other.y_crossing();
|
||||||
|
let ratio = (other_yint - our_yint) / (our_slope - other_slope);
|
||||||
|
Some(Vec2 {
|
||||||
|
x: ratio,
|
||||||
|
y: our_slope * ratio + our_yint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn xy_point_future(&self, point: &Vec2) -> bool {
|
||||||
|
// a point will be in the past if the difference between its 'new' position and its 'start' position has a
|
||||||
|
// different sign than the velocity for any component
|
||||||
|
let diffs = [point.x - self.pos.x, point.y - self.pos.y];
|
||||||
|
// for (diff, vel) in diffs.iter().zip([self.vel.x, self.vel.y].iter()) {
|
||||||
|
// println!(" diff: {:?} vel: {:?} mul: {:?}", diff, vel, diff * vel > 0.);
|
||||||
|
// }
|
||||||
|
diffs.iter().zip([self.vel.x, self.vel.y].iter()).any(|(diff, vel)| diff * vel > 0.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Hailstone {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
let (pos, vel) = value.split_once("@").unwrap();
|
||||||
|
let [px, py, pz] = pos.split(",").map(|s| s.trim().parse::<f64>().unwrap()).collect_vec()[..] else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
let [vx, vy, vz] = vel.split(",").map(|s| s.trim().parse::<f64>().unwrap()).collect_vec()[..] else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pos: Vec3 { x: px, y: py, z: pz },
|
||||||
|
vel: Vec3 { x: vx, y: vy, z: vz },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Hailstone {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?} @ {:?}", self.pos, self.vel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Hailstones {
|
||||||
|
stones: Vec<Hailstone>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hailstones {
|
||||||
|
fn count_xy_pois(&self, bounds: (f64, f64)) -> u64 {
|
||||||
|
assert!(bounds.0 < bounds.1);
|
||||||
|
let mut stones = self.stones.clone();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
while let Some(stone) = &stones.pop() {
|
||||||
|
for other in &stones {
|
||||||
|
let Some(poi) = stone.xy_poi(other) else { continue };
|
||||||
|
// println!("intersection: {:?} / {:?} @ {:?}", stone, other, poi);
|
||||||
|
if poi.x >= bounds.0 && poi.x <= bounds.1 && poi.y >= bounds.0 && poi.y <= bounds.1 && stone.xy_point_future(&poi) && other.xy_point_future(&poi) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Hailstones {
|
||||||
|
type Output = Hailstone;
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.stones[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Hailstones {
|
||||||
|
fn from(value: Lines<T>) -> Self {
|
||||||
|
let mut stones = Vec::new();
|
||||||
|
for line in value {
|
||||||
|
stones.push(Hailstone::from(line.unwrap().as_str()));
|
||||||
|
}
|
||||||
|
Hailstones { stones }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
problem1_impl(input, (200000000000000., 400000000000000.))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn problem1_impl<T: BufRead>(input: Lines<T>, bounds: (f64, f64)) -> u64 {
|
||||||
|
let stones = Hailstones::from(input);
|
||||||
|
|
||||||
|
stones.count_xy_pois(bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"19, 13, 30 @ -2, 1, -2
|
||||||
|
18, 19, 22 @ -1, -1, -2
|
||||||
|
20, 25, 34 @ -2, -2, -4
|
||||||
|
12, 31, 28 @ -1, -2, -1
|
||||||
|
20, 19, 15 @ 1, -5, -3";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1_impl(c.lines(), (7., 27.)), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 0);
|
||||||
|
}
|
||||||
|
}
|
266
25/Cargo.lock
generated
Normal file
266
25/Cargo.lock
generated
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"unicode-width",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day25"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"indicatif",
|
||||||
|
"itertools",
|
||||||
|
"petgraph",
|
||||||
|
"rayon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.17.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"instant",
|
||||||
|
"number_prefix",
|
||||||
|
"portable-atomic",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.151"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "number_prefix"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
12
25/Cargo.toml
Normal file
12
25/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "day25"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
indicatif = "0.17.7"
|
||||||
|
itertools = "0.12.0"
|
||||||
|
petgraph = "0.6.4"
|
||||||
|
rayon = "1.8.0"
|
171
25/src/main.rs
Normal file
171
25/src/main.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use indicatif::{ProgressBar, ProgressIterator, ProgressStyle};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use petgraph::algo::connected_components;
|
||||||
|
use petgraph::dot::Dot;
|
||||||
|
use petgraph::prelude::*;
|
||||||
|
use petgraph::visit::{depth_first_search, DfsEvent, IntoEdgeReferences, IntoNodeIdentifiers, IntoNodeReferences};
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Lines};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// BOILERPLATE
|
||||||
|
type InputIter = Lines<BufReader<File>>;
|
||||||
|
|
||||||
|
fn get_input() -> InputIter {
|
||||||
|
let f = File::open("input").unwrap();
|
||||||
|
let br = BufReader::new(f);
|
||||||
|
br.lines()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans1 = problem1(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 1 solution: {} [{}s]", ans1, duration.as_secs_f64());
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
let ans2 = problem2(get_input());
|
||||||
|
let duration = start.elapsed();
|
||||||
|
println!("Problem 2 solution: {} [{}s]", ans2, duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
|
||||||
|
// PARSE
|
||||||
|
|
||||||
|
struct Circuit {
|
||||||
|
graph: UnGraph<String, String>,
|
||||||
|
nodes: HashMap<String, Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Node {
|
||||||
|
targets: Vec<String>,
|
||||||
|
index: Option<NodeIndex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node {
|
||||||
|
fn with_index(mut self, index: NodeIndex) -> Self {
|
||||||
|
self.index = Some(index);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BufRead> From<Lines<T>> for Circuit {
|
||||||
|
fn from(lines: Lines<T>) -> Self {
|
||||||
|
let mut graph = UnGraph::default();
|
||||||
|
let mut nodes = HashMap::new();
|
||||||
|
for line in lines.map(|v| v.unwrap()) {
|
||||||
|
let (source, targets_s) = line.split_once(": ").unwrap();
|
||||||
|
let targets = targets_s.split_whitespace().map(|s| s.to_string()).collect_vec();
|
||||||
|
nodes.insert(
|
||||||
|
source.to_string(),
|
||||||
|
Node {
|
||||||
|
targets,
|
||||||
|
index: Some(graph.add_node(source.to_string())),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, node) in nodes.iter_mut() {
|
||||||
|
for target in &node.targets {
|
||||||
|
let target_idx = match graph.node_references().find(|n| n.1 == target).map(|n| n.0) {
|
||||||
|
Some(target) => target,
|
||||||
|
None => graph.add_node(target.to_string()),
|
||||||
|
};
|
||||||
|
graph.add_edge(node.index.unwrap(), target_idx, format!("{}-{}", name, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { graph, nodes }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Circuit {
|
||||||
|
// returns the set of nodes on each side
|
||||||
|
fn find_critical_edges(&self, removals: usize) -> (Vec<String>, Vec<String>) {
|
||||||
|
let bar = ProgressBar::new(self.graph.edge_references().combinations(removals).try_len().unwrap() as u64)
|
||||||
|
.with_style(
|
||||||
|
ProgressStyle::with_template(
|
||||||
|
"[{elapsed_precise}/{eta_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {per_sec}",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
// for set in self.graph.edge_references().combinations(removals).progress_with(bar) {
|
||||||
|
|
||||||
|
let set = [("zcp", "zjm"), ("rsg", "nsk"), ("jks", "rfg")]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|(src, dst)| {
|
||||||
|
self.graph.edge_references().filter(|e| self.graph[e.source()] == *src && self.graph[e.target()] == *dst || self.graph[e.target()] == *src && self.graph[e.source()] == *dst)
|
||||||
|
}).collect_vec();
|
||||||
|
let mut local_graph: StableUnGraph<_, _> = self.graph.clone().into();
|
||||||
|
for wire in &set {
|
||||||
|
local_graph.remove_edge(wire.id());
|
||||||
|
}
|
||||||
|
let local_graph = UnGraph::from(local_graph);
|
||||||
|
if connected_components(&local_graph) == 2 {
|
||||||
|
// each edge will have one leg in each component, so return the set of connected nodes
|
||||||
|
let mut left = Vec::new();
|
||||||
|
depth_first_search(&local_graph, Some(set[0].source()), |event| {
|
||||||
|
if let DfsEvent::Discover(n, t) = event {
|
||||||
|
left.push(local_graph[n].to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let mut right = Vec::new();
|
||||||
|
depth_first_search(&local_graph, Some(set[0].target()), |event| {
|
||||||
|
if let DfsEvent::Discover(n, t) = event {
|
||||||
|
right.push(local_graph[n].to_string());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (left, right);
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
panic!("no cutline found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 1 solution
|
||||||
|
|
||||||
|
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
let circuit = Circuit::from(input);
|
||||||
|
println!("{:?}", Dot::new(&circuit.graph));
|
||||||
|
let (left, right) = circuit.find_critical_edges(3);
|
||||||
|
(left.len() * right.len()) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROBLEM 2 solution
|
||||||
|
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const EXAMPLE: &str = &"jqt: rhn xhk nvd
|
||||||
|
rsh: frs pzl lsr
|
||||||
|
xhk: hfx
|
||||||
|
cmg: qnr nvd lhk bvb
|
||||||
|
rhn: xhk bvb hfx
|
||||||
|
bvb: xhk hfx
|
||||||
|
pzl: lsr hfx nvd
|
||||||
|
qnr: nvd
|
||||||
|
ntq: jqt hfx bvb xhk
|
||||||
|
nvd: lhk
|
||||||
|
lsr: lhk
|
||||||
|
rzs: qnr cmg lsr rsh
|
||||||
|
frs: qnr lhk lsr";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem1_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem1(c.lines()), 54);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn problem2_example() {
|
||||||
|
let c = Cursor::new(EXAMPLE);
|
||||||
|
assert_eq!(problem2(c.lines()), 0);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user