I'm bad at this
This commit is contained in:
parent
61a5cd899e
commit
734b80b05c
1 changed files with 67 additions and 21 deletions
|
@ -1,4 +1,5 @@
|
||||||
mod prelude;
|
mod prelude;
|
||||||
|
|
||||||
pub use crate::prelude::*;
|
pub use crate::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -6,7 +7,6 @@ fn main() {
|
||||||
show_answers(part1(&input), part2(&input));
|
show_answers(part1(&input), part2(&input));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
|
||||||
enum Dir {
|
enum Dir {
|
||||||
N,
|
N,
|
||||||
S,
|
S,
|
||||||
|
@ -17,7 +17,7 @@ enum Dir {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Region {
|
struct Region {
|
||||||
locations: HashSet<(usize, usize)>,
|
locations: HashSet<(usize, usize)>,
|
||||||
perimeters: HashSet<(usize, usize, Dir)>,
|
perimeters: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Region {
|
impl Region {
|
||||||
|
@ -26,24 +26,24 @@ impl Region {
|
||||||
let (height, width) = (bytes.len(), bytes[0].len());
|
let (height, width) = (bytes.len(), bytes[0].len());
|
||||||
let mut candidates = vec![(sx, sy)];
|
let mut candidates = vec![(sx, sy)];
|
||||||
let mut locations = HashSet::from_iter(candidates.clone());
|
let mut locations = HashSet::from_iter(candidates.clone());
|
||||||
let mut perimeters = HashSet::new();
|
let mut perimeters = 0;
|
||||||
|
|
||||||
while let Some((x, y)) = candidates.pop() {
|
while let Some((x, y)) = candidates.pop() {
|
||||||
print!("AT {x},{y}: ");
|
print!("AT {x},{y}: ");
|
||||||
for (nx, ny, d) in [
|
for (nx, ny) in [
|
||||||
(x, y.saturating_sub(1), Dir::N),
|
(x, y.saturating_sub(1)),
|
||||||
(x, y + 1, Dir::S),
|
(x, y + 1),
|
||||||
(x + 1, y, Dir::E),
|
(x + 1, y),
|
||||||
(x.saturating_sub(1), y, Dir::W),
|
(x.saturating_sub(1), y),
|
||||||
] {
|
] {
|
||||||
if (nx, ny) == (x, y) || nx >= width || ny >= height {
|
if (nx, ny) == (x, y) || nx >= width || ny >= height {
|
||||||
print!("EDGE@{nx},{ny}; ");
|
print!("EDGE@{nx},{ny}; ");
|
||||||
perimeters.insert((nx, ny, d));
|
perimeters += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if bytes[ny][nx] != target {
|
if bytes[ny][nx] != target {
|
||||||
print!("EDGE@{nx},{ny}; ");
|
print!("EDGE@{nx},{ny}; ");
|
||||||
perimeters.insert((nx, ny, d));
|
perimeters += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !locations.contains(&(nx, ny)) {
|
if !locations.contains(&(nx, ny)) {
|
||||||
|
@ -60,7 +60,7 @@ impl Region {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part1(input: &str) -> usize {
|
fn regions(input: &str) -> Vec<Region> {
|
||||||
let mut regions = vec![];
|
let mut regions = vec![];
|
||||||
let bytes: Vec<Vec<u8>> = input
|
let bytes: Vec<Vec<u8>> = input
|
||||||
.trim()
|
.trim()
|
||||||
|
@ -74,25 +74,71 @@ fn part1(input: &str) -> usize {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let region = Region::measure_at(&bytes, x, y);
|
let region = Region::measure_at(&bytes, x, y);
|
||||||
println!(
|
|
||||||
"New Region: (Byte: {}, Area: {}, Perimeter: {})",
|
|
||||||
bytes[y][x],
|
|
||||||
®ion.locations.len(),
|
|
||||||
®ion.perimeters.len(),
|
|
||||||
);
|
|
||||||
regionated.extend(®ion.locations);
|
regionated.extend(®ion.locations);
|
||||||
regions.push(region);
|
regions.push(region);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{regions:?}");
|
|
||||||
regions
|
regions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(input: &str) -> usize {
|
||||||
|
regions(input)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| r.locations.len() * r.perimeters.len())
|
.map(|r| r.locations.len() * r.perimeters)
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn part2(input: &str) -> usize {
|
fn part2(input: &str) -> usize {
|
||||||
0
|
regions(input)
|
||||||
|
.iter()
|
||||||
|
.map(|r| {
|
||||||
|
println!("{r:?}");
|
||||||
|
// find top edge in region
|
||||||
|
if r.locations.len() <= 2 {
|
||||||
|
return r.locations.len() * 4;
|
||||||
|
}
|
||||||
|
let (sx, sy) = {
|
||||||
|
let (x, mut y) = *r.locations.iter().next().unwrap();
|
||||||
|
y = (1..y)
|
||||||
|
.rev()
|
||||||
|
.find(|y| r.locations.contains(&(x, y - 1)))
|
||||||
|
.unwrap_or(0);
|
||||||
|
(x, y)
|
||||||
|
};
|
||||||
|
|
||||||
|
// walk along region edge and count turns until we end up where we started
|
||||||
|
let mut turns = 0;
|
||||||
|
let ops = [
|
||||||
|
|(x, y)| (x + 1, y),
|
||||||
|
|(x, y)| (x, y + 1),
|
||||||
|
|(x, y): (usize, usize)| (x.saturating_sub(1), y),
|
||||||
|
|(x, y): (usize, usize)| (x, y.saturating_sub(1)),
|
||||||
|
];
|
||||||
|
let mut dir = 0;
|
||||||
|
let (mut x, mut y) = (sx, sy);
|
||||||
|
println!("start at {x},{y}");
|
||||||
|
loop {
|
||||||
|
let initial_dir = dir;
|
||||||
|
while !r.locations.contains(&ops[dir]((x, y))) || ops[dir]((x, y)) == (x, y) {
|
||||||
|
println!("turning @ {x},{y}");
|
||||||
|
dir = (dir + 1) % ops.len();
|
||||||
|
if dir == initial_dir {
|
||||||
|
panic!("turned too many times in one place");
|
||||||
|
}
|
||||||
|
turns += 1;
|
||||||
|
}
|
||||||
|
(x, y) = ops[dir]((x, y));
|
||||||
|
println!("move to {x},{y}");
|
||||||
|
if turns >= 3 && x == sx && y == sy {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("turns {turns}");
|
||||||
|
|
||||||
|
// walk each side, counting turns
|
||||||
|
r.locations.len() * turns
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -118,7 +164,7 @@ MMMISSJEEE"#;
|
||||||
.collect();
|
.collect();
|
||||||
let region = Region::measure_at(&bytes, 0, 0);
|
let region = Region::measure_at(&bytes, 0, 0);
|
||||||
assert_eq!(region.locations.len(), 12);
|
assert_eq!(region.locations.len(), 12);
|
||||||
assert_eq!(region.perimeters.len(), 18);
|
assert_eq!(region.perimeters, 18);
|
||||||
assert_eq!(part1(input), 1930);
|
assert_eq!(part1(input), 1930);
|
||||||
assert_eq!(part2(input), 1206);
|
assert_eq!(part2(input), 1206);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue