Day 11 part 2 solution
This commit is contained in:
parent
63850f082b
commit
1a7666783d
@ -84,6 +84,112 @@
|
|||||||
//! At this point, something interesting happens: the chaos stabilizes and further applications of these rules cause no seats to change state! Once people stop moving around, you count 37 occupied seats.
|
//! At this point, something interesting happens: the chaos stabilizes and further applications of these rules cause no seats to change state! Once people stop moving around, you count 37 occupied seats.
|
||||||
//!
|
//!
|
||||||
//! Simulate your seating area by applying the seating rules repeatedly until no seats change state. How many seats end up occupied?
|
//! Simulate your seating area by applying the seating rules repeatedly until no seats change state. How many seats end up occupied?
|
||||||
|
//!
|
||||||
|
//! --- Part Two ---
|
||||||
|
//! As soon as people start to arrive, you realize your mistake. People don't just care about adjacent seats - they care about the first seat they can see in each of those eight directions!
|
||||||
|
//!
|
||||||
|
//! Now, instead of considering just the eight immediately adjacent seats, consider the first seat in each of those eight directions. For example, the empty seat below would see eight occupied seats:
|
||||||
|
//!
|
||||||
|
//! .......#.
|
||||||
|
//! ...#.....
|
||||||
|
//! .#.......
|
||||||
|
//! .........
|
||||||
|
//! ..#L....#
|
||||||
|
//! ....#....
|
||||||
|
//! .........
|
||||||
|
//! #........
|
||||||
|
//! ...#.....
|
||||||
|
//! The leftmost empty seat below would only see one empty seat, but cannot see any of the occupied ones:
|
||||||
|
//!
|
||||||
|
//! .............
|
||||||
|
//! .L.L.#.#.#.#.
|
||||||
|
//! .............
|
||||||
|
//! The empty seat below would see no occupied seats:
|
||||||
|
//!
|
||||||
|
//! .##.##.
|
||||||
|
//! #.#.#.#
|
||||||
|
//! ##...##
|
||||||
|
//! ...L...
|
||||||
|
//! ##...##
|
||||||
|
//! #.#.#.#
|
||||||
|
//! .##.##.
|
||||||
|
//! Also, people seem to be more tolerant than you expected: it now takes five or more visible occupied seats for an occupied seat to become empty (rather than four or more from the previous rules). The other rules still apply: empty seats that see no occupied seats become occupied, seats matching no rule don't change, and floor never changes.
|
||||||
|
//!
|
||||||
|
//! Given the same starting layout as above, these new rules cause the seating area to shift around as follows:
|
||||||
|
//!
|
||||||
|
//! L.LL.LL.LL
|
||||||
|
//! LLLLLLL.LL
|
||||||
|
//! L.L.L..L..
|
||||||
|
//! LLLL.LL.LL
|
||||||
|
//! L.LL.LL.LL
|
||||||
|
//! L.LLLLL.LL
|
||||||
|
//! ..L.L.....
|
||||||
|
//! LLLLLLLLLL
|
||||||
|
//! L.LLLLLL.L
|
||||||
|
//! L.LLLLL.LL
|
||||||
|
//! #.##.##.##
|
||||||
|
//! #######.##
|
||||||
|
//! #.#.#..#..
|
||||||
|
//! ####.##.##
|
||||||
|
//! #.##.##.##
|
||||||
|
//! #.#####.##
|
||||||
|
//! ..#.#.....
|
||||||
|
//! ##########
|
||||||
|
//! #.######.#
|
||||||
|
//! #.#####.##
|
||||||
|
//! #.LL.LL.L#
|
||||||
|
//! #LLLLLL.LL
|
||||||
|
//! L.L.L..L..
|
||||||
|
//! LLLL.LL.LL
|
||||||
|
//! L.LL.LL.LL
|
||||||
|
//! L.LLLLL.LL
|
||||||
|
//! ..L.L.....
|
||||||
|
//! LLLLLLLLL#
|
||||||
|
//! #.LLLLLL.L
|
||||||
|
//! #.LLLLL.L#
|
||||||
|
//! #.L#.##.L#
|
||||||
|
//! #L#####.LL
|
||||||
|
//! L.#.#..#..
|
||||||
|
//! ##L#.##.##
|
||||||
|
//! #.##.#L.##
|
||||||
|
//! #.#####.#L
|
||||||
|
//! ..#.#.....
|
||||||
|
//! LLL####LL#
|
||||||
|
//! #.L#####.L
|
||||||
|
//! #.L####.L#
|
||||||
|
//! #.L#.L#.L#
|
||||||
|
//! #LLLLLL.LL
|
||||||
|
//! L.L.L..#..
|
||||||
|
//! ##LL.LL.L#
|
||||||
|
//! L.LL.LL.L#
|
||||||
|
//! #.LLLLL.LL
|
||||||
|
//! ..L.L.....
|
||||||
|
//! LLLLLLLLL#
|
||||||
|
//! #.LLLLL#.L
|
||||||
|
//! #.L#LL#.L#
|
||||||
|
//! #.L#.L#.L#
|
||||||
|
//! #LLLLLL.LL
|
||||||
|
//! L.L.L..#..
|
||||||
|
//! ##L#.#L.L#
|
||||||
|
//! L.L#.#L.L#
|
||||||
|
//! #.L####.LL
|
||||||
|
//! ..#.#.....
|
||||||
|
//! LLL###LLL#
|
||||||
|
//! #.LLLLL#.L
|
||||||
|
//! #.L#LL#.L#
|
||||||
|
//! #.L#.L#.L#
|
||||||
|
//! #LLLLLL.LL
|
||||||
|
//! L.L.L..#..
|
||||||
|
//! ##L#.#L.L#
|
||||||
|
//! L.L#.LL.L#
|
||||||
|
//! #.LLLL#.LL
|
||||||
|
//! ..#.L.....
|
||||||
|
//! LLL###LLL#
|
||||||
|
//! #.LLLLL#.L
|
||||||
|
//! #.L#LL#.L#
|
||||||
|
//! Again, at this point, people stop shifting around and the seating area reaches equilibrium. Once this occurs, you count 26 occupied seats.
|
||||||
|
//!
|
||||||
|
//! Given the new visibility method and the rule change for occupied seats becoming empty, once equilibrium is reached, how many seats end up occupied?
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -233,12 +339,68 @@ impl Map {
|
|||||||
cnt
|
cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Counts number of occupied seats in 8 cardinal directions. Stops if it hits an empty seat.
|
||||||
|
fn line_of_sight_count(&self, x: usize, y: usize) -> usize {
|
||||||
|
let incs = vec![
|
||||||
|
// Right
|
||||||
|
(1, 0),
|
||||||
|
// Left
|
||||||
|
(-1, 0),
|
||||||
|
// Up
|
||||||
|
(0, -1),
|
||||||
|
// Down
|
||||||
|
(0, 1),
|
||||||
|
// Up-right
|
||||||
|
(1, -1),
|
||||||
|
// Up-left
|
||||||
|
(-1, -1),
|
||||||
|
// Down-right
|
||||||
|
(1, 1),
|
||||||
|
// Down-left
|
||||||
|
(-1, 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
incs.into_iter()
|
||||||
|
.map(|inc| self.shoot(x, y, inc))
|
||||||
|
.filter(|&v| v)
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over the map using the offsets until it hits an occupied seat or edge.
|
||||||
|
/// If an occupied seat is found before an unoccupied seat or edge, true is returned.
|
||||||
|
/// If an unoccupied seat is found before an occupied seat or edge, false is returned.
|
||||||
|
/// If an edge is hit, false is returned.
|
||||||
|
/// Floors are ignored.
|
||||||
|
fn shoot(&self, x: usize, y: usize, (x_off, y_off): (isize, isize)) -> bool {
|
||||||
|
let mut x = x as isize;
|
||||||
|
let mut y = y as isize;
|
||||||
|
let width = self.width as isize;
|
||||||
|
let height = self.height as isize;
|
||||||
|
loop {
|
||||||
|
x = x + x_off;
|
||||||
|
y = y + y_off;
|
||||||
|
|
||||||
|
// Hit an edge.
|
||||||
|
if x < 0 || y < 0 || x >= width || y >= height {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = self[(x as usize, y as usize)];
|
||||||
|
if let State::Empty = s {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let State::Occupied = s {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn occupied_count(&self) -> usize {
|
fn occupied_count(&self) -> usize {
|
||||||
self.cells.iter().filter(|&c| c == &State::Occupied).count()
|
self.cells.iter().filter(|&c| c == &State::Occupied).count()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn step(map: &Map) -> Map {
|
fn step_solution1(map: &Map) -> Map {
|
||||||
let mut new_m = Map::new(map.width, map.height);
|
let mut new_m = Map::new(map.width, map.height);
|
||||||
for y in 0..map.height {
|
for y in 0..map.height {
|
||||||
for x in 0..map.width {
|
for x in 0..map.width {
|
||||||
@ -258,6 +420,26 @@ fn step(map: &Map) -> Map {
|
|||||||
new_m
|
new_m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn step_solution2(map: &Map) -> Map {
|
||||||
|
let mut new_m = Map::new(map.width, map.height);
|
||||||
|
for y in 0..map.height {
|
||||||
|
for x in 0..map.width {
|
||||||
|
// Floor's never change
|
||||||
|
if map[(x, y)] == State::Floor {
|
||||||
|
new_m[(x, y)] = State::Floor;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let new_cell = match map.line_of_sight_count(x, y) {
|
||||||
|
0 => State::Occupied,
|
||||||
|
c if c >= 5 => State::Empty,
|
||||||
|
_ => map[(x, y)],
|
||||||
|
};
|
||||||
|
new_m[(x, y)] = new_cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_m
|
||||||
|
}
|
||||||
|
|
||||||
#[aoc_generator(day11)]
|
#[aoc_generator(day11)]
|
||||||
fn parse(input: &str) -> Map {
|
fn parse(input: &str) -> Map {
|
||||||
input.parse().expect("Failed to parse map")
|
input.parse().expect("Failed to parse map")
|
||||||
@ -265,13 +447,26 @@ fn parse(input: &str) -> Map {
|
|||||||
|
|
||||||
#[aoc(day11, part1)]
|
#[aoc(day11, part1)]
|
||||||
fn solution1(map: &Map) -> usize {
|
fn solution1(map: &Map) -> usize {
|
||||||
let mut prev = step(map);
|
let mut prev = step_solution1(map);
|
||||||
let mut cur = step(&prev);
|
let mut cur = step_solution1(&prev);
|
||||||
while prev != cur {
|
while prev != cur {
|
||||||
// Show map animating.
|
// Show map animating.
|
||||||
// println!("{}", cur);
|
// println!("{}", cur);
|
||||||
prev = cur;
|
prev = cur;
|
||||||
cur = step(&prev);
|
cur = step_solution1(&prev);
|
||||||
|
}
|
||||||
|
cur.occupied_count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day11, part2)]
|
||||||
|
fn solution2(map: &Map) -> usize {
|
||||||
|
let mut prev = step_solution2(map);
|
||||||
|
let mut cur = step_solution2(&prev);
|
||||||
|
while prev != cur {
|
||||||
|
// Show map animating.
|
||||||
|
// println!("{}", cur);
|
||||||
|
prev = cur;
|
||||||
|
cur = step_solution2(&prev);
|
||||||
}
|
}
|
||||||
cur.occupied_count()
|
cur.occupied_count()
|
||||||
}
|
}
|
||||||
@ -370,7 +565,155 @@ mod tests {
|
|||||||
let want: Map = want_input
|
let want: Map = want_input
|
||||||
.parse()
|
.parse()
|
||||||
.expect(&format!("Failed to parse step {}", i));
|
.expect(&format!("Failed to parse step {}", i));
|
||||||
let got = step(&m);
|
let got = step_solution1(&m);
|
||||||
|
assert_eq!(want, got, "step {}\nm {}", i, m);
|
||||||
|
m = got;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn line_of_sight_count() {
|
||||||
|
let test_input = vec![
|
||||||
|
(
|
||||||
|
8,
|
||||||
|
(3, 4),
|
||||||
|
r#".......#.
|
||||||
|
...#.....
|
||||||
|
.#.......
|
||||||
|
.........
|
||||||
|
..#L....#
|
||||||
|
....#....
|
||||||
|
.........
|
||||||
|
#........
|
||||||
|
...#....."#
|
||||||
|
.replace(' ', ""),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
4,
|
||||||
|
(3, 0),
|
||||||
|
r#"#.L#.##.L#
|
||||||
|
#L#####.LL
|
||||||
|
L.#.#..#..
|
||||||
|
##L#.##.##
|
||||||
|
#.##.#L.##
|
||||||
|
#.#####.#L
|
||||||
|
..#.#.....
|
||||||
|
LLL####LL#
|
||||||
|
#.L#####.L
|
||||||
|
#.L####.L#"#
|
||||||
|
.replace(' ', ""),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
(1, 1),
|
||||||
|
r#".............
|
||||||
|
.L.L.#.#.#.#.
|
||||||
|
............."#
|
||||||
|
.replace(' ', ""),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
(3, 3),
|
||||||
|
r#".##.##.
|
||||||
|
#.#.#.#
|
||||||
|
##...##
|
||||||
|
...L...
|
||||||
|
##...##
|
||||||
|
#.#.#.#
|
||||||
|
.##.##."#
|
||||||
|
.replace(' ', ""),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (want, (x, y), input) in test_input {
|
||||||
|
let m: Map = input.parse().expect("Failed to parse map data");
|
||||||
|
assert_eq!(want, m.line_of_sight_count(x, y), "map {}", m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn solution2() {
|
||||||
|
let input = r#"L.LL.LL.LL
|
||||||
|
LLLLLLL.LL
|
||||||
|
L.L.L..L..
|
||||||
|
LLLL.LL.LL
|
||||||
|
L.LL.LL.LL
|
||||||
|
L.LLLLL.LL
|
||||||
|
..L.L.....
|
||||||
|
LLLLLLLLLL
|
||||||
|
L.LLLLLL.L
|
||||||
|
L.LLLLL.LL"#
|
||||||
|
.replace(' ', "");
|
||||||
|
let steps: Vec<_> = vec![
|
||||||
|
r#"#.##.##.##
|
||||||
|
#######.##
|
||||||
|
#.#.#..#..
|
||||||
|
####.##.##
|
||||||
|
#.##.##.##
|
||||||
|
#.#####.##
|
||||||
|
..#.#.....
|
||||||
|
##########
|
||||||
|
#.######.#
|
||||||
|
#.#####.##"#,
|
||||||
|
r#"#.LL.LL.L#
|
||||||
|
#LLLLLL.LL
|
||||||
|
L.L.L..L..
|
||||||
|
LLLL.LL.LL
|
||||||
|
L.LL.LL.LL
|
||||||
|
L.LLLLL.LL
|
||||||
|
..L.L.....
|
||||||
|
LLLLLLLLL#
|
||||||
|
#.LLLLLL.L
|
||||||
|
#.LLLLL.L#"#,
|
||||||
|
r#"#.L#.##.L#
|
||||||
|
#L#####.LL
|
||||||
|
L.#.#..#..
|
||||||
|
##L#.##.##
|
||||||
|
#.##.#L.##
|
||||||
|
#.#####.#L
|
||||||
|
..#.#.....
|
||||||
|
LLL####LL#
|
||||||
|
#.L#####.L
|
||||||
|
#.L####.L#"#,
|
||||||
|
r#"#.L#.L#.L#
|
||||||
|
#LLLLLL.LL
|
||||||
|
L.L.L..#..
|
||||||
|
##LL.LL.L#
|
||||||
|
L.LL.LL.L#
|
||||||
|
#.LLLLL.LL
|
||||||
|
..L.L.....
|
||||||
|
LLLLLLLLL#
|
||||||
|
#.LLLLL#.L
|
||||||
|
#.L#LL#.L#"#,
|
||||||
|
r#"#.L#.L#.L#
|
||||||
|
#LLLLLL.LL
|
||||||
|
L.L.L..#..
|
||||||
|
##L#.#L.L#
|
||||||
|
L.L#.#L.L#
|
||||||
|
#.L####.LL
|
||||||
|
..#.#.....
|
||||||
|
LLL###LLL#
|
||||||
|
#.LLLLL#.L
|
||||||
|
#.L#LL#.L#"#,
|
||||||
|
r#"#.L#.L#.L#
|
||||||
|
#LLLLLL.LL
|
||||||
|
L.L.L..#..
|
||||||
|
##L#.#L.L#
|
||||||
|
L.L#.LL.L#
|
||||||
|
#.LLLL#.LL
|
||||||
|
..#.L.....
|
||||||
|
LLL###LLL#
|
||||||
|
#.LLLLL#.L
|
||||||
|
#.L#LL#.L#"#,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.replace(' ', ""))
|
||||||
|
.collect();
|
||||||
|
let mut m = input.parse().expect("Failed to parse map");
|
||||||
|
for (i, want_input) in steps.iter().enumerate() {
|
||||||
|
let want: Map = want_input
|
||||||
|
.parse()
|
||||||
|
.expect(&format!("Failed to parse step {}", i));
|
||||||
|
let got = step_solution2(&m);
|
||||||
assert_eq!(want, got, "step {}\nm {}", i, m);
|
assert_eq!(want, got, "step {}\nm {}", i, m);
|
||||||
m = got;
|
m = got;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user