This commit is contained in:
Shadowfacts 2023-12-18 16:30:48 -05:00
parent 0c5498df01
commit 2aca99aa2b
3 changed files with 1282 additions and 1 deletions

634
input/day18.txt Normal file
View File

@ -0,0 +1,634 @@
R 4 (#9505a2)
U 3 (#984f41)
R 5 (#763772)
U 4 (#5e0883)
R 8 (#6dff52)
D 4 (#5e0881)
R 9 (#220312)
U 7 (#984f43)
L 8 (#1eacc2)
U 8 (#0f1673)
L 2 (#7cab42)
U 9 (#7dae23)
L 5 (#0d4642)
D 13 (#2be373)
L 4 (#225752)
D 4 (#3f8d43)
L 7 (#2930b2)
U 10 (#67f943)
L 6 (#25a0a0)
D 12 (#69b2d3)
L 3 (#8be9f0)
U 4 (#207593)
L 3 (#b18a92)
U 5 (#63c483)
L 9 (#613142)
U 2 (#a6aff3)
L 4 (#7a5082)
U 4 (#2beb03)
R 11 (#050d70)
U 2 (#665ed3)
R 2 (#5422f2)
U 6 (#264a73)
L 7 (#5422f0)
U 3 (#47fcc3)
L 6 (#050d72)
U 8 (#0d1f63)
L 7 (#2828e2)
U 5 (#440971)
L 6 (#547822)
D 8 (#9961b1)
L 5 (#547820)
D 6 (#304541)
L 6 (#8bd7f2)
D 3 (#4eb533)
R 11 (#5c4602)
D 4 (#096b13)
L 11 (#260da0)
D 4 (#400e13)
L 8 (#5f2bb0)
D 5 (#760133)
L 7 (#6a72f0)
D 9 (#33bdc3)
L 3 (#80d940)
U 4 (#155633)
L 4 (#8f4e82)
U 8 (#85bc63)
L 3 (#26b562)
U 4 (#66fa93)
L 7 (#b26d12)
U 11 (#67b8f3)
L 2 (#2bb2f0)
U 3 (#b531a3)
R 4 (#4013d0)
U 6 (#2bd863)
R 2 (#4a6a80)
U 12 (#0f7c13)
R 5 (#6cc370)
U 5 (#109003)
R 4 (#457c40)
U 9 (#935793)
R 4 (#1edea0)
U 4 (#5bc2b3)
R 3 (#4e6750)
U 6 (#947b93)
R 6 (#7fafb0)
U 5 (#8f4c91)
R 2 (#0fa3b0)
U 6 (#21c311)
L 12 (#485f20)
U 3 (#3f2ea1)
L 3 (#8688c0)
U 4 (#0175f3)
R 4 (#7283b0)
U 6 (#64da33)
R 7 (#23e570)
U 7 (#869213)
R 4 (#12f200)
D 8 (#42f3b1)
R 5 (#854f90)
D 3 (#34eaf1)
R 9 (#854f92)
D 6 (#695841)
R 12 (#05b840)
D 6 (#0a3561)
L 3 (#901430)
D 3 (#5ece03)
L 8 (#5f85b0)
D 8 (#3856f3)
R 9 (#4e6aa0)
D 9 (#1cba43)
L 9 (#4b8f20)
D 5 (#730143)
R 11 (#726f40)
D 7 (#2bc223)
R 6 (#2617e0)
U 6 (#2c3d13)
R 4 (#6482c0)
U 5 (#2d55f3)
R 4 (#6e4650)
U 8 (#2d55f1)
R 6 (#0138d0)
U 2 (#243eb3)
R 7 (#17bd10)
U 5 (#7c0aa3)
R 4 (#31a982)
U 7 (#5ae133)
R 4 (#b5ad22)
U 9 (#6a6203)
R 5 (#046852)
U 4 (#12d6b3)
R 6 (#0d09e2)
U 7 (#526203)
R 11 (#3f8962)
U 5 (#4245e3)
L 4 (#699702)
U 6 (#17dce3)
L 11 (#44f9a2)
U 3 (#0c7143)
L 4 (#09aec2)
D 4 (#746e03)
L 6 (#49edf0)
U 4 (#839f83)
L 5 (#5e9ce0)
U 5 (#839f81)
R 9 (#5c47d0)
U 3 (#17f3f3)
R 2 (#3180a0)
U 11 (#7a7973)
R 3 (#7d7750)
U 7 (#9ed523)
R 3 (#6b5450)
D 9 (#523bb3)
R 5 (#9a1b80)
D 3 (#4323e3)
R 3 (#299430)
U 2 (#97c0e3)
R 4 (#6e8450)
U 10 (#448eb1)
R 5 (#63bda2)
U 3 (#702a61)
R 3 (#2c2690)
U 12 (#7379e1)
R 4 (#2c2692)
U 7 (#0c4041)
R 3 (#63bda0)
U 7 (#45cc21)
L 4 (#4cd2e0)
U 4 (#2ae8f1)
L 7 (#738540)
D 11 (#a34001)
L 6 (#738542)
D 2 (#16d291)
L 4 (#05ba40)
D 5 (#8872a1)
L 9 (#186db0)
D 3 (#8e7ce1)
L 5 (#9c6d10)
U 6 (#8e7ce3)
L 9 (#56a350)
U 2 (#9df721)
L 6 (#4e9042)
U 3 (#2659a1)
R 4 (#3bd022)
U 5 (#2659a3)
R 11 (#811db2)
U 5 (#ad2b91)
L 9 (#05ba42)
U 5 (#72a9c1)
R 8 (#211510)
U 5 (#13cb31)
R 6 (#6c2480)
D 7 (#13cb33)
R 6 (#2f0f60)
U 7 (#4683f1)
R 4 (#0054d0)
U 4 (#8bf741)
L 13 (#7fb5c0)
U 2 (#149691)
L 3 (#196d60)
U 6 (#5fef73)
R 3 (#0cf060)
U 5 (#52b473)
R 6 (#022db0)
U 9 (#346de3)
R 6 (#1f0e40)
U 5 (#251e63)
R 10 (#777a02)
U 4 (#6f8d93)
R 6 (#777a00)
U 12 (#3cdb63)
L 3 (#426ac2)
U 8 (#1cd103)
L 10 (#83a360)
U 5 (#07e093)
L 3 (#2a5f40)
U 6 (#22d423)
R 2 (#448862)
U 6 (#8da513)
R 7 (#697a42)
U 2 (#6478e3)
R 3 (#426ac0)
U 4 (#8c62b3)
R 11 (#908510)
U 2 (#625113)
R 2 (#7dcc10)
U 4 (#315be3)
L 10 (#242e40)
U 2 (#352c83)
L 3 (#68e2f0)
U 4 (#658603)
R 3 (#4aa570)
U 4 (#387113)
L 3 (#3616a0)
U 4 (#3bcef3)
L 6 (#3616a2)
U 12 (#68c1b3)
L 2 (#4aa572)
U 8 (#028b23)
L 10 (#4126a0)
U 3 (#14e773)
R 10 (#763032)
U 2 (#86bf23)
R 4 (#3f43a2)
U 5 (#468f11)
R 7 (#0ec812)
U 3 (#99ca31)
L 7 (#4bc6a0)
U 8 (#67a621)
L 3 (#4bc6a2)
U 3 (#53c3a1)
L 10 (#6d0ad0)
U 6 (#218a01)
R 12 (#6d0ad2)
U 3 (#4e8fe1)
R 8 (#52f3a2)
U 7 (#2ae183)
R 8 (#420262)
U 3 (#a3eba3)
R 3 (#6f0962)
U 11 (#9018d3)
R 6 (#444152)
U 7 (#acf6f3)
R 5 (#4caec2)
D 10 (#47f963)
R 3 (#2094f2)
U 13 (#02f073)
R 3 (#2cb412)
U 7 (#29d5b3)
R 5 (#999602)
D 2 (#52abf3)
R 4 (#7fbe72)
D 9 (#5210d3)
R 4 (#b456f2)
D 9 (#378693)
R 5 (#b456f0)
U 10 (#58bea3)
R 5 (#111ef2)
D 7 (#1eb663)
R 3 (#873e92)
D 2 (#02cbb3)
R 3 (#8756c2)
D 12 (#682d83)
R 3 (#64e760)
U 7 (#6478a3)
R 8 (#7a9d20)
D 4 (#6ec453)
R 8 (#8aec52)
D 3 (#858fa3)
R 5 (#8aec50)
D 6 (#5fe253)
L 7 (#804c10)
D 4 (#5721c1)
L 3 (#5a26e0)
D 5 (#344fc1)
L 2 (#260642)
D 3 (#947521)
L 10 (#260640)
D 4 (#10be21)
L 6 (#28aba0)
U 7 (#239181)
R 4 (#a84ed0)
U 5 (#594d81)
L 4 (#523490)
U 4 (#5d20e3)
L 3 (#621ce0)
D 3 (#5d20e1)
L 9 (#45f630)
U 5 (#07f8b1)
L 2 (#9bceb0)
U 4 (#541ae1)
L 9 (#56a000)
D 7 (#5cdf31)
L 9 (#2f94d0)
D 2 (#1705b3)
L 7 (#7f1d70)
D 7 (#99f463)
R 6 (#8a9190)
D 5 (#9f9111)
R 5 (#02d950)
D 4 (#1b0841)
R 7 (#199fc0)
D 2 (#739481)
R 8 (#199fc2)
U 4 (#4b47c1)
R 9 (#7014b0)
D 4 (#24c0a1)
R 15 (#30ae00)
D 4 (#8e1d01)
L 8 (#85f080)
D 3 (#2f10a1)
L 3 (#46b8e2)
D 4 (#830d61)
L 12 (#04b302)
D 2 (#9d5ae1)
L 3 (#018932)
D 5 (#04ada3)
L 6 (#2fe952)
D 5 (#3ff843)
L 7 (#8e4dd2)
D 6 (#78d433)
L 12 (#127612)
D 6 (#3f20f1)
R 12 (#994c62)
D 4 (#5cb071)
R 3 (#994c60)
D 3 (#21a8b1)
R 8 (#533c92)
D 3 (#58d461)
R 7 (#316010)
D 5 (#3772e1)
R 4 (#3efac2)
D 3 (#185d41)
R 10 (#2a5450)
D 4 (#66b841)
R 3 (#2a5452)
D 7 (#4c84c1)
R 4 (#3efac0)
D 3 (#0544d1)
R 4 (#959a70)
D 6 (#07b843)
R 2 (#789922)
D 7 (#97a0f3)
R 5 (#789920)
D 3 (#68f8c3)
R 3 (#632b70)
D 7 (#0628c1)
R 3 (#46b8e0)
D 9 (#0a5911)
R 3 (#0caab0)
U 6 (#247553)
R 3 (#451e30)
U 9 (#53d613)
R 5 (#85d060)
U 7 (#1e3623)
R 5 (#044a50)
D 9 (#558213)
R 7 (#481c60)
D 5 (#49bbd3)
L 7 (#481c62)
D 6 (#830fb3)
R 2 (#6b1ef0)
D 2 (#0e5861)
R 9 (#070aa0)
D 6 (#693991)
R 4 (#070aa2)
U 4 (#4c5121)
R 9 (#205ad0)
U 5 (#0c67d1)
R 7 (#062fc0)
U 6 (#16c763)
R 8 (#669720)
U 5 (#4e9843)
R 6 (#05bc32)
U 4 (#9513d3)
R 3 (#05bc30)
U 2 (#928d03)
R 4 (#a01410)
D 11 (#7b2af1)
R 6 (#4c41d0)
D 13 (#52bb51)
R 3 (#9001e0)
D 2 (#0a18d1)
R 4 (#968322)
D 5 (#509641)
L 13 (#1abda2)
D 6 (#540201)
L 9 (#2b02f2)
D 2 (#106921)
L 5 (#3a2dc0)
D 6 (#319fd3)
R 9 (#56ac20)
D 3 (#319fd1)
R 5 (#400070)
D 7 (#735a51)
R 10 (#20c2b2)
D 2 (#a17341)
R 3 (#005a72)
D 5 (#224c51)
L 7 (#022422)
D 3 (#3a9061)
L 9 (#402e82)
D 8 (#4d0491)
L 5 (#6e9c32)
D 2 (#0b58d1)
L 15 (#2bb0f0)
U 4 (#8a1051)
L 9 (#2bb0f2)
U 5 (#84c961)
L 3 (#39dea2)
U 13 (#75c911)
L 4 (#3cb3c2)
D 4 (#2466e1)
L 8 (#3cb3c0)
D 8 (#685971)
L 4 (#6adcc2)
D 6 (#1e7673)
L 5 (#526972)
D 4 (#1b2ad3)
L 7 (#853862)
D 9 (#696ea3)
R 10 (#0d3450)
D 4 (#4633b1)
R 3 (#7c6780)
D 9 (#4633b3)
R 5 (#4e0600)
D 8 (#5f7983)
R 7 (#8861d2)
U 5 (#79c723)
R 5 (#4b16b2)
U 4 (#b58831)
R 3 (#06a1b2)
U 9 (#59fd71)
R 7 (#6fa5e2)
U 6 (#873f01)
R 3 (#6fa5e0)
U 3 (#61b3c1)
R 5 (#06a1b0)
D 7 (#6931a1)
R 9 (#ab7272)
U 7 (#640df3)
R 10 (#00b292)
D 7 (#8488f3)
R 6 (#8572c2)
D 8 (#105483)
L 7 (#5f6022)
U 5 (#3fadd3)
L 2 (#5f6020)
U 7 (#7ee933)
L 3 (#333b12)
D 10 (#221823)
L 3 (#a61062)
D 2 (#880f83)
L 5 (#0c2a12)
D 9 (#79c721)
L 5 (#7ccff2)
D 3 (#35a183)
R 8 (#14e432)
U 6 (#557103)
R 5 (#b5e082)
U 2 (#6bee81)
R 8 (#261612)
D 2 (#1f2401)
R 4 (#af2ae2)
D 11 (#40ed21)
L 6 (#1c2ef2)
D 5 (#293701)
L 7 (#3699c0)
D 6 (#5708b1)
L 3 (#8dd6c0)
D 12 (#2894f1)
L 5 (#513a12)
D 7 (#198a23)
R 12 (#20de32)
D 2 (#198a21)
R 9 (#525842)
D 4 (#273111)
L 10 (#3dd5a0)
D 5 (#14f9b1)
L 11 (#269190)
D 5 (#3d5191)
L 10 (#18a862)
U 3 (#71c981)
L 5 (#18a860)
U 4 (#1c7671)
R 8 (#6c8330)
U 11 (#5356c3)
L 8 (#41d400)
U 9 (#6b4d03)
R 5 (#41d402)
U 14 (#0cedc3)
L 5 (#686260)
D 5 (#717c11)
L 7 (#2afee0)
D 8 (#103261)
L 5 (#95f2c0)
D 9 (#81ae73)
L 8 (#88ebb0)
D 10 (#0ccc91)
L 7 (#5866b0)
D 9 (#304491)
L 3 (#2e6b60)
D 7 (#67abd1)
L 5 (#2e6b62)
D 9 (#2b3131)
L 2 (#5866b2)
D 11 (#375731)
L 8 (#5855c0)
D 7 (#33fcb1)
L 4 (#4b9132)
D 6 (#5bc731)
R 5 (#4b9130)
D 5 (#36f2b1)
R 7 (#68cbf2)
D 4 (#2e6191)
R 8 (#a1b162)
D 6 (#585861)
R 4 (#004682)
U 5 (#23f741)
R 6 (#abffe2)
D 5 (#46fcd3)
R 10 (#8cc712)
D 6 (#46fcd1)
R 6 (#31aad2)
U 3 (#4ed551)
R 3 (#9a6852)
U 5 (#7b9781)
R 9 (#5d9402)
D 8 (#20bc71)
R 10 (#577972)
U 6 (#624ef1)
R 7 (#2e7e40)
D 8 (#0e1851)
R 4 (#868f30)
D 6 (#9ac001)
R 3 (#91bd02)
D 7 (#8455f1)
R 6 (#3dc142)
D 4 (#6bf421)
L 9 (#262a72)
D 2 (#6c0b41)
L 2 (#2def60)
D 3 (#2e8621)
L 7 (#2def62)
D 7 (#5cd0a1)
L 3 (#2eabf2)
D 9 (#87f891)
L 7 (#7801e2)
U 4 (#2d78c1)
L 4 (#884eb2)
U 8 (#5f91d1)
L 8 (#b069c2)
U 3 (#706ec3)
L 10 (#14d6a0)
U 2 (#2e1ee3)
L 5 (#6fcd20)
U 2 (#2e1ee1)
L 4 (#6a8280)
U 9 (#10aed3)
L 6 (#28d1e0)
U 8 (#9ef053)
L 9 (#0e4470)
U 3 (#9fcdf3)
L 6 (#6be0a0)
U 4 (#4b5df3)
L 13 (#3d1b92)
D 5 (#0a7c03)
L 4 (#4225d2)
D 4 (#1a1661)
L 12 (#012740)
D 5 (#3ce951)
L 3 (#52df42)
D 7 (#ace6c1)
L 8 (#52df40)
D 4 (#255791)
R 7 (#012742)
D 3 (#4a15d1)
R 10 (#318982)
D 3 (#510b33)
L 14 (#7cfeb2)
D 2 (#510b31)
L 3 (#13c862)
D 5 (#126f93)
L 8 (#204922)
D 8 (#7b3623)
L 5 (#6c3780)
U 4 (#0c8663)
L 9 (#6c3782)
U 3 (#794583)
L 11 (#204920)
U 8 (#5fe243)
L 3 (#508b42)
U 4 (#62a383)
R 10 (#67e9b2)
U 8 (#94a731)
R 6 (#8e9b22)
U 4 (#858011)
L 10 (#8e9b20)
U 7 (#4c8cd1)
L 6 (#8f5152)
U 8 (#483551)
L 4 (#42e142)
D 12 (#40e3a1)
L 4 (#0b5b92)
D 9 (#0d1471)
R 4 (#37cb02)
D 5 (#b1c241)
L 8 (#67aa22)
D 5 (#799ad1)
L 5 (#3aa9f2)
D 7 (#473731)
L 4 (#60de22)
D 6 (#65e001)
L 2 (#80c4d0)
D 9 (#2fbf71)
L 3 (#826d60)
U 4 (#848001)
L 3 (#687032)
U 11 (#9768d1)
L 4 (#5b7e22)
D 5 (#25fb53)
L 7 (#ade7d2)
U 2 (#25fb51)
L 4 (#394662)
U 11 (#840763)

646
src/day18.rs Normal file
View File

@ -0,0 +1,646 @@
use std::{collections::VecDeque, ops::RangeInclusive, thread};
use itertools::{Itertools, MinMaxResult};
use regex::{Captures, Regex, Replacer};
pub fn run() {
let input = include_str!("../input/day18.txt");
// let input = 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)
// "#;
// let input = r#"
// R 4 (#000000)
// U 4 (#000000)
// R 6 (#000000)
// U 10 (#000000)
// L 4 (#000000)
// D 6 (#000000)
// L 6 (#000000)
// D 8 (#000000)
// "#;
// let input = r#"
// L 3 (#000000)
// U 5 (#000000)
// L 3 (#000000)
// D 3 (#000000)
// L 3 (#000000)
// U 6 (#000000)
// R 9 (#000000)
// D 8 (#000000)
// "#;
let instructions = parse_instructions(input);
let path = run_instructions(&instructions);
dbg!(count_enclosed2(&path));
// let instructions2 = parse_instructions_part2(input);
// let path2 = run_instructions(&instructions2);
// dbg!(count_enclosed2(&path2));
}
fn parse_instructions(s: &str) -> Vec<Instruction> {
s.trim()
.lines()
.map(|l| {
let mut parts = l.trim().split(" ");
let dir: Direction = parts.next().unwrap().into();
let distance: u32 = parts.next().unwrap().parse().unwrap();
Instruction {
direction: dir,
distance,
}
})
.collect()
}
fn parse_instructions_part2(s: &str) -> Vec<Instruction> {
s.trim()
.lines()
.map(|l| {
let hex = l
.trim()
.split(" ")
.skip(2)
.next()
.unwrap()
.strip_prefix("(#")
.unwrap()
.strip_suffix(")")
.unwrap();
let dir = match hex.chars().last().unwrap() {
'0' => Direction::Right,
'1' => Direction::Down,
'2' => Direction::Left,
'3' => Direction::Up,
c => panic!("unexpected dir {}", c),
};
let distance = u32::from_str_radix(hex.split_at(5).0, 16).unwrap();
Instruction {
direction: dir,
distance,
}
})
.collect()
}
#[derive(Debug, Clone, Copy)]
struct Instruction {
direction: Direction,
distance: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Direction {
Up,
Down,
Left,
Right,
}
impl From<&str> for Direction {
fn from(value: &str) -> Self {
match value {
"U" => Self::Up,
"D" => Self::Down,
"L" => Self::Left,
"R" => Self::Right,
_ => panic!("invalid direction {}", value),
}
}
}
impl Direction {
fn is_vertical(&self) -> bool {
match self {
Self::Up | Self::Down => true,
_ => false,
}
}
fn move_point(&self, (x, y): (isize, isize), distance: isize) -> (isize, isize) {
match self {
Self::Up => (x, y - distance),
Self::Down => (x, y + distance),
Self::Left => (x - distance, y),
Self::Right => (x + distance, y),
}
}
fn turn(&self, other: Self) -> Turn {
match (self, other) {
(Self::Up, Self::Left) => Turn::Left,
(Self::Up, Self::Right) => Turn::Right,
(Self::Up, Self::Up) => Turn::None,
(Self::Up, Self::Down) => Turn::Back,
(Self::Down, Self::Left) => Turn::Right,
(Self::Down, Self::Right) => Turn::Left,
(Self::Down, Self::Down) => Turn::None,
(Self::Down, Self::Up) => Turn::Back,
(Self::Left, Self::Up) => Turn::Right,
(Self::Left, Self::Down) => Turn::Left,
(Self::Left, Self::Left) => Turn::None,
(Self::Left, Self::Right) => Turn::Back,
(Self::Right, Self::Up) => Turn::Left,
(Self::Right, Self::Down) => Turn::Right,
(Self::Right, Self::Right) => Turn::None,
(Self::Right, Self::Left) => Turn::Back,
}
}
fn between(a: (isize, isize), b: (isize, isize)) -> Self {
if a.0 == b.0 {
if a.1 > b.1 {
Self::Up
} else {
Self::Down
}
} else if a.1 == b.1 {
if a.0 > b.0 {
Self::Left
} else {
Self::Right
}
} else {
panic!()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Turn {
None,
Back,
Left,
Right,
}
fn run_instructions(instructions: &[Instruction]) -> Vec<Segment> {
let mut path = vec![];
let mut prev = (0, 0);
for insn in instructions {
let next = insn.direction.move_point(prev, insn.distance as isize);
path.push(Segment {
start: prev,
end: next,
direction: insn.direction,
});
prev = next;
}
path
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Segment {
start: (isize, isize),
end: (isize, isize),
direction: Direction,
}
impl Segment {
fn contains(&self, (x, y): (isize, isize)) -> bool {
if self.start.0 == self.end.0 {
let min_y = self.start.1.min(self.end.1);
let max_y = self.start.1.max(self.end.1);
x == self.start.0 && y >= min_y && y <= max_y
} else if self.start.1 == self.end.1 {
let min_x = self.start.0.min(self.end.0);
let max_x = self.start.0.max(self.end.0);
x >= min_x && x <= max_x && y == self.start.1
} else {
panic!();
}
}
fn contains_y(&self, y: isize) -> bool {
let min_y = self.start.1.min(self.end.1);
let max_y = self.start.1.max(self.end.1);
y >= min_y && y <= max_y
}
fn intersects(&self, min_x: isize, max_x: isize, min_y: isize, max_y: isize) -> bool {
if self.direction.is_vertical() {
if self.start.0 >= min_x && self.start.0 <= max_x {
let ys = self.start.1.min(self.end.1)..=self.start.1.max(self.end.1);
return range_intersects(ys, min_y..=max_y);
}
} else {
if self.start.1 >= min_y && self.start.1 <= max_y {
let xs = self.start.0.min(self.end.0)..=self.start.0.max(self.end.0);
return range_intersects(xs, min_x..=max_x);
}
}
false
}
}
fn range_intersects(a: RangeInclusive<isize>, b: RangeInclusive<isize>) -> bool {
if b.contains(a.start()) {
true
} else if b.contains(a.end()) {
true
} else {
a.start() < b.start() && a.end() > b.end()
}
}
fn path_bounds(path: &[Segment]) -> (isize, isize, isize, isize) {
let xs = path
.iter()
.flat_map(|segment| [segment.start.0, segment.end.0].into_iter())
.minmax();
let (min_x, max_x) = match xs {
MinMaxResult::NoElements => panic!(),
MinMaxResult::OneElement(x) => (x, x),
MinMaxResult::MinMax(min, max) => (min, max),
};
let ys = path
.iter()
.flat_map(|segment| [segment.start.1, segment.end.1].into_iter())
.minmax();
let (min_y, max_y) = match ys {
MinMaxResult::NoElements => panic!(),
MinMaxResult::OneElement(y) => (y, y),
MinMaxResult::MinMax(min, max) => (min, max),
};
(min_x, max_x, min_y, max_y)
}
fn count_enclosed2(path: &[Segment]) -> usize {
// println!("initial segments: {}", path.len());
// print_path(path);
let mut count = 0;
let mut path = path.to_vec();
let mut last_segment_count = None;
loop {
// println!("--------------");
// print_path(&path);
if let Some(c) = last_segment_count {
if c == path.len() {
print_path(&path);
panic!("stuck at {} segments", c);
} else {
last_segment_count = Some(path.len());
}
} else {
last_segment_count = Some(path.len());
}
// println!("segments remaining: {}", path.len());
// if iterations == 4 {
// break;
// }
if path.len() > 4 {
'start_idx: for start_idx in 0..path.len() - 3 {
let a = path[start_idx];
let b = path[start_idx + 1];
let c = path[start_idx + 2];
let ab = a.direction.turn(b.direction);
let bc = b.direction.turn(c.direction);
if !((ab == Turn::Right && bc == Turn::Right)
|| (ab == Turn::Left && bc == Turn::Left))
{
continue;
}
let min_x: isize;
let max_x: isize;
let min_y: isize;
let max_y: isize;
if !b.direction.is_vertical() {
if b.direction == Direction::Left {
min_x = b.end.0;
max_x = b.start.0;
} else {
min_x = b.start.0;
max_x = b.end.0;
}
let up: Segment;
let down: Segment;
if a.direction == Direction::Up {
up = a;
down = c;
} else {
up = c;
down = a;
}
min_y = up.end.1.max(down.start.1);
max_y = up.start.1.min(down.end.1);
// skip this start_idx if removing the rect would cause the path to intersect
// itself
for (i, s) in path.iter().enumerate() {
if i == start_idx || i == start_idx + 1 || i == start_idx + 2 {
continue;
}
if b.direction.is_vertical() == s.direction.is_vertical() {
continue;
}
if s.intersects(min_x, max_x, min_y, max_y) {
continue 'start_idx;
}
}
// dbg!(start_idx);
let width = 1 + max_x - min_x;
let height = 1 + max_y - min_y;
if is_inside(&path, (max_x, max_y - 1)) {
// println!("+{}", width * (height - 1));
count += width * (height - 1);
} else {
// println!("-{}", (width - 2) * (height - 1));
count -= (width - 2) * (height - 1);
}
if a.direction == Direction::Down {
path[start_idx].end.1 = min_y;
path[start_idx + 1].start.1 = min_y;
path[start_idx + 1].end.1 = min_y;
path[start_idx + 2].start.1 = min_y;
} else {
path[start_idx].end.1 = max_y;
path[start_idx + 1].start.1 = max_y;
path[start_idx + 1].end.1 = max_y;
path[start_idx + 2].start.1 = max_y;
}
} else {
if b.direction == Direction::Down {
min_y = b.start.1;
max_y = b.end.1;
} else {
min_y = b.end.1;
max_y = b.start.1;
}
let left: Segment;
let right: Segment;
if a.direction == Direction::Left {
left = a;
right = c;
} else {
left = c;
right = a;
}
min_x = left.end.0.max(right.start.0);
max_x = left.start.0.min(right.end.0);
// skip this start_idx if removing the rect would cause the path to intersect
// itself
for (i, s) in path.iter().enumerate() {
if i == start_idx || i == start_idx + 1 || i == start_idx + 2 {
continue;
}
if b.direction.is_vertical() == s.direction.is_vertical() {
continue;
}
if s.intersects(min_x, max_x, min_y, max_y) {
continue 'start_idx;
}
}
// dbg!(start_idx);
let width = 1 + max_x - min_x;
let height = 1 + max_y - min_y;
// dbg!((width, height));
if is_inside(&path, (max_x, max_y - 1)) {
// println!("+{}", (width - 1) * height);
count += (width - 1) * height;
} else {
// println!("-{}", (width - 1) * (height - 2));
count -= (width - 1) * (height - 2);
}
if a.direction == Direction::Left {
path[start_idx].end.0 = max_x;
path[start_idx + 1].start.0 = max_x;
path[start_idx + 1].end.0 = max_x;
path[start_idx + 2].start.0 = max_x;
} else {
path[start_idx].end.0 = min_x;
path[start_idx + 1].start.0 = min_x;
path[start_idx + 1].end.0 = min_x;
path[start_idx + 2].start.0 = min_x;
}
}
simplify_path(&mut path);
break;
}
} else if path.len() == 4 {
println!("four segments remaining, almost done");
let (min_x, max_x, min_y, max_y) = rect_around(path[0], path[1], path[2]);
let width = 1 + max_x - min_x;
let height = 1 + max_y - min_y;
// dbg!((width, height));
count += width * height;
break;
}
}
// dbg!(count);
count as usize
}
fn is_inside(path: &[Segment], p: (isize, isize)) -> bool {
let (min_x, _, _, _) = path_bounds(path);
let row_paths = path
.iter()
.filter(|s| s.contains_y(p.1))
.collect::<Vec<_>>();
let mut inside = false;
for x in min_x..p.0 {
let containing = row_paths
.iter()
.filter(|s| s.contains((x, p.1)))
.take(2)
.collect::<Vec<_>>();
if containing.len() == 2 {
// only count the top corners
let vert = if containing[0].direction.is_vertical() {
containing[0]
} else {
containing[1]
};
let min_y = vert.start.1.min(vert.end.1);
if p.1 == min_y {
inside = !inside;
}
} else if containing.len() == 1 {
if containing[0].direction.is_vertical() {
inside = !inside;
}
}
}
inside
}
fn rect_around(a: Segment, b: Segment, c: Segment) -> (isize, isize, isize, isize) {
let mut min_x = a.start.0;
let mut max_x = a.start.0;
let mut min_y = a.start.1;
let mut max_y = a.start.1;
for s in [a, b, c] {
min_x = min_x.min(s.start.0).min(s.end.0);
max_x = max_x.max(s.start.0).max(s.end.0);
min_y = min_y.min(s.start.1).min(s.end.1);
max_y = max_y.max(s.start.1).max(s.end.1);
}
(min_x, max_x, min_y, max_y)
}
fn simplify_path(path: &mut Vec<Segment>) {
// println!("before simplification:");
// print_path(path);
let mut i = 0;
while i < path.len() - 1 {
let a = path[i];
let b = path[i + 1];
if b.start == b.end {
path.remove(i + 1);
continue;
}
path[i].direction = Direction::between(a.start, a.end);
let turn = a.direction.turn(b.direction);
match turn {
Turn::None | Turn::Back => {
if path[i].direction.is_vertical() {
path[i].end.1 = path[i + 1].end.1;
} else {
path[i].end.0 = path[i + 1].end.0;
}
path.remove(i + 1);
}
_ => i += 1,
}
}
assert_eq!(path[0].start, path[path.len() - 1].end);
if path[0].direction == path[path.len() - 1].direction {
path[0].start = path[path.len() - 1].start;
path.remove(path.len() - 1);
}
}
fn print_path(path: &[Segment]) {
// for segment in path {
// println!(
// "{:?} {:?} -> {:?}",
// segment.direction, segment.start, segment.end
// );
// }
let (min_x, max_x, min_y, max_y) = path_bounds(path);
for y in min_y..=max_y {
for x in min_x..=max_x {
if (x, y) == path[0].start {
print!("X");
} else if let Some(s) = path.iter().find(|s| s.contains((x, y))) {
let c = match s.direction {
Direction::Up => '^',
Direction::Down => 'V',
Direction::Left => '<',
Direction::Right => '>',
};
print!("{}", c);
} else {
print!(".");
}
}
println!();
}
println!();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_run_instructions() {
let instructions = parse_instructions(
r#"
R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
"#,
);
let path = run_instructions(&instructions);
assert_eq!(
path,
vec![
Segment {
start: (0, 0),
end: (6, 0),
direction: Direction::Right
},
Segment {
start: (6, 0),
end: (6, 5),
direction: Direction::Down
},
Segment {
start: (6, 5),
end: (4, 5),
direction: Direction::Left
},
Segment {
start: (4, 5),
end: (4, 7),
direction: Direction::Down
},
]
);
}
#[test]
fn test_count_inside() {
let instructions = parse_instructions(
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)
"#,
);
let path = run_instructions(&instructions);
assert_eq!(count_enclosed2(&path), 62);
}
}

View File

@ -18,7 +18,8 @@ mod day14;
mod day15;
mod day16;
mod day17;
mod day18;
fn main() {
day17::run();
day18::run();
}