summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2023-12-21 01:18:14 -0600
committerToby Vincent <tobyv@tobyvin.dev>2023-12-21 01:18:14 -0600
commit6f88481aa6242007d1815060388f530be4a13b81 (patch)
tree37a06dc955cc4ec2683be5880940aec792194239
parent3142d80e9db5f7ffd75350a83a2bd314d5804ef4 (diff)
feat: impl day 18
-rw-r--r--input/day_18.txt644
-rw-r--r--src/day_09.rs8
-rw-r--r--src/day_18.rs178
-rw-r--r--src/lib.rs48
-rw-r--r--src/main.rs59
-rw-r--r--src/printer.rs117
6 files changed, 1026 insertions, 28 deletions
diff --git a/input/day_18.txt b/input/day_18.txt
new file mode 100644
index 0000000..e74903a
--- /dev/null
+++ b/input/day_18.txt
@@ -0,0 +1,644 @@
+L 5 (#0760b2)
+U 4 (#058b53)
+L 3 (#d05a12)
+D 4 (#058b51)
+L 6 (#12ee82)
+U 6 (#63c403)
+L 4 (#065a12)
+U 8 (#a44373)
+L 7 (#7581c2)
+U 7 (#334ec3)
+L 3 (#35e792)
+U 5 (#079963)
+L 3 (#1737b0)
+U 4 (#29a7a3)
+L 2 (#705a02)
+U 5 (#7151e3)
+L 4 (#705a00)
+U 4 (#43f5a3)
+L 5 (#1737b2)
+U 8 (#61a8c3)
+L 5 (#6005d2)
+D 3 (#20f4c1)
+L 3 (#4aa812)
+D 3 (#8163b1)
+L 4 (#80ac22)
+D 4 (#5e64c1)
+L 7 (#cb5430)
+D 5 (#7ac2d1)
+R 7 (#920132)
+D 6 (#a44371)
+L 6 (#944582)
+U 3 (#bc3423)
+L 5 (#71c1b2)
+U 4 (#88e6f3)
+L 4 (#0e35f2)
+U 5 (#11fa31)
+L 8 (#6ab312)
+U 5 (#5c3df1)
+R 8 (#40be22)
+U 3 (#5c3df3)
+R 9 (#42e412)
+U 6 (#11fa33)
+R 5 (#178f02)
+U 10 (#88e6f1)
+L 2 (#cff5f2)
+U 6 (#41fb73)
+L 5 (#247782)
+U 4 (#8d6d73)
+L 5 (#139492)
+U 8 (#6360d3)
+R 4 (#1688c2)
+U 2 (#28eb43)
+R 5 (#7d6230)
+U 6 (#769093)
+R 3 (#7d6232)
+U 5 (#487383)
+L 5 (#4fe4c2)
+U 4 (#784971)
+L 7 (#649a42)
+U 3 (#81c8d1)
+L 6 (#3e8422)
+U 5 (#2e26f3)
+L 5 (#880bd2)
+U 4 (#cbeb53)
+L 6 (#3c3a82)
+U 3 (#990203)
+L 8 (#18ce92)
+U 6 (#3bd723)
+L 10 (#8b17c2)
+U 5 (#931f03)
+R 7 (#56b4b2)
+U 3 (#1c3d03)
+R 2 (#693490)
+U 7 (#a5d813)
+L 4 (#693492)
+U 7 (#454523)
+R 8 (#749e20)
+U 3 (#b6ecd3)
+L 8 (#1e69b0)
+U 6 (#0cd813)
+R 4 (#a286d0)
+U 8 (#8249a3)
+R 6 (#c431e0)
+U 10 (#64b5d3)
+R 3 (#26fee0)
+U 7 (#3a6403)
+R 7 (#44c0a2)
+U 8 (#574291)
+R 2 (#9bf502)
+U 5 (#574293)
+R 5 (#0a7b22)
+U 8 (#12e553)
+R 2 (#67c0e0)
+U 3 (#ab6f63)
+R 7 (#922b60)
+D 6 (#680283)
+R 5 (#637c90)
+D 5 (#b10343)
+R 3 (#954ed0)
+D 8 (#254333)
+L 8 (#3f16a0)
+D 3 (#55f2c3)
+R 4 (#2465e0)
+D 9 (#6b7461)
+R 6 (#8b2b00)
+D 7 (#6b7463)
+R 5 (#7ae9f0)
+D 3 (#584e33)
+R 3 (#4fd2d2)
+D 4 (#30e451)
+R 3 (#682c22)
+D 3 (#30e453)
+R 4 (#727be2)
+D 8 (#85b173)
+L 4 (#3a8c50)
+D 3 (#004a23)
+R 2 (#6eef60)
+D 3 (#92b8d3)
+R 5 (#bdb140)
+U 8 (#8500b3)
+R 5 (#2e42f2)
+D 8 (#531953)
+R 3 (#9358a2)
+D 5 (#14d4b3)
+R 6 (#b19aa2)
+D 8 (#14d4b1)
+R 8 (#3e0d32)
+U 8 (#274023)
+R 3 (#b2d1a2)
+U 3 (#274021)
+R 8 (#206d02)
+U 6 (#2d02d3)
+R 4 (#0bd782)
+U 3 (#483403)
+R 9 (#7d6fc0)
+U 5 (#717513)
+R 9 (#5e63a0)
+U 6 (#614071)
+R 6 (#6df500)
+U 9 (#6f14e1)
+R 5 (#9229d0)
+U 5 (#6f14e3)
+L 5 (#0993b0)
+U 4 (#614073)
+L 3 (#aad3a0)
+U 7 (#2aed13)
+L 7 (#117f30)
+U 8 (#b185d3)
+L 3 (#a39640)
+U 10 (#a408b1)
+L 5 (#1e31b0)
+U 4 (#5af491)
+L 3 (#43ff50)
+U 4 (#125121)
+R 5 (#2321b0)
+U 4 (#4a6de1)
+R 6 (#80c430)
+U 5 (#4a6de3)
+L 5 (#8fe3b0)
+U 4 (#483d91)
+R 8 (#012050)
+U 3 (#3730e1)
+R 5 (#d36d12)
+U 8 (#7d5761)
+R 7 (#d36d10)
+U 7 (#21b1c1)
+R 9 (#8ea5e2)
+U 7 (#602a01)
+R 8 (#aae3f2)
+U 5 (#8d2981)
+R 5 (#263f72)
+U 5 (#2a3471)
+R 7 (#263f70)
+U 2 (#88ea21)
+R 3 (#3f5f62)
+U 6 (#5e1cc1)
+R 5 (#adffb0)
+U 6 (#104941)
+R 5 (#073230)
+U 4 (#25be03)
+L 9 (#1a2fd0)
+U 5 (#3d1233)
+R 9 (#879540)
+U 4 (#5c9671)
+L 2 (#6ad9e0)
+U 8 (#5c9673)
+L 7 (#3bb750)
+U 3 (#3d1231)
+R 11 (#080ca0)
+U 4 (#25be01)
+R 4 (#50a100)
+U 5 (#163541)
+L 5 (#27ff80)
+U 3 (#ab8481)
+R 4 (#549890)
+U 7 (#010511)
+L 4 (#749c72)
+U 4 (#46cfe1)
+L 5 (#a03822)
+D 5 (#594361)
+L 2 (#12a9f0)
+D 9 (#509f91)
+L 3 (#c051f0)
+U 3 (#509f93)
+L 7 (#41d8b0)
+D 3 (#80af51)
+L 3 (#549892)
+D 9 (#29c701)
+L 5 (#58fe00)
+D 5 (#4ef833)
+R 5 (#4ad860)
+D 7 (#aa4b13)
+L 7 (#6d6810)
+D 8 (#774e21)
+L 6 (#631140)
+U 8 (#4c9b31)
+L 4 (#4a8a50)
+D 3 (#61b9d1)
+L 6 (#665fd0)
+D 5 (#4edd51)
+R 6 (#46f5d0)
+D 3 (#109bd1)
+L 6 (#896f50)
+D 5 (#3ab8e1)
+L 3 (#6f6ce0)
+D 4 (#5acd11)
+L 5 (#1d15b2)
+U 4 (#032e23)
+L 10 (#8d6c92)
+U 3 (#032e21)
+R 10 (#4e59f2)
+U 5 (#70a541)
+L 5 (#1102a0)
+U 8 (#8b66f1)
+L 5 (#871710)
+U 10 (#be4e51)
+R 3 (#871712)
+U 11 (#1182c1)
+R 3 (#1102a2)
+D 9 (#493441)
+R 8 (#7a6b80)
+D 4 (#c3daa1)
+R 3 (#8a38d0)
+U 3 (#07ac71)
+R 4 (#131b90)
+U 5 (#34c6e1)
+R 4 (#914cf2)
+U 5 (#0e9af1)
+R 3 (#6c62d2)
+U 3 (#3af801)
+L 6 (#0018c0)
+U 7 (#2b7361)
+L 4 (#55fb20)
+U 5 (#8a33c1)
+R 4 (#a79be0)
+U 4 (#59acf1)
+R 7 (#bb8240)
+D 5 (#77ca71)
+R 7 (#894bd0)
+U 5 (#a12ff1)
+R 3 (#437630)
+D 4 (#1dbba1)
+R 10 (#4c87b0)
+U 6 (#9ea131)
+R 2 (#4c87b2)
+U 4 (#19f7e1)
+L 11 (#85c770)
+U 4 (#220631)
+L 9 (#224540)
+U 5 (#d4ac83)
+L 4 (#421610)
+U 3 (#23ae63)
+L 9 (#8259c0)
+D 4 (#1b4b51)
+R 6 (#b84e80)
+D 11 (#9b8e41)
+L 6 (#29c310)
+D 4 (#9cba93)
+L 6 (#2e33e0)
+U 10 (#1d8b03)
+L 5 (#2578e2)
+U 7 (#0c7911)
+L 2 (#6112e2)
+U 2 (#0c7913)
+L 7 (#621cb2)
+D 8 (#4164f3)
+L 4 (#080dd2)
+U 11 (#574773)
+R 7 (#6ab252)
+U 3 (#4224b3)
+R 3 (#898930)
+U 2 (#c88f51)
+R 4 (#798b30)
+U 11 (#c88f53)
+R 4 (#585430)
+U 5 (#3832c3)
+R 3 (#4fee20)
+U 6 (#b69301)
+R 10 (#8cec10)
+U 8 (#bc9fd1)
+L 6 (#8cec12)
+U 2 (#5a1691)
+L 7 (#084160)
+U 7 (#164633)
+L 7 (#3cbba0)
+U 5 (#3e9073)
+R 8 (#9a4ce0)
+U 5 (#6202f3)
+R 4 (#133000)
+U 6 (#60c5f1)
+R 4 (#74b6b0)
+D 6 (#6ab6a1)
+R 4 (#25f5c0)
+U 6 (#9fac91)
+R 7 (#707bb2)
+U 7 (#d176c1)
+R 8 (#7ecfd2)
+D 3 (#348d21)
+R 4 (#582b12)
+D 3 (#583831)
+R 2 (#3cd532)
+D 8 (#583833)
+R 6 (#67b552)
+D 10 (#813bd1)
+R 2 (#1fe0d0)
+D 4 (#37af51)
+R 5 (#807980)
+D 4 (#37af53)
+R 6 (#6bfb10)
+D 4 (#48bf11)
+L 6 (#6d20d0)
+D 4 (#a44a91)
+L 5 (#020f30)
+D 10 (#270741)
+L 4 (#0e8270)
+D 9 (#a5d781)
+R 4 (#8f64c0)
+D 3 (#c06611)
+R 6 (#574250)
+U 10 (#7c7d13)
+R 5 (#c4e490)
+D 8 (#58a503)
+R 3 (#869e62)
+D 4 (#302873)
+R 4 (#716f60)
+D 2 (#96bdb3)
+R 9 (#579f30)
+D 6 (#3ae6d3)
+R 2 (#59c002)
+D 6 (#5f2243)
+R 6 (#6f4e92)
+D 2 (#5effd3)
+R 5 (#869e60)
+D 9 (#72a4c3)
+R 5 (#040640)
+U 3 (#4b1523)
+R 8 (#a6bc50)
+U 8 (#363643)
+R 7 (#897d90)
+D 4 (#5f6cc1)
+R 7 (#3cb430)
+D 8 (#431931)
+R 6 (#5ec560)
+D 7 (#1f9831)
+R 5 (#8ff6c0)
+D 4 (#4efe31)
+R 7 (#5b1802)
+D 2 (#645e71)
+R 8 (#5b1800)
+D 7 (#271021)
+L 4 (#749b40)
+D 3 (#a6a101)
+L 2 (#40cd30)
+D 10 (#210bc1)
+L 3 (#70fd00)
+U 10 (#8095f1)
+L 3 (#1db8e0)
+U 3 (#969461)
+L 3 (#80ea40)
+D 4 (#0d9f41)
+L 8 (#47fc40)
+U 5 (#0a7ed1)
+L 5 (#2dc420)
+D 5 (#6614d1)
+L 5 (#499120)
+D 5 (#2dedd1)
+L 5 (#7eb2c0)
+D 3 (#0b4331)
+L 7 (#075d50)
+D 4 (#9357e1)
+L 5 (#196f62)
+D 7 (#6148d1)
+L 4 (#49cc32)
+U 8 (#1074b1)
+L 2 (#0f1812)
+U 6 (#448f53)
+L 5 (#3a2852)
+D 6 (#4a85a3)
+L 3 (#a83322)
+U 7 (#4a85a1)
+L 6 (#152012)
+D 7 (#827293)
+L 3 (#24bbe2)
+D 3 (#c701e1)
+R 12 (#15c452)
+D 5 (#a53e01)
+L 3 (#4aab42)
+D 4 (#a7ac61)
+L 11 (#635062)
+D 4 (#6bb071)
+L 2 (#03e0b2)
+D 6 (#6a9ce1)
+R 5 (#6052d2)
+D 4 (#5a3341)
+L 5 (#314be2)
+D 4 (#26e621)
+L 5 (#945112)
+D 3 (#9612d1)
+R 4 (#20d072)
+D 6 (#0714d1)
+R 6 (#a00062)
+D 5 (#22f091)
+R 10 (#3f49c0)
+D 2 (#4aa3f1)
+R 7 (#030530)
+D 9 (#115f21)
+R 2 (#363192)
+D 3 (#40b6f1)
+L 7 (#b66fa2)
+D 2 (#642471)
+L 4 (#195292)
+D 10 (#38e091)
+L 8 (#cfc230)
+D 9 (#1acfc1)
+R 3 (#363190)
+D 3 (#579531)
+R 6 (#030532)
+D 8 (#17df01)
+R 2 (#3f49c2)
+D 5 (#13eb81)
+R 9 (#c0d0d0)
+D 7 (#3d1a81)
+R 8 (#2cf6a2)
+U 7 (#990ba1)
+R 2 (#280182)
+U 12 (#151693)
+R 6 (#6a9612)
+D 7 (#151691)
+R 10 (#833942)
+D 2 (#990ba3)
+R 4 (#0aa312)
+D 4 (#74b4b1)
+L 5 (#9cefb2)
+D 3 (#0aebc3)
+L 9 (#7d2300)
+D 3 (#bae673)
+R 8 (#7d2302)
+D 5 (#6b2643)
+R 4 (#1ad422)
+D 12 (#a511e3)
+R 4 (#640b02)
+U 4 (#bace03)
+R 5 (#812422)
+U 5 (#128b13)
+R 8 (#3d8f62)
+U 6 (#cd5893)
+R 11 (#802072)
+D 6 (#30e411)
+R 5 (#8985a2)
+D 4 (#217371)
+R 5 (#5fb102)
+U 7 (#76cd11)
+R 4 (#019092)
+D 7 (#764f53)
+R 7 (#1991f2)
+D 5 (#200673)
+R 3 (#c4df72)
+D 2 (#12fbe3)
+R 10 (#239232)
+D 4 (#2d6823)
+L 4 (#2bbfc0)
+D 11 (#58adf3)
+L 4 (#2bbfc2)
+D 5 (#5d0073)
+L 4 (#34b482)
+D 5 (#bfb221)
+L 5 (#05eac2)
+D 8 (#84cb91)
+L 5 (#05eac0)
+U 11 (#47ea71)
+L 3 (#2ffbb2)
+U 7 (#0968c3)
+L 7 (#2a09e2)
+U 11 (#382063)
+L 5 (#523622)
+D 10 (#502c23)
+L 2 (#22a8e0)
+D 6 (#4f68e3)
+L 3 (#22a8e2)
+U 11 (#5f7063)
+L 3 (#61a142)
+U 6 (#90dcc1)
+L 4 (#8ee7b2)
+D 4 (#a3c391)
+L 9 (#8ee7b0)
+D 5 (#028571)
+R 9 (#aea642)
+D 4 (#0780f3)
+L 2 (#9eb382)
+D 4 (#090683)
+L 6 (#7f5882)
+D 3 (#cbd233)
+L 4 (#3ef000)
+D 2 (#5a4be3)
+L 7 (#572c50)
+D 8 (#c3b7a1)
+L 5 (#7c8430)
+U 8 (#c3b7a3)
+L 3 (#1c43d0)
+U 2 (#944203)
+L 7 (#89b852)
+D 10 (#128611)
+L 8 (#25a0b2)
+D 6 (#128613)
+R 4 (#7f8b52)
+D 3 (#3836c3)
+R 6 (#b96892)
+D 5 (#59a813)
+R 4 (#671590)
+U 4 (#108741)
+R 4 (#c47fa0)
+D 4 (#108743)
+R 5 (#abdf60)
+D 5 (#7f8903)
+R 6 (#c5fd02)
+D 5 (#0fe7a3)
+L 6 (#62c892)
+D 3 (#95f933)
+L 11 (#b77762)
+D 3 (#a0bff3)
+R 6 (#444872)
+D 6 (#730533)
+R 4 (#295162)
+U 6 (#a27af3)
+R 5 (#b41db2)
+D 4 (#5df303)
+R 2 (#c1a730)
+D 3 (#39f573)
+R 5 (#000ef0)
+D 3 (#593163)
+L 8 (#2a99b0)
+D 6 (#5a9631)
+L 5 (#0326a0)
+D 3 (#767951)
+L 5 (#d43c00)
+D 4 (#1ebf01)
+L 5 (#300a00)
+D 4 (#0cd251)
+L 2 (#101d60)
+D 5 (#6b6901)
+L 10 (#bbfbb0)
+D 8 (#5c6c61)
+L 6 (#cc1912)
+D 10 (#4b0fb1)
+L 8 (#5935a0)
+D 7 (#37a1e1)
+L 4 (#c146d0)
+D 10 (#104103)
+L 7 (#6fc450)
+D 8 (#2c8903)
+L 4 (#44bce0)
+D 5 (#88eba3)
+L 4 (#44bce2)
+D 2 (#3e5c83)
+L 8 (#1dd540)
+D 5 (#102cb3)
+R 3 (#41e720)
+D 7 (#5d8523)
+R 5 (#83e9d0)
+U 5 (#518603)
+R 3 (#125412)
+U 4 (#35aee3)
+R 4 (#125410)
+D 5 (#4e2ef3)
+R 8 (#1c9c60)
+D 4 (#593161)
+R 3 (#103c30)
+D 7 (#5b8993)
+R 6 (#9eac70)
+D 8 (#435fb3)
+L 8 (#894ad0)
+D 3 (#8ae413)
+L 4 (#51f0e2)
+D 9 (#755d61)
+L 5 (#a55d12)
+D 4 (#755d63)
+R 5 (#1c6f72)
+D 3 (#1332b3)
+R 12 (#1439e2)
+D 3 (#5c1e03)
+R 6 (#685ab2)
+D 3 (#844351)
+L 7 (#a8c6b2)
+D 5 (#13b3f1)
+L 3 (#2af6d2)
+D 7 (#3b43d1)
+L 4 (#7f2e72)
+D 7 (#a19111)
+L 3 (#aa2540)
+U 4 (#5009a1)
+L 3 (#ac9422)
+U 10 (#1e4901)
+L 3 (#0ac0b2)
+D 5 (#75dc13)
+L 4 (#810712)
+U 5 (#50e203)
+L 5 (#6bafe2)
+U 7 (#8b0a43)
+R 6 (#6bafe0)
+U 4 (#13f013)
+L 6 (#810710)
+U 7 (#7d6663)
+L 6 (#cfc8c2)
+D 8 (#13b173)
+L 6 (#3e6882)
+D 5 (#c7c4a3)
+L 11 (#09a232)
+U 5 (#a8a233)
+L 5 (#8e1632)
+D 6 (#5cd3d1)
+L 4 (#a044c2)
+U 7 (#a688e1)
+L 3 (#8e58f2)
+U 5 (#091d61)
+L 5 (#7dd0b2)
+U 7 (#0ac043)
+L 7 (#9e5aa2)
+U 3 (#9f9d63)
+L 12 (#8d64d2)
+U 4 (#1df793)
+L 4 (#0189e2)
+U 4 (#4424e3)
+L 10 (#02fe02)
+U 7 (#71b7d3)
diff --git a/src/day_09.rs b/src/day_09.rs
index 78cf69a..8c13228 100644
--- a/src/day_09.rs
+++ b/src/day_09.rs
@@ -11,18 +11,18 @@ impl Problem for Day09 {
}
impl Solution for Day09 {
- type Answer1 = isize;
+ type Answer1 = usize;
- type Answer2 = isize;
+ type Answer2 = usize;
fn part_1(input: &str) -> anyhow::Result<Self::Answer1> {
let data = parse_input(input)?;
- Ok(data.into_iter().map(extrapolate_forward).sum())
+ Ok(data.into_iter().map(extrapolate_forward).sum::<isize>() as usize)
}
fn part_2(input: &str) -> anyhow::Result<Self::Answer2> {
let data = parse_input(input)?;
- Ok(data.into_iter().map(extrapolate_reverse).sum())
+ Ok(data.into_iter().map(extrapolate_reverse).sum::<isize>() as usize)
}
}
diff --git a/src/day_18.rs b/src/day_18.rs
new file mode 100644
index 0000000..1ed5100
--- /dev/null
+++ b/src/day_18.rs
@@ -0,0 +1,178 @@
+use crate::{Problem, Solution};
+
+pub struct Day18;
+
+impl Problem for Day18 {
+ const DAY: u8 = 18;
+
+ const INPUT: &'static str = include_str!("../input/day_18.txt");
+}
+
+impl Solution for Day18 {
+ type Answer1 = usize;
+
+ type Answer2 = usize;
+
+ fn part_1(input: &str) -> anyhow::Result<Self::Answer1> {
+ let mut pos = (0_isize, 0_isize);
+ let mut trenches = vec![(pos, 'S')];
+
+ let mut b = 0;
+ let mut dir = 'S';
+
+ for line in input.lines() {
+ let mut iter = line.split_whitespace();
+ let c = iter.next().unwrap().chars().next().unwrap();
+ let len = iter.next().unwrap().parse()?;
+ b += len;
+
+ if "DU".contains(c) && dir != c {
+ dir = c;
+ if let Some((_, prev)) = trenches.last_mut() {
+ *prev = dir
+ }
+ }
+
+ for _ in 0..len {
+ match c {
+ 'U' => pos.0 -= 1,
+ 'D' => pos.0 += 1,
+ 'L' => pos.1 -= 1,
+ 'R' => pos.1 += 1,
+ c => return Err(anyhow::format_err!("Invalid character: {c}")),
+ };
+
+ trenches.push((pos, dir));
+ }
+ }
+
+ trenches.sort();
+
+ let n = trenches
+ .group_by(|a, b| a.0 .0 == b.0 .0)
+ .fold(b, |acc, row| {
+ acc + row
+ .iter()
+ .map_windows(|[((_, start), c1), ((_, end), c2)]| {
+ if *c1 == 'U' && *c2 == 'D' {
+ start.abs_diff(*end) - 1
+ } else {
+ 0
+ }
+ })
+ .sum::<usize>()
+ });
+
+ Ok(n)
+
+ // 58396 >
+ // 58396 >
+ // 49897 ==
+ }
+
+ fn part_2(input: &str) -> anyhow::Result<Self::Answer2> {
+ let mut pos = (0_isize, 0_isize);
+ let mut trenches = vec![(pos, 'S')];
+
+ let mut b = 0;
+ let mut dir = 'S';
+
+ for line in input.lines() {
+ let (c, len) = parse_code(line);
+ b += len;
+
+ if "DU".contains(c) && dir != c {
+ dir = c;
+ if let Some((_, prev)) = trenches.last_mut() {
+ *prev = dir
+ }
+ }
+
+ for _ in 0..len {
+ match c {
+ 'U' => pos.0 -= 1,
+ 'D' => pos.0 += 1,
+ 'L' => pos.1 -= 1,
+ 'R' => pos.1 += 1,
+ c => return Err(anyhow::format_err!("Invalid character: {c}")),
+ };
+
+ trenches.push((pos, dir));
+ }
+ }
+
+ trenches.sort();
+
+ let n = trenches
+ .group_by(|a, b| a.0 .0 == b.0 .0)
+ .fold(b, |acc, row| {
+ acc + row
+ .iter()
+ .map_windows(|[((_, start), c1), ((_, end), c2)]| {
+ if *c1 == 'U' && *c2 == 'D' {
+ start.abs_diff(*end) - 1
+ } else {
+ 0
+ }
+ })
+ .sum::<usize>()
+ });
+
+ Ok(n)
+ }
+}
+
+fn parse_code(s: &str) -> (char, usize) {
+ let iter = &mut s
+ .split_whitespace()
+ .nth(2)
+ .unwrap()
+ .strip_prefix("(#")
+ .unwrap()
+ .strip_suffix(')')
+ .unwrap()
+ .chars();
+ let dist = usize::from_str_radix(&iter.take(5).collect::<String>(), 16).unwrap();
+ let code = iter.next().unwrap().to_digit(10).unwrap();
+ let c = match code {
+ 0 => 'R',
+ 1 => 'D',
+ 2 => 'L',
+ 3 => 'U',
+ n => panic!("Invalid code: {n}"),
+ };
+
+ (c, dist)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ const INPUT: &str = indoc::indoc! {r#"
+ 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)
+ "#};
+
+ #[test]
+ fn test_part_1() -> anyhow::Result<()> {
+ Ok(assert_eq!(62, Day18::part_1(INPUT)?))
+ }
+
+ #[test]
+ fn test_part_2() -> anyhow::Result<()> {
+ Ok(assert_eq!(952408144115, Day18::part_2(INPUT)?))
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 51f906c..54ce211 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,7 +4,9 @@
iter_array_chunks,
array_windows,
iter_intersperse,
- impl_trait_in_assoc_type
+ impl_trait_in_assoc_type,
+ macro_metavar_expr,
+ slice_group_by
)]
pub mod day_01;
@@ -24,6 +26,50 @@ pub mod day_14;
pub mod day_15;
pub mod day_16;
pub mod day_17;
+pub mod day_18;
+pub mod printer;
+
+pub use printer::Printer;
+
+pub type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
+
+#[macro_export]
+macro_rules! get_days {
+ // `()` indicates that the macro takes no argument.
+ ($($day:path),*) => {
+ pub fn get_days() -> [(&'static str, [Box<dyn Fn(&str) -> anyhow::Result<usize>>; 2]); ${count(day)}] {
+ [
+ $((<$day>::INPUT,
+ [
+ Box::new(<$day>::part_1),
+ Box::new(<$day>::part_2),
+ ])
+ ,)*
+ ]
+ }
+ };
+}
+
+get_days!(
+ day_01::Day01,
+ day_02::Day02,
+ day_03::Day03,
+ day_04::Day04,
+ day_05::Day05,
+ day_06::Day06,
+ day_07::Day07,
+ day_08::Day08,
+ day_09::Day09,
+ day_10::Day10,
+ day_11::Day11,
+ day_12::Day12,
+ day_13::Day13,
+ day_14::Day14,
+ day_15::Day15,
+ day_16::Day16,
+ day_17::Day17,
+ day_18::Day18
+);
pub trait Problem {
const DAY: u8;
diff --git a/src/main.rs b/src/main.rs
index 33333c1..0883c66 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,27 +1,40 @@
-use aoc_2023::{
- day_01::Day01, day_02::Day02, day_03::Day03, day_04::Day04, day_05::Day05, day_06::Day06,
- day_07::Day07, day_08::Day08, day_09::Day09, day_10::Day10, day_11::Day11, day_12::Day12,
- day_13::Day13, day_14::Day14, day_15::Day15, day_16::Day16, day_17::Day17, Solution,
-};
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+ let mut args = std::env::args().skip(1);
+ let days = aoc_2023::get_days();
-fn main() -> anyhow::Result<()> {
- Day01::solve()?;
- Day02::solve()?;
- Day03::solve()?;
- Day04::solve()?;
- Day05::solve()?;
- Day06::solve()?;
- Day07::solve()?;
- Day08::solve()?;
- Day09::solve()?;
- Day10::solve()?;
- Day11::solve()?;
- Day12::solve()?;
- Day13::solve()?;
- Day14::solve()?;
- Day15::solve()?;
- Day16::solve()?;
- Day17::solve()?;
+ let days_n = if let Some(first) = args.next() {
+ if "all".contains(first.as_str()) {
+ (1..days.len() + 1).collect::<Vec<_>>()
+ } else {
+ std::iter::once(first)
+ .chain(args)
+ .map(|d| d.parse::<usize>())
+ .collect::<Result<Vec<_>, _>>()?
+ }
+ } else {
+ vec![days.len()]
+ };
+
+ for day in days_n {
+ if day == 0 || day > days.len() {
+ eprintln!("Error: Invalid day: {day}");
+ continue;
+ }
+
+ let (input, parts) = &days[day - 1];
+
+ for (part, f) in parts.iter().enumerate() {
+ let timer = std::time::SystemTime::now();
+ let answer = f(input)?;
+ let duration = timer.elapsed()?;
+ println!(
+ "Day {day}.{}: {answer} ({}ms)",
+ part + 1,
+ duration.as_micros() as f64 / 100f64
+ );
+ }
+ println!()
+ }
Ok(())
}
diff --git a/src/printer.rs b/src/printer.rs
new file mode 100644
index 0000000..7091124
--- /dev/null
+++ b/src/printer.rs
@@ -0,0 +1,117 @@
+pub struct Printer<W: std::io::Write> {
+ lines: usize,
+ buffer: String,
+ writer: W,
+}
+
+impl<W> From<W> for Printer<W>
+where
+ W: std::io::Write,
+{
+ fn from(value: W) -> Self {
+ Self {
+ lines: 0,
+ buffer: String::new(),
+ writer: value,
+ }
+ }
+}
+
+impl<W: std::io::Write> Printer<W> {
+ pub fn write(&mut self) -> std::io::Result<&mut Self> {
+ writeln!(self.writer, "{}", self.buffer)?;
+ self.writer.flush()?;
+
+ self.lines = self.buffer.lines().count() + 1;
+ self.buffer.clear();
+
+ Ok(self)
+ }
+
+ pub fn write_pause(&mut self, prompt: &str) -> std::io::Result<&mut Self> {
+ use std::io::Read;
+
+ self.buffer.push('\n');
+ self.buffer.push_str(prompt);
+
+ self.write()?;
+ let _ = std::io::stdin().read(&mut [0u8])?;
+ Ok(self)
+ }
+
+ pub fn write_pause_condition(
+ &mut self,
+ prompt: &str,
+ cond: bool,
+ ) -> std::io::Result<&mut Self> {
+ if cond {
+ self.write_pause(prompt)
+ } else {
+ self.write()
+ }
+ }
+
+ pub fn write_sleep(&mut self, time: u64) -> std::io::Result<&mut Self> {
+ self.write()?;
+ std::thread::sleep(std::time::Duration::from_millis(time));
+
+ Ok(self)
+ }
+
+ pub fn clear(&mut self) -> &mut Self {
+ self.buffer
+ .insert_str(0, &"\x1b[1A\x1b[K".repeat(self.lines));
+ self.lines = 0;
+ self
+ }
+
+ pub fn with(&mut self, fmt: std::fmt::Arguments) -> &mut Self {
+ self.buffer.push('\n');
+ self.buffer.push_str(format!("{}", fmt).as_str());
+ self
+ }
+
+ pub fn with_grid<T: std::fmt::Display>(&mut self, grid: &[Vec<T>]) -> &mut Self {
+ let s = grid
+ .iter()
+ .flat_map(|row| {
+ row.iter()
+ .map(|s| s.to_string())
+ .chain(std::iter::once("\n".to_string()))
+ })
+ .collect::<String>();
+
+ self.buffer.push('\n');
+ self.buffer.push_str(s.as_str());
+
+ self
+ }
+
+ pub fn with_grid_path<T: std::fmt::Display>(
+ &mut self,
+ grid: &[Vec<T>],
+ highlight: &[(usize, usize)],
+ ) -> &mut Self {
+ let s = grid
+ .iter()
+ .enumerate()
+ .flat_map(|(x, row)| {
+ row.iter()
+ .enumerate()
+ .map(move |(y, s)| {
+ if highlight.contains(&(x, y)) {
+ format!("\x1b[1;30;42m{s}\x1b[0m")
+ } else {
+ s.to_string()
+ }
+ })
+ .chain(std::iter::once("\n".to_string()))
+ })
+ .collect::<String>();
+
+ self.buffer.push('\n');
+ self.buffer.push_str(s.as_str());
+
+ self
+ }
+}