From 33275b39189df2f3f278e2565c6c8bd0b3bb4d5d Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Mon, 8 Dec 2025 22:17:10 -0800 Subject: [PATCH] day9: part1 and bruteforce part 2 (some cleanups and clippies) --- .aoc_tiles/tiles/2025/09.png | Bin 0 -> 7249 bytes README.md | 5 +- src/day8.rs | 15 ++-- src/day9.rs | 141 +++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + utils/grid/lib.rs | 19 ++++- 6 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 .aoc_tiles/tiles/2025/09.png create mode 100644 src/day9.rs diff --git a/.aoc_tiles/tiles/2025/09.png b/.aoc_tiles/tiles/2025/09.png new file mode 100644 index 0000000000000000000000000000000000000000..32e6986d22dd1f079cb16198a76f164abcc1e507 GIT binary patch literal 7249 zcmV-X9IoSuP)=4-zQ0x7UEN*1cRERTLiRuwNC;a%Kt*sH5M@RfM`p%RS>_$}iyl2^&U0{P&YAHY z@jSmcobf3$3OrEYDe9ms0?HOh2w)(DK=!@U>F)HtSJnGaSgBN3S66j9Nr&+J)VX!5 ze)oUxFSqXUzyE^T_x=?m3ZKuH@VzLC-s8QCdErT6oo=-}-FScZ!7=f~vre~Ko>sgY z-aAC{CL*jUXYD=S3E9`*D3`aj!qE1U&_?X;S003~_thHY~!ObfO6Isucq@sCa3yUBKECPwd z0D{N_M4M6Y#Fn;0JHj4^Ao^%lL6|DFOac~5V6jAuszFwfcFuCw?MwEnCkY$}0LU`) z5KTIoRV>dcN;)rz3A2|jDOTQ?!t$Ft%-??sAV_X1Ouz3*krV|0h@|L@6&pGZe5d0RUpT!Z3G*I=@^bQv@BBp)02V0J)F;mdqLPdv5LhFQr81mO_7NaUMQEtf2edIUxn{|9x`5?t>nHA=f zdk8EdlA`HLpOTvjsdQyQMOQ6vkJ0p*}WRbF}JQ!3;zDL1bAVIwCESFAS!)DMFoaoRJzGzdhNB>s;jGE7;bEAeE_j21n zvJyBJ@wur)iBbyyG-K69N>u;=Ko9_e^kvml0`$}1ECEbKRZ+l#zTs=9=_wL*8UVm@ z{!st1kHc=3;XHp{?X3CvYc}Cn*nIJu{&QbKu&7||R*A+y&!e0Bkbd4OZ&#D$?B^k; z#rWVeikwo`r*ZR|mObeVV2s4Hw6p^U4y2`}{pBxz*|u$)*X!N0XHP{%1tS}mu;{F? z7@>X>IIhSll<7066!XPzn?C+i+o8XQeJ+j%^2C%@6$z?$r~m0UcLZ(y1Rfa+uYa(+ z=j5mTXTETCHn}=(44poJ1-$B63#kkunL<;x*mmit^X5grxx-d}+}+-wo4X?VQQW+{ zZihvgMIV0nAtU|87henpgRi~z+Qo|(>+0&>dh4wV7cRW|>Z^=wF@;6%`b1JxL>qO6 zJr0@PNc|bG_1hZH6F3&I4GdlVf$lp#jg6sDh)VhFv(G9kD|2#k=-GI!ywhKB002+VZRLz& z)|}CAKLQ)|4+_C|qzp@>(YH@^Rb~HdGXQ`wcn1KuTCXJK`E*eBO7$jp+mBSbM5znA zYy=j8B~qzjM!?(=9<~4gBuZ`2+DGQ``FsF^^kqw6u|!w0(9v?0OecruB9UnO_U*N` zwV!|f`MP!M7`zUL!)P?pQ^?xO$;s*I>7f$ijIkgX))ZA5s#Z`b-v0KW!{Yy`hyVat zT2@-cG6)vQ^v3jg4>2D>5E0t@5zQ$D04NJ9VMNBrIMr1J0FbEDB13a*Ul5 z17)u=e-4buy`49xOJY=o1-t+NUDZRzhkm6jtRM&+3;IN;n#^#=UV^aSsEPPo_U1YO zz=rn@QIo!xUV14jD{I@fZLGY$U`RZw;)27Lo>QMu%kI6WKFeRTS)$ZZHvj+v zmTp-_E~7w>#`B7tGHPuQ5=-z%C}bOuW#*A7J{Qvl{z$bI4FZc`0bkf<_4T)TI~%cJ z(z-(iuSljaKD04t>vxQvfnq+lG$RK9;BIShw>1C&AXo$=@`%sHus3>LN~Kc0`|i7^ zPoK8i?Ik58005K81OO;4EyXabyStmrcJScAg9i_4G#aQ&s2wcNk;JXb`xt*$gW$ER`EqZp0%Y%h}J# z{UQosw_Q~{4;CYMGu-`VaKPj(vZN&KY*u2G1M> z5CjMU5{XqsRWie!*QkG}H{$mS;w6!4s+urfkz8e3xexO>bDrI4% z>vlbvqMEfJVCxUq`oU;Pz468y>(;H?zJ2>wUwuWUoH})?yu6(Lv~}y&z5Vvv)z#HF zO};XjED#8gzcVs2o_Xe(Pd@pCK2HRsuqLdQb(Ifl%I>2kh9ri5{9(L#8JH|pWvuuW zjK~nRo}Q>Fu0l-(p57Kq{datLB`Te9<*xxj3|~Hm=rXBQ=#bNf`P~2jJQQ%;IIo}o z2qY2*?E{LOQblfA_jh|4y%Y??&p!LCOeR~uemy0uXhe@Amo8oU=Rf~>*REZyt*v=^ zd7C$H?(6H@zkfd?n|LB?S&XWgs=9K@-4%ZmZH&BhBykQXlvkE!BKPv?5X+TfxiaKp z?#a+Ww^vuSlH6l8uKYDUkG1w2YSF=Q<2)Afs|x38=PdUR^=;m=^}>Y1d+f2_|Ni%8v-$Ah!ykO`0i(MD06>i&{U?V>97v#b4NIO- zWY2;mQY_&04R+aXT=1DYCxDm282^h3Hoi%J(JKop)0eEJ=ZQ7OB6&-H`)0JTNI2WC z_n!JJ7H`63Uh~(z3Ew-$dQQ;iJuz16#lzMqKE9bMyc^y-G`aRBBCL^h6jUuupCQ$o z5S>wsDq)F?T=vAn0X!6l_&p)JIcOgU4)s!Nq~mI>M4cu#6(ZUUM3XK;Rj@<~ixE5$ z#=`+D7znxT0oy>pZuSneV*vrhh{fw^zvgMb#(gi{-sU|l)0zZ$xj~MlCjGxiu&_`R zg%PhW|oTAME?T3{|~MKXnI=6qE_rI=b& zqXCv6umlmKYN;+mm0Jn`APC$y(CO-EbhKQJo>lSZjf)9xU21qf>8b)kg{9Q!G-Zp` zC5vH6oJD5_Wa&Aw^c;QFO6#?Aw#IXKI8Jji5X)LvD%Vv$s4A*r?4oc3f?!2fp(3j= zW5L6=#`Crt7w~XU5HBB0Wb4vre5s%+AV^plbC#sddpNFhEeBwUG-JUk{p=;?i{Cg~ z8+hIo%UV_8T>boqqxT&7LnK2p7CxdcU)*=*3r}wgPhLKlu-0WPBBY3_08e3w5LwQO z^@`lGgo#H{$`mtJ{8Bk%*1-9%V|5i2SgnObV#A`JDGMu;Qyx^E_xSVnria>lTxYzaouL5 z+VsLFwL}^xRTp z6%SrI>N9s~iYj%bi-<@#=om8B9sxXBH`cZ>NJ&)z4q?G!N#3Ks9amM|DFLd^dHC7R z!#m@SZ{(&Tb!j#0r6fX`KPPA(a5dM(%^4at57m5?y?U$V+!s_W_niC`08sSvSEy_O zTfe*erc{?XboF~xPD$9~Oq;#5{onrs2qJ6wQ>ZZ?xMDgk15QbSR8L!cx3SO0X~_rPyiB%kyC0mYxQhRyu%Lgqxz5|)9`So%L?+W4wZ&EPjGXv){sc68rrcQI zH+OJn^Z9)C=DLElTZ4|F;hS~7!LGPZj`-YzmyQ)Yv4sfv0R&mjeL)u`A4!3fR~3jB z7K);pvL!;Nfdm%ubX*&1stY-701#4bx~^oQrdZg5IHJu^7teRKux$H?m0D?9c62%` zy#4JxC--4NKb7J$ciNjS>dUH)OV=_^{Bb~CTFosivX&jUuQ+Zq58<>O`aAi<-gI$P z*# zfx~}I*%DXlmFP}Omd>}c2|9+lkMCjK0kq$&BM6YS{3)J~LbHk`N?ojxRuWs6zoe4O zD+oe)NB(_DR%QMiK~liO!GZ5~(^WN6l)>)KZ$D-oL&SnusYPeZicXiNnRq^7@X|4k zedXciIl%u=7#Ohi57r$M^gzul zmi|&CQ}VeNkAyrux4H8ST{+3WFpT(yB$Cp)LM4?f-UN^sub9p%R%iq*F$8V>LpSTW z^Vn}((9gaPQR#R-QLu4(7h6NmB zq#^{3rIvs9!Lh_7HAdb^^!yn$DYtCxEG|DnJ(&qBX?G%#NUAD1N4q%v}4dOhAxC zV+h&JRDyr7ljp7Kg4w2}Pnv7LrR$PW%OW|iIp&?RNCbPRvc^3ZiYcusKo^!6)d+eD zJ;F&`2vQ*cK%&snh2^sJhuy;xep5?*`C?_x%;B4tyaVkar&THu!6J!Bu8?TbWf{3> z_DqS2-2;pjB7`N5S1fSEJr{(jt|~D4RVeIVQ&7MK1j6HIqJbWk?at0g>(%smD`Vd= znogz9tbR-oW6Y9_4!IKxapRuz$6cT*FiKebYLEnhWBez2D2m4QZD#=bNm!J%w#J&Y zIm?Bf4oU(b2!dfoL>D@E#y#hWyF*ogE-Xk$oAGz(zQam==Yk(#u>_2^77O}qH)_&p zu>~gv1Qv;@{we@~fY%e9NZ?q{$xn;cy*w(uym0vX zTBK=NJl9qjFLAo0nwpx%QjEI~3m1-TG>-^N=rBkmkz%1(UbSPI;d2xw;&XR=^HJX8 zFYw=dWWd{f(^~sY-iFtC=BK`#u;IN!O`AsrU!cb*OTj*4a(PFDh4EY6rhsS+{-Iu; ztU}i^ID&SBoVNBue>W|AN>e24z$$@7h8uoxHrEPraSl3$;_k+zZ0k-U?})I%F7};} zSdeNnScS#PD)d|i_kt=G3iN)z-`;f5F!upfPD!k2%@l}8*wb;{apOFB$V{RZuoS%W z>+iWUq;l&{A}>u?ZaaZv{GEyA>Di7Jrb})tR>o%$xPga*9LJ+6_y)VWkM9x770R4a zb#@`5Nf#^BFd~Ow5rJcPI2iFbLc@c8OP9Z|mG1o~6XN{d+S-o${nnjC z-cd6(cb|X{C`goAnIVf0tK3v5$lci^d_JGMhnIg91w+OCd{~9LJI8e|rjS4_tBU8v9g|TwckW!WcqvQ=RRKy^B&%Z(A*vX!q&u$NFEK-!c~UFPl!=r@rG1| zb5+I6Z}V|r-#!+H!GtlbR0X0>LI;N}p1xLPwt$zHvanJlSK8{2h20}j@Fgm}VaXHx z51Nwj^xO_P<2Z|=D5@%`lxPgff;sM%E3THy@%>97NK?94KW`QPlC-q6oIQJ%!OQ=4 z2Bw>;*yFrgE}u|l7XcvPi_UUW;fyE#!#~&+c3BB5g6J}3nR$XX2LS+pAS{>T9Qs31 z6ww>W0}c=@QkN`Jmn;fcy1iXZfuZhDlsh4e$k41}P5Dwpn=Ys<@4WL4{p&GPv~?$u zmql29OV9AF%eoR_Q#k-Za$~;Sn4fTghHur=zpoh$>Z~>+U6zqcE=}Q~K*a0Bf<8PP zgb|rYra;sN{&PSIr%#`*si|S`CWh&$DiAA-(O}&%bzZqhHttc^C}2U~VEu8940o)B zAddJ-Fd{?75JZ`T+wFe)?YEh{31QM(cM^Ho-&R=A*Zci`KC`prfFOFmKftl^Oj#>8 z7Vtc7pD?y<+eS?WQ>S(7>*Jg_XXO>@*poziV-ABneXW*DTpv11A}p6rM2A_YK(|&| zP%*A0*}Z%B@#Dv%d4*y;RK-VI(W>IFt>oIvHNLi9J7aH3^7o9RF?_3j=*QEsu8#5+ z6iXB{O2)4wUw--J_U+rFd4(eBZz9Tpj$2!-eHG)wmV$VBg4NzQ6SskyudUb4a_1Qf z>^Cm-pZyX5c287>wTc-f%&(Lu4_|%t)gS-(M{*{ZQmP^mS6eBiDiBv#004L68T*wJ z9LH1=1A*g~`tJrV9OkJi0DvGD3I4!we8-L*Z@&3v%BqS4hqh8pRUodgNLFWa?ZEL* z=~vf|E7Ucf0X!12Hk@wz;(ec`n-4D?1dcgwoPYH3)w_1>isjA1AK`HLlTSWb zvt~_gZ7nx1A57Q`pP{YPR2AU(bZ;zHSSr_+-KQ+96cj-O0DuL3j+U#|hBFaA%L$yg zyddfT`|8!J*REYVd$!=P;U16Y$dMx-ee_Xp?}%$PpIWZ3ucseGp)m35MpTbQX(**s z1!4&+J}U&tjRlIla#?x~XD9?B8n|NZw@S65e5ROt0w zK^X=I2OAn1PMkP#;>3wSVAS~{p0&&>tjSu9q-!hHR0UXtCD>O`f*`s~kz55MG7N|S z0C*^Xh5QkpJ762&I3mV}S5Vw@gTYWxP>`9Ksn_deG8qIxZnxXzaycB1=H_OrHBQ{D zxQG_kaU zePUP{VDR3p5vr5UOYgConwsKjYa;C(5mqYH^4%SwI=Q^`zKYtt;n3Cu+bf-#Vm+=OStF4K*cT}AB31cNe@=l)!)#Icp>US({O^UtZNv!257omDA7*|zM zDbd=RtoG#_2`#y-zxzPgcTkeWdsp^VbTG6viS`O~OCK}qhW8HLQ&nQTJXaQ?*W$;> zD-@)?e0wZqVWn=){XJjrK=eke&)Np3_r*9`qRJx4$s}!aJkxUVCS$*a% z+x2rH_sBQdrg_}+G4cvpucG>`SbI?Xd4+)Mwyc-19N>Ca?;+aN$DA?^KYsk{{FWsyK>Vi4y(!~IP4~rk(xpQY-T^%bcf22t3PA>0Q_5mkFRe-0kd_Er%FAsr5 zR&DtM06;30E?BT&)22=T{O3P6Zrs?`CLq{VG;hN9-ZiS4qP(MorJuJ-Sy*Yma>COw z5_5(R>vR7&iXeBi7Yqh#YHDuXx^?#K*{Z6lgoSlC)$%mtr3njy)H4@AVu`9~9wn@} ztmN?gg%@6U>7|$U@893h(9qr8txzbQd+s@}*GqZ*3dLPk%hQl|R18w*txKxH3U})j zKCJW^-^U+++|<e(q%04{&00000NkvXXu0mjf)(!>! literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 7c943c9..b97cb02 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- 2025 - 16 ⭐ - Rust + 2025 - 17 ⭐ - Rust

@@ -26,4 +26,7 @@ + + + diff --git a/src/day8.rs b/src/day8.rs index 0f8c360..de7e153 100644 --- a/src/day8.rs +++ b/src/day8.rs @@ -9,13 +9,13 @@ struct Junction { } fn squared_distance(a: &Junction, b: &Junction) -> u64 { - if a.pos == b.pos { - 0 - } else { - (a.pos.0 - b.pos.0).pow(2) as u64 - + (a.pos.1 - b.pos.1).pow(2) as u64 - + (a.pos.2 - b.pos.2).pow(2) as u64 - } + // if a.pos == b.pos { + // 0 + // } else { + (a.pos.0 - b.pos.0).pow(2) as u64 + + (a.pos.1 - b.pos.1).pow(2) as u64 + + (a.pos.2 - b.pos.2).pow(2) as u64 + // } } impl Junction { @@ -144,6 +144,7 @@ struct JunctionPair { a: usize, b: usize, } + fn make_heap(circuits: &Circuits) -> BinaryHeap> { BinaryHeap::from_iter( circuits diff --git a/src/day9.rs b/src/day9.rs new file mode 100644 index 0000000..20923c5 --- /dev/null +++ b/src/day9.rs @@ -0,0 +1,141 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use grid::{AsCoord2d, Coord2d, Grid}; +use itertools::Itertools; +use std::cmp::{max, min}; + +#[aoc_generator(day9, part1)] +fn parse(input: &str) -> Vec { + input.lines().map(|l| l.parse().unwrap()).collect() +} + +#[aoc(day9, part1)] +fn part1(input: &Vec) -> u64 { + input + .iter() + .tuple_combinations() + .inspect(|(a, b)| { + println!( + "{a} vs {b} = {}", + a.x().abs_diff(b.x()) * a.y().abs_diff(b.y()) + ) + }) + .map(|(a, b)| (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1)) + .sorted_unstable() + .next_back() + .unwrap() +} + +#[aoc_generator(day9, part2)] +fn parse2(input: &str) -> (Vec, Grid) { + let reds = parse(input); + let width = reds.iter().map(|c| c.x()).max().unwrap() + 1; + let height = reds.iter().map(|c| c.y()).max().unwrap() + 1; + + let mut grid = Grid::with_shape(width as usize, height as usize, b'.'); + let mut prev = reds.last().unwrap(); + for c in &reds { + // mark c filled + grid.set(&c, b'#'); + // build a line of green between it and the previous + if c.x() == prev.x() { + // vertical + for y in (min(c.y(), prev.y()) + 1)..max(c.y(), prev.y()) { + grid.set(&(c.x(), y), b'X'); + } + } else if c.y() == prev.y() { + // horiztonal + for x in (min(c.x(), prev.x()) + 1)..max(c.x(), prev.x()) { + grid.set(&(x, c.y()), b'X'); + } + } else { + panic!() + } + prev = c + } + println!("grid {}x{}", grid.width(), grid.height()); + (reds, grid) +} + +fn flood_fill(grid: &mut Grid) { + #[derive(Debug, Eq, PartialEq)] + enum State { + OffLine(bool), // Off a line(true=inside) + OnLine(bool), // On a line(previous state) + } + for y in 1..grid.height() - 1 { + let mut state = match grid.get(&(0, y)) { + Some(b'.') => State::OffLine(false), //noop + Some(b'#') | Some(b'X') => State::OnLine(true), + s => panic!("Unexpected state: {s:?}"), + }; // if the row starts with a ., we start outside + for x in 1..grid.width() - 1 { + match grid.get(&(x, y)) { + Some(b'.') => { + if state == State::OffLine(true) || state == State::OnLine(false) { + grid.set(&(x, y), b'X'); + state = State::OffLine(true) + } + } + Some(b'#') | Some(b'X') => { + state = State::OnLine(match state { + State::OnLine(s) | State::OffLine(s) => s, + }) + } + None => panic!("overran the grid"), + Some(c) => panic!("unexpected value {c}"), + } + } + } +} + +#[aoc(day9, part2)] +fn part2((reds, grid): &(Vec, Grid)) -> u64 { + let mut grid = grid.clone(); + flood_fill(&mut grid); + + 'outer: for (a, b) in reds + .iter() + .tuple_combinations() + .sorted_unstable_by_key(|(a, b)| (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1)) + .rev() + { + println!( + "{a} vs {b} = {}", + a.x().abs_diff(b.x()) * a.y().abs_diff(b.y()) + ); + + for y in (min(a.y(), b.y()))..=max(a.y(), b.y()) { + for x in (min(a.x(), b.x()))..=max(a.x(), b.y()) { + if *grid.get(&(x, y)).unwrap() == b'.' { + continue 'outer; + } + } + } + return (a.x().abs_diff(b.x()) + 1) * (a.y().abs_diff(b.y()) + 1); + } + panic!() +} + +#[cfg(test)] +mod tests { + use super::*; + + const EXAMPLE: &str = "7,1 +11,1 +11,7 +9,7 +9,5 +2,5 +2,3 +7,3"; + + #[test] + fn part1_example() { + assert_eq!(part1(&parse(EXAMPLE)), 50); + } + + #[test] + fn part2_example() { + assert_eq!(part2(&parse2(EXAMPLE)), 24); + } +} diff --git a/src/lib.rs b/src/lib.rs index ac83a67..b38dc0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ mod day5; mod day6; mod day7; mod day8; +mod day9; use aoc_runner_derive::aoc_lib; diff --git a/utils/grid/lib.rs b/utils/grid/lib.rs index f2fa866..6e60bc5 100644 --- a/utils/grid/lib.rs +++ b/utils/grid/lib.rs @@ -22,22 +22,37 @@ pub const ADJACENT_OFFSETS: [&(i64, i64); 8] = [ /// NESW pub const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)]; -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub struct Coord2d { pub x: i64, pub y: i64, } -impl Debug for Coord2d { +impl Display for Coord2d { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("({}, {})", self.x, self.y)) } } +impl FromStr for Coord2d { + type Err = Box; + fn from_str(s: &str) -> Result { + let (l, r) = s.split_once(',').ok_or("Can't split on ,")?; + Ok(Coord2d { + x: l.parse()?, + y: r.parse()?, + }) + } +} + pub trait AsCoord2d { fn to_coord(self) -> Coord2d; fn x(&self) -> i64; fn y(&self) -> i64; + + fn manhattan(&self, other: &T) -> u64 { + self.x().abs_diff(other.x()) + self.y().abs_diff(other.y()) + } } impl Sub for &Coord2d {