Compare commits

..

26 Commits

Author SHA1 Message Date
48c96ce7ea day24: cheat solution used for part 2 submission 2024-12-11 09:54:10 -08:00
342f4c1883 day25: problem 1 solution - cheated with dot 2023-12-24 22:33:20 -08:00
881d0b08ad day24: problem 1 solution 2023-12-23 22:54:21 -08:00
c1eb7761e3 day23: problem 2 solution 2023-12-23 02:54:07 -08:00
98456ed98d day23: problem 1 solution 2023-12-22 22:33:34 -08:00
d6d4c0d056 gitignore 2023-12-22 20:58:14 -08:00
3bb3b3d6b6 day22: cleanup & nice output 2023-12-22 04:19:58 -08:00
dd91259fe2 day22: problem 2 solution.
no help but annoyingly i misread the hint about low/high and didn't submit my *correct* answer for over an hour while I bug hunted!
2023-12-22 03:47:01 -08:00
8495969877 day22: problem 1 solution 2023-12-22 01:32:08 -08:00
190fc92842 day21: problem 2 solution
not proud of this one either, completely cheated and it does not get
exactly the correct error (it was off by one for my input), but the
quadratic solver on Wolfram Alpha was able to do it.
2023-12-21 03:17:11 -08:00
eb6c1f42cd day 21: problem 1 solution
another unsatisfying one where i needed a visual hint to grok what i
should be doing.

a bunch of graph building stuff that wasn't needed for the part 1
solution at all.
2023-12-21 00:34:08 -08:00
512b05f624 day20: problem 2 solution - needed a hint 2023-12-20 01:48:09 -08:00
877101f9a2 day20: problem 1 solution 2023-12-20 00:13:23 -08:00
cdfecf821c day19: refactoring and cleanup 2023-12-19 02:01:47 -08:00
2b921b5fb2 day19: problem 2 solution 2023-12-19 01:01:36 -08:00
a5dea64b32 day19: problem 1 solution 2023-12-18 22:06:03 -08:00
8200c1a8cf root: add .rustfmt.toml 2023-12-18 02:04:22 -08:00
8d178ddfc6 day18: formatting and cleanup 2023-12-18 02:03:48 -08:00
3bc073f9b8 day18: problem 2 solution 2023-12-18 01:54:31 -08:00
0a9fa8e32f day18: problem 1 solution 2023-12-17 23:04:56 -08:00
e65c17c8e6 day17: don't revisit the start position 2023-12-17 20:55:42 -08:00
3ee26cefe5 day17: super obvious code cleanups, more to do 2023-12-17 15:18:22 -08:00
9e37b2ce66 day17: add heatmap visualization of final path 2023-12-17 15:11:43 -08:00
d422c9b84e day17: problem 2 - an ugly mess but finally working 2023-12-17 05:57:30 -08:00
5efa9853ca day17: problem 1 solution - a messy one! 2023-12-17 04:38:35 -08:00
da25b73eca day16: use tail recursion unstead of passing mutable state 2023-12-16 11:07:39 -08:00
37 changed files with 6787 additions and 21 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
**/target
input

1
.rustfmt.toml Normal file
View File

@ -0,0 +1 @@
max_width = 120

View File

@ -41,12 +41,12 @@ enum FromDirection {
}
impl FromDirection {
fn mask(&self) -> u8 {
const fn mask(&self) -> u8 {
1 << *self as u8
}
// return the new pos for a ray that will be from the direction.
// a ray 'from' left 'goes' right
fn goes_pos(&self, pos: (i64, i64)) -> (i64, i64) {
const fn goes_pos(&self, pos: (i64, i64)) -> (i64, i64) {
match self {
Self::Left => (pos.0 + 1, pos.1),
Self::Right => (pos.0 - 1, pos.1),
@ -54,7 +54,7 @@ impl FromDirection {
Self::Below => (pos.0, pos.1 - 1),
}
}
fn reflect_ne(&self) -> Self {
const fn reflect_ne(&self) -> Self {
match self {
Self::Left => Self::Below,
Self::Right => Self::Above,
@ -62,7 +62,7 @@ impl FromDirection {
Self::Below => Self::Left,
}
}
fn opposite(&self) -> FromDirection {
const fn opposite(&self) -> FromDirection {
match self {
Self::Left => Self::Right,
Self::Right => Self::Left,
@ -70,7 +70,7 @@ impl FromDirection {
Self::Below => Self::Above,
}
}
fn reflect_se(&self) -> FromDirection {
const fn reflect_se(&self) -> FromDirection {
self.reflect_ne().opposite()
}
fn interact(&self, tile: char) -> Interaction {
@ -90,7 +90,7 @@ impl FromDirection {
Interaction::Two((FromDirection::Left, FromDirection::Right))
}
},
c => unimplemented!("invalid tile {}", c),
c => panic!("invalid tile {}", c),
}
}
}
@ -150,17 +150,15 @@ impl Contraption {
fn width(&self) -> i64 {
self.tiles[0].len() as i64
}
fn cast_ray<'a>(&'a mut self, pos: (i64, i64), dir: FromDirection) -> VisitState {
let mut state = self.empty_state();
self.cast_ray_inner(&mut state, pos, dir);
state
fn cast_ray(&self, pos: (i64, i64), dir: FromDirection) -> VisitState {
self.cast_ray_inner(self.empty_state(), pos, dir)
}
fn cast_ray_inner<'a>(
&'a mut self,
state: &'a mut VisitState,
fn cast_ray_inner(
&self,
mut state: VisitState,
pos: (i64, i64),
dir: FromDirection,
) {
) -> VisitState {
if pos.0 >= 0
&& pos.1 >= 0
&& pos.0 < self.width()
@ -169,11 +167,14 @@ impl Contraption {
{
match dir.interact(self.tiles[pos.1 as usize][pos.0 as usize]) {
Interaction::One(dir) => self.cast_ray_inner(state, dir.goes_pos(pos), dir),
Interaction::Two((dir1, dir2)) => {
self.cast_ray_inner(state, dir1.goes_pos(pos), dir1);
self.cast_ray_inner(state, dir2.goes_pos(pos), dir2);
Interaction::Two((dir1, dir2)) => self.cast_ray_inner(
self.cast_ray_inner(state, dir2.goes_pos(pos), dir2),
dir1.goes_pos(pos),
dir1,
),
}
};
} else {
state
}
}
fn empty_state(&self) -> VisitState {
@ -198,14 +199,14 @@ impl<T: BufRead> From<Lines<T>> for Contraption {
// PROBLEM 1 solution
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
let mut contraption = Contraption::from(input);
let contraption = Contraption::from(input);
contraption.cast_ray((0, 0), FromDirection::Left).score()
}
// PROBLEM 2 solution
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
let mut contraption = Contraption::from(input);
let contraption = Contraption::from(input);
let rows_max = (0..contraption.height()).fold(0, |max_tiles, y| {
std::cmp::max(

141
17/Cargo.lock generated Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,131 @@
...................................................................................................................................
..............#...#........#...............#.#.......#....##...........#.#..#......#.....#.........#..##...........................
.#..##..##..#......#.#.#...##......###...##......#.#..#...................#.....#..........#..#................#...#..........#....
.....................#..#.......#.....##.........#.......................................#........#....#.#..........#.#......#.#...
......##...#.....#.......#...#..###..........#..........#......................#........#.............#.....#........#....#........
.................##.................#...#.........#................................#........#...........#............#........#....
..............#.#....#........##.....##..........#.............##.............#...#......#..##..........#.........#.....#...#..#...
..#....#.......#...##..#......#.........#.#..#....#.#..............#........#...#...#...............#.#.....#..#..##......#...#....
...#......##...##..#...#..........#...#..........#..............#...#..........#..#..#..#........#.#.#.#.#...........###...........
.#.#.#...#.#...##............................................#......................#...#......#......##.#.........................
.##.#.........#...#..................##...........#............#..................###...#...........#.................#....#.......
.....................#...#.#................#................#.#........................#...#...##....##....#.#...#.........#...#..
...#.......#...#.........................#.#..................#........##..........................#......##....##............#....
......................#.....................#...............#.......#.#...................#...............#...#........#.##......#.
............................#..........................#........#....#.##..#.......#.##..#...#.#..#...............#.#..#....#......
.......................................................#.#..#.#....#......................#............#....#..#.......#.........#.
.....##........#...............#.......#...............#.#..........##..#...................#................#..#...#.#....#...###.
....#.....................##................#.......#.......#...#.#...#...............#................#...............##..........
....#........#..#.......#.#.#........................#.#...........#.......#..#.........#....#.......#........#.#.#................
......###.....#..#...........#.....#..#..#........#......#.#........###.....##............#..#...........#.........................
.....#...........#...................#..#..........#..#...###.#.........#.##...............#..##..........#.........#..............
.#.........#....#............#.##..........................##.....#........#....#.............#.......#...#..............##.#......
.#..#...#.......#...#.......##.......#.#.............................#...#...#.#...........#...#.................#.........#.#.#...
...#....................#.....##..............#.................#.................#............#......#....#.......#.........#.....
.......#...#.............#.##...#.#...................#.....#..#........#................................#.............#..#...##...
...#.###..............#....#........................#......#...#.........#......#.#....................#........#...#...#.......#..
............#.#...#...........................#....###.###...#........#..#........#...................##.....###......#........#...
.....#...#................#.##..##..................#....#.........#............##...................##................#.....#.....
.#....#..............##...#..................#......#..........##.#....#......##.#...............#....##..............#....#.......
....#.#.##...........##.....#...........#.........#...#........#..#.......#......#................#.#...#....#...#.................
.......#...#...#...#..#.......#..........#..................#..#........#..#.#.....#.#.....................##......................
.....##.........#.......##...#.............#.##.#.#...#.##.#...#......#...#....#.......#..#.........#...........#.##.###.#.....#...
...................#.#.......................#.....#.#......#.....##...#.#....#..#..........#...........#..##....#...#.......#.#...
.....#..#..#.........#...#.#.........#...#.#...##...#......##........#...............#.......#................#.....#...#.#........
........#.....###.....................#.........#.........#.........#....##............#..##.............#.........#..#.......#....
.#.........#....##..##.................#...#................................#...#.....#.........#.......#............#....#......#.
..#.........#.......#..................#..#.#...#........#.#.......#...##.#........#..........#.#..........#..#.....#.........#....
..#...............#...................##.#.......#...#..........#....................##.........#.................#..#......##..#..
.#........#.......#............##...........##........#.......................#................#....................#...###......#.
........###..........#..............#.............#..#.#.#............##...............#........#...#........#...................#.
...#............................#...##.##........#......#..#...................#.#.....#...#.##...............#........#...#.......
..#...##....................#.....##......#.......#..........#......#.........#...#..............#..............#..................
.....#..#....................#....###.....#..#.............#...#....#................#.....#.....................#........#........
.....#.#...#.....#..............##............#....##.#....#.#........##...........#....#.........................#....#......##...
....#..#.....##...........#.#.#.#............#....#.....#.........#........................##.......#.#..............##...#........
...............#..............#................................#....#........#.......#.......##......#.#............#......#....#..
.#......#....##........#.............#..#.#.............#...#..#.........#.........#................#..................#...........
.........#..............#....#......#.....##......#............#....#.........#....#...................#....#.........#......#..#..
..............................#....#.#........#.#.....#..#.................#....#...#..........#............##.......#.#.#....#....
.#..................#....#..#.......#.##..............#...#.......#................#...............................................
.#..##.........................#.....###......#....#......#.....#............#.#......##......##......##....#..........##.....#....
..........................##.#.....#..........................................#.#..#....#..#..................#...........#........
..##.....#.......#....#.........#..........#....................#.........#........###........................#..........#.........
.#.#...............#..........#.......#.....#....##.#..#.##...............#...#...#.#......#.......#.......#.#.............#....##.
..................#...............##.........##..#........#..#..........#.....................#............................#.......
.....#................#...##.......##.........#.....#.#....#.#........#...#..#....#..............#..#....#....#....#...............
..##.#........#...............#.#..#...................##...#......#.#...#..#.....##.................##...#.#...................#..
...#...............#......#.....#.......#......#.........#...#......#...#..#....#..#......#.......#.......#...#.##.#...........##..
..............##..........##..........#..##...............#...........##..#..#..#.#.......#...#.............#......................
..........#.#........................#...#.#..#.#...##..#.#.#.#.......#....#.#.#..............#...#...#........###..##...........#.
......................#...#.#..##.....#....#.....###.#..#.....#..........#........#...........##...#..#...........##..#............
..................................####.#..............#.................#........#.#............##......#.#..........#.............
..................#..........#.............................#...........#..#..#......#................#.......##...##..#............
....................#...#....#.#.#.##......#................#.................#...........#....#..........#....#...##.###..........
.................#.......#...#............###.###..#.......#......#.......#..##......#.#.....#.....................#...............
.................................................................S.................................................................
.......##...........#.........###.......#....###.#.#....#.#....#....#........#.......#...#...#.#.........#...................#.....
.......#...............#............#...#..#.......##...#...#.#............#.............#......##..........#..............#.......
.......##.........#.....................##...#...#.................#...#.......#..####......#.....#..............#..##.............
........#..#.............#.#..##..............#...#.............#.....#......#...#.#.......#...............##...##.................
.........#..#...#..#.#..#..#...................##......#.....#..#...##..............#......#..........#.##...#.#.##.#..............
..............#..........#....................................#.........#.......#..#............##................#................
...........#...#.....#.........#....#..###....#...#.......#....#...............##.....#.......#.#.....#.#....#.#..#................
..#...................#........###..............#.#................#...###...##.............#.###......#...#...#.....#..........#..
.#.#............#.....#....###......................................#..........................#..................#................
................#..#...#................#.................##.................##..........#.......#...#.............#...............
.....##...........#....#.......#......#.#.....#.....#................#.....#.........#..#.................#........#........#......
.#.#.............#..#.#..............#.....#..#.#.....#..#......#.........#.....#.#......#..#.......#.#......##............#..#....
...................#............#....#...........#........#...................#.....##..............#........###...............#...
......###..........###.#.......#.................................................#..#.........#.#...#.........#.#..........#.#.....
..#.................#..#..#...#............#...#...#..##.#....##..#..................##.....#......#.........................#...#.
......................#.#.....#.#...#.......##...........#...#....#.............#.......#.............#.#.#.#......................
......#..#.#..........#....#.........#......#................#.........##.#....#.......#........#.#....................#......#....
..#....#....#...............#..........#...#.#......#...................#.........#..#.#......#..#.........................##....#.
..............#..........##......#.##...#...#.#................#...#..#.......#.#.....#........#...###..##.........#..##.........#.
........##...........................##.......#.#..................#........#.......#.#........#.........................##....#...
..#.#...........#.......................#.#.....#....#.....#...............####...#..............#...#....................#.#......
.......#...#....#.#.......#####...##.....#.#.......#....#.#........#................................#.##..........##....#..#.......
.........#.....#................##.#..................#.....................#...#................#.###.#.......###....#............
............#.#....#........#....#..................#...##.............#............#.......#.....#..#............##...............
....#.....#..........#..............#...#...#........##.....#.#....#....#........##.............................#.#.......#........
..#..#.#.......#.................#................................#......##.#..#..............#.#................#...#.#...........
.....#.....#........................#..#................#......#.......#.........###.#.#.........#.........#.....#.......#.........
.......#.......................................#.......#...............#.#..###...#.#.##.......#...........#.#.....#.##........#...
......##.........#.................................#.........#........##.#................#.#...#.............#...#..#........#....
......#.....#.#.......#...........#..#...........#.........#..#.#.......#.........##.....#....#.#...............#...#...#....#...#.
..#...#.#....#....#..............................#..#...#.......#.#.#..##..................#...............#......#..###..#.#......
.....#...#..#......#.....##...............#..........#..#.#####.......#...........#...................#.....#...#.........#..#.#...
.................#.......#..................#........#.......##...##.#....#.#.............#.............#....#....#................
...........####..#.....#....#.............#.......#...#..#.....#.............#...#....#.............#.#....#.#.............#.......
...#..#..#...#...#.#.....#.......................#....#..###.###.....#.........#....................#....#..#............#.....#...
.#.##....##...#......#.#.....#......................#.##..................#........#..#................#.#.......#.............#...
....##........#.......#..#..#............#..#..#..#...#......###..#..#..#...##...............................#.#........#......#.#.
..#..#..........#..........#..#.#.............#.....#...........#.##.......#............................#...........#...#..........
..#.#..#...#....#.....#.....#...#................#.....#.....#....#..#...#..#....#....#.....................#....#.................
.......#........#...#.............#.................#...#.#.....#.#....#..........#......................#..#............#.........
....#........#........#..............#.........................#...................#..........#.........#..#.........#.............
................#........#.........#............................#.#.............#..##.......#......#..#.................#......#.#.
..#.....#.........#...#..#.#.........................#...#...#...........#.....#...........#........#.............#.....#........#.
....#...#....#......#....#...#..#.................#...##.....#.#............................##...#...#..##.#.....................#.
...#..##...............#............................#...........#......#.#.....#............#........#.##................#.........
................#..#.............#..#..............#.#....#...#.#...#...#.#.##.............................#..#...........#........
.......#.......#....###............#.#.#.....................#.#..#....#.................##.....#.#..........##..#......#..........
.......#..........##.#.......#.##...#...............##.....#..........#................#............#...#........#........#........
...###.#.............................#.....#.#............##..#...#.....###..........#...............................#.....#....#..
....###.#...#.......#.##........#......#..##.#..........#.#...#.#....#.#..............##....#..#...#...........#...#.#..#..........
.....#....#.#..##.....#..........#..#...##..............#.......#.......#.............#..#.....#.......#.....#...##...###.......#..
........##...#...##..#.#.....#..........................#.#.#..#..#...................#....#....#..#....#..........#....##.........
...........##.....#...#........##..#........#....#..........#..#...............................................#......#.#.......#..
...#..##.........##....#...........##...#.......##.........#........#...........#........#.#.##...........#....#.....###...#.......
...#...#........................#..#...#..#........................................#......#..#...#.#....#...........#..............
...#..#.......#..#......##...................#...............#.....#.#.............#.....#.........#.#..##.....#..........#..#.....
....###....#..#.....#.#........#.##.......##...#...............#...............###.###.#...#............##.....#.................#.
....#...#.........#.##............#.....#........#............................................##.#......#..##.........#....###..#..
............#...##..#..........#........#.......#.#..........................#..#.#.......#......#.......................##.#..#...
....#......#....#....#..#.....#........#......#....#..#.#..............................#..#....#............#....#.................
..#.............#...#......#...#.....................#.##...............................##...#.......#........................#.##.
....#....##........#..............#....#.......#.....................................#........#........#...##..........#...........
....#.#.##..#..#....................#.................#.##.............#....#....#.............###...#...#..##....#.....##.........
.............#.......#...............#........#.#.....#..#.#................#.....#..##.....#....#...............#....#......#...#.
...................................................................................................................................

230
21/src/main.rs Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}
}