-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
245 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- Part Two --- | ||
|
||
Fortunately, the Elves are trying to order so much fence that they qualify for a **bulk discount**! | ||
|
||
Under the bulk discount, instead of using the perimeter to calculate the price, you need to use the **number of sides** each region has. Each straight section of fence counts as a side, regardless of how long it is. | ||
|
||
Consider this example again: | ||
|
||
``` | ||
AAAA | ||
BBCD | ||
BBCC | ||
EEEC | ||
``` | ||
|
||
The region containing type `A` plants has `4` sides, as does each of the regions containing plants of type `B`, `D`, and `E`. However, the more complex region containing the plants of type `C` has `8` sides! | ||
|
||
Using the new method of calculating the per-region price by multiplying the region's area by its number of sides, regions `A` through `E` have prices `16`, `16`, `32`, `4`, and `12`, respectively, for a total price of *`80`*. | ||
|
||
The second example above (full of type `X` and `O` plants) would have a total price of `436`. | ||
|
||
Here's a map that includes an `E`-shaped region full of type `E` plants: | ||
|
||
``` | ||
EEEEE | ||
EXXXX | ||
EEEEE | ||
EXXXX | ||
EEEEE | ||
``` | ||
|
||
The `E`-shaped region has an area of `17` and `12` sides for a price of `204`. Including the two regions full of type `X` plants, this map has a total price of `236`. | ||
|
||
This map has a total price of `368`: | ||
|
||
``` | ||
AAAAAA | ||
AAABBA | ||
AAABBA | ||
ABBAAA | ||
ABBAAA | ||
AAAAAA | ||
``` | ||
|
||
It includes two regions full of type `B` plants (each with `4` sides) and a single region full of type `A` plants (with `4` sides on the outside and `8` more sides on the inside, a total of `12` sides). Be especially careful when counting the fence around regions like the one full of type `A` plants; in particular, each section of fence has an in-side and an out-side, so the fence does not connect across the middle of the region (where the two `B` regions touch diagonally). (The Elves would have used the Möbius Fencing Company instead, but their contract terms were too one-sided.) | ||
|
||
The larger example from before now has the following updated prices: | ||
|
||
* A region of `R` plants with price `12 * 10 = 120`. | ||
* A region of `I` plants with price `4 * 4 = 16`. | ||
* A region of `C` plants with price `14 * 22 = 308`. | ||
* A region of `F` plants with price `10 * 12 = 120`. | ||
* A region of `V` plants with price `13 * 10 = 130`. | ||
* A region of `J` plants with price `11 * 12 = 132`. | ||
* A region of `C` plants with price `1 * 4 = 4`. | ||
* A region of `E` plants with price `13 * 8 = 104`. | ||
* A region of `I` plants with price `14 * 16 = 224`. | ||
* A region of `M` plants with price `5 * 6 = 30`. | ||
* A region of `S` plants with price `3 * 6 = 18`. | ||
|
||
Adding these together produces its new total price of **1206**. | ||
|
||
**What is the new total price of fencing all regions on your map?** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,18 @@ | ||
mod part1; | ||
mod part2; | ||
|
||
pub fn solve_part1_example() -> u32 { | ||
part1::solve(include_str!("../example.txt")) | ||
} | ||
|
||
pub fn solve_part1() -> u32 { | ||
part1::solve(include_str!("../input.txt")) | ||
} | ||
|
||
pub fn solve_part2_example() -> u32 { | ||
part2::solve(include_str!("../example.txt")) | ||
} | ||
|
||
pub fn solve_part2() -> u32 { | ||
part2::solve(include_str!("../input.txt")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
use std::collections::{HashMap, HashSet}; | ||
use crate::part1::{Coordinate, Region}; | ||
|
||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] | ||
enum Side { | ||
Up, | ||
Down, | ||
Left, | ||
Right, | ||
} | ||
|
||
impl Coordinate { | ||
fn neighbour_on_side(&self, side: Side) -> Self { | ||
match side { | ||
Side::Up => {Coordinate::new(self.horizontal, self.vertical-1)} | ||
Side::Down => {Coordinate::new(self.horizontal, self.vertical+1)} | ||
Side::Left => {Coordinate::new(self.horizontal-1, self.vertical)} | ||
Side::Right => {Coordinate::new(self.horizontal+1, self.vertical)} | ||
} | ||
} | ||
} | ||
|
||
impl Region { | ||
fn sides(&self) -> u32 { | ||
let mut side_set: HashSet<(Coordinate, Side)> = HashSet::new(); | ||
|
||
for plot in &self.plots { | ||
for s in [Side::Up, Side::Down, Side::Left, Side::Right] { | ||
if !self.plots.contains(&plot.neighbour_on_side(s)) { | ||
side_set.insert((*plot, s)); | ||
} | ||
} | ||
} | ||
|
||
let mut grouped_sides: HashMap<(Coordinate,Side), i32> = HashMap::new(); | ||
for side_entry in side_set.iter() { | ||
let mut current = side_entry.0; | ||
|
||
match side_entry.1 { | ||
Side::Up|Side::Down => { | ||
let mut to_the_left = current.neighbour_on_side(Side::Left); | ||
// find leftmost | ||
while side_set.contains(&(to_the_left, side_entry.1)) { | ||
current = to_the_left; | ||
to_the_left = current.neighbour_on_side(Side::Left); | ||
} | ||
|
||
// current is the leftmost coordinate for the side. side_entry.1 is either | ||
// Up or Down. | ||
let key = (current, side_entry.1); | ||
|
||
// if we have found one of the other wall pieces of the same wall, we should get | ||
// to the same key because everything is normalised to the left and to bottom | ||
if grouped_sides.contains_key(&key) { | ||
continue; | ||
} | ||
|
||
let mut side_length = 1; | ||
let mut to_the_right = current.neighbour_on_side(Side::Right); | ||
|
||
// once we moved all the way to the left, check that if the space to the right | ||
// also has the same border. | ||
while side_set.contains(&(to_the_right, side_entry.1)) { | ||
current = to_the_right; | ||
to_the_right = current.neighbour_on_side(Side::Right); | ||
side_length += 1; | ||
} | ||
|
||
grouped_sides.insert(key, side_length); | ||
} | ||
Side::Left|Side::Right => { | ||
// find the bottom most | ||
let mut below = current.neighbour_on_side(Side::Down); | ||
while side_set.contains(&(below, side_entry.1)) { | ||
current = below; | ||
below = current.neighbour_on_side(Side::Down); | ||
} | ||
|
||
// current is the leftmost coordinate for the side. side_entry.1 is either | ||
// Left or Right. | ||
let key = (current, side_entry.1); | ||
|
||
// if we have found one of the other wall pieces of the same wall, we should get | ||
// to the same key because everything is normalised to the left and to bottom | ||
if grouped_sides.contains_key(&key) { | ||
continue; | ||
} | ||
|
||
let mut side_length = 1; | ||
let mut above = current.neighbour_on_side(Side::Up); | ||
while side_set.contains(&(above, side_entry.1)) { | ||
current = above; | ||
above = current.neighbour_on_side(Side::Up); | ||
side_length += 1; | ||
} | ||
|
||
grouped_sides.insert(key, side_length); | ||
} | ||
} | ||
} | ||
|
||
grouped_sides.len() as u32 | ||
} | ||
} | ||
|
||
pub(crate) fn solve(input: &str) -> u32 { | ||
let lines = input.trim().lines(); | ||
let mut map: HashMap<Coordinate, String> = HashMap::new(); | ||
|
||
for (height, line) in lines.enumerate() { | ||
for (width, c) in line.chars().enumerate() { | ||
map.insert(Coordinate::new(width as i32, height as i32), c.to_string()); | ||
} | ||
} | ||
|
||
let mut visited: HashSet<Coordinate> = HashSet::new(); | ||
let mut regions : Vec<Region> = Vec::new(); | ||
|
||
for coord in map.keys() { | ||
let region = crate::part1::flood_fill(&map, *coord, map.get(coord).unwrap(), &mut visited); | ||
|
||
regions.push(Region::new(region)); | ||
} | ||
|
||
let regions: Vec<&Region> = regions.iter().filter(|&r| !r.plots.is_empty()).collect(); | ||
|
||
let mut sum = 0; | ||
|
||
for region in regions { | ||
sum += region.sides() * region.area() as u32 | ||
} | ||
// | ||
// if let Some(&ref region) = regions.into_iter().next() { | ||
// if let Some(plot) = region.plots.clone().into_iter().next() { | ||
// println!("looking at region for {:?}:\ncoords:\n{:?}", plot, region.plots); | ||
// | ||
// } | ||
// let sides = region.sides(); | ||
// | ||
// println!("these are the sides: {:?}", sides); | ||
// } | ||
// //c | ||
sum | ||
} | ||
|
||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_group_sides() { | ||
let input = "XX\nXY\n"; | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters