Compare commits

..

3 Commits

Author SHA1 Message Date
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
5 changed files with 1032 additions and 0 deletions

View File

@ -311,6 +311,7 @@ impl<'a> WalkCost2<'a> {
weight: cur_move.weight + self.map.map[new_pos.1][new_pos.0], 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| *m.dir != cur_move.dir.opposite())
.filter(|m| { .filter(|m| {
if m.dir == cur_move.dir { if m.dir == cur_move.dir {

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)

357
18/src/main.rs Normal file
View File

@ -0,0 +1,357 @@
use itertools::Itertools;
use std::collections::{HashMap, LinkedList};
use std::fmt::{Display, Write};
use std::fs::File;
use std::io::{BufRead, BufReader, Lines};
use std::ops::Range;
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>,
tiles_map: HashMap<Position, DigTile>,
x_range: Range<isize>,
y_range: Range<isize>,
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(),
tiles_map: HashMap::new(),
x_range: 0..0,
y_range: 0..0,
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
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 Display for DigHole {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for y in self.y_range.clone() {
for x in self.x_range.clone() {
f.write_char(if (x, y) == (133, -267) {
'*'
} else if self.tiles_map.contains_key(&(x, y)) {
'#'
} else {
'.'
})?;
}
writeln!(f)?;
}
Ok(())
}
}
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);
}
}