summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReiner Herrmann <reiner@reiner-h.de>2024-12-16 15:40:13 +0100
committerReiner Herrmann <reiner@reiner-h.de>2024-12-16 15:40:13 +0100
commit201e1648c4d2740f915cce25736481b189f071d1 (patch)
tree37d8cc65503fe86423a0b067c60466d32b27753c
parentd6e04daed59707a19966b3e626815cd297f92a69 (diff)
day12 solution 2
-rw-r--r--src/bin/day12.rs115
1 files changed, 106 insertions, 9 deletions
diff --git a/src/bin/day12.rs b/src/bin/day12.rs
index 5ccf078..c31ce47 100644
--- a/src/bin/day12.rs
+++ b/src/bin/day12.rs
@@ -4,8 +4,8 @@ static DAY: u8 = 12;
fn main() {
let input = advent::read_lines(DAY);
- println!("{DAY}a: {}", fencing_price(&input));
- println!("{DAY}b: {}", 0);
+ println!("{DAY}a: {}", fencing_price(&input, false));
+ println!("{DAY}b: {}", fencing_price(&input, true));
}
#[derive(Eq, PartialEq, Copy, Clone, Hash)]
@@ -30,6 +30,78 @@ fn count_fences(region: &HashSet<Position>) -> usize {
total_fences
}
+fn count_sides(region: &HashSet<Position>) -> usize {
+ let mut horizontal = HashSet::new();
+ let mut vertical = HashSet::new();
+
+ let mut min_pos = Position { x: isize::MAX, y: isize::MAX };
+ let mut max_pos = Position { x: isize::MIN, y: isize::MIN };
+
+ for pos in region {
+ min_pos.x = min_pos.x.min(pos.x);
+ min_pos.y = min_pos.y.min(pos.y);
+ max_pos.x = max_pos.x.max(pos.x);
+ max_pos.y = max_pos.y.max(pos.y);
+
+ let neighbor = Position { x: pos.x, y: pos.y + 1 };
+ if !region.contains(&neighbor) {
+ horizontal.insert((neighbor, 1));
+ max_pos.y = max_pos.y.max(neighbor.y);
+ }
+
+ let neighbor = Position { x: pos.x, y: pos.y - 1 };
+ if !region.contains(&neighbor) {
+ horizontal.insert((neighbor, 0));
+ min_pos.y = min_pos.y.min(neighbor.y);
+ }
+
+ let neighbor = Position { x: pos.x + 1, y: pos.y };
+ if !region.contains(&neighbor) {
+ vertical.insert((neighbor, 1));
+ max_pos.x = max_pos.x.max(neighbor.x);
+ }
+
+ let neighbor = Position { x: pos.x - 1, y: pos.y };
+ if !region.contains(&neighbor) {
+ vertical.insert((neighbor, 0));
+ min_pos.x = min_pos.x.min(neighbor.x);
+ }
+ }
+
+ let mut sides = 0;
+ for separator in [0, 1] {
+ for x in min_pos.x ..= max_pos.x {
+ let mut is_side = false;
+ for y in min_pos.y ..= max_pos.y {
+ let check = Position { x, y };
+ if is_side && !vertical.contains(&(check, separator)) {
+ is_side = false;
+ sides += 1;
+ }
+ if !is_side && vertical.contains(&(check, separator)) {
+ is_side = true;
+ }
+ }
+ }
+ }
+ for separator in [0, 1] {
+ for y in min_pos.y ..= max_pos.y {
+ let mut is_side = false;
+ for x in min_pos.x ..= max_pos.x {
+ let check = Position { x, y };
+ if is_side && !horizontal.contains(&(check, separator)) {
+ is_side = false;
+ sides += 1;
+ }
+ if !is_side && horizontal.contains(&(check, separator)) {
+ is_side = true;
+ }
+ }
+ }
+ }
+ sides
+}
+
fn find_region(plots: &HashMap<Position, char>, pos: Position, visited: &mut HashSet<Position>) -> HashSet<Position> {
let mut region = HashSet::new();
if visited.contains(&pos) {
@@ -71,10 +143,10 @@ fn find_regions(plots: &HashMap<Position, char>) -> HashMap<char, Vec<HashSet<Po
regions
}
-fn fencing_price(input: &[String]) -> usize {
+fn fencing_price(input: &[String], with_discount: bool) -> usize {
let mut plots = HashMap::new();
- for (x, line) in input.iter().enumerate() {
- for (y, c) in line.chars().enumerate() {
+ for (y, line) in input.iter().enumerate() {
+ for (x, c) in line.chars().enumerate() {
let pos = Position { x: x as isize, y: y as isize };
plots.insert(pos, c);
}
@@ -84,7 +156,11 @@ fn fencing_price(input: &[String]) -> usize {
for regions in all_regions.values() {
for region in regions {
let area = region.len();
- let fences = count_fences(region);
+ let fences = if !with_discount {
+ count_fences(region)
+ } else {
+ count_sides(region)
+ };
total_price += area * fences;
}
}
@@ -104,7 +180,8 @@ mod tests {
"BBCC",
"EEEC",
].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
- assert_eq!(fencing_price(&input), 140);
+ assert_eq!(fencing_price(&input, false), 140);
+ assert_eq!(fencing_price(&input, true), 80);
let input = [
"OOOOO",
@@ -113,7 +190,8 @@ mod tests {
"OXOXO",
"OOOOO",
].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
- assert_eq!(fencing_price(&input), 772);
+ assert_eq!(fencing_price(&input, false), 772);
+ assert_eq!(fencing_price(&input, true), 436);
let input = [
"RRRRIICCFF",
@@ -127,6 +205,25 @@ mod tests {
"MIIISIJEEE",
"MMMISSJEEE",
].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
- assert_eq!(fencing_price(&input), 1930);
+ assert_eq!(fencing_price(&input, false), 1930);
+
+ let input = [
+ "EEEEE",
+ "EXXXX",
+ "EEEEE",
+ "EXXXX",
+ "EEEEE",
+ ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
+ assert_eq!(fencing_price(&input, true), 236);
+
+ let input = [
+ "AAAAAA",
+ "AAABBA",
+ "AAABBA",
+ "ABBAAA",
+ "ABBAAA",
+ "AAAAAA",
+ ].iter().map(|&x| String::from(x)).collect::<Vec<_>>();
+ assert_eq!(fencing_price(&input, true), 368);
}
}