1
Fork 0
advent-of-code/source/year_2020/day_11/grid.rs

182 lines
4.5 KiB
Rust
Raw Permalink Normal View History

2024-01-14 21:04:10 +00:00
//! [`Grid`], [`Cell`] and [`Ruleset`] code.
/// The different types of cell available in the [`Grid`].
2022-10-03 16:02:40 +00:00
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Cell {
2024-01-14 21:04:10 +00:00
/// The cell is an edge of the grid.
2022-10-03 16:02:40 +00:00
Edge,
2024-01-14 21:04:10 +00:00
/// The cell is a floor tile.
2022-10-03 16:02:40 +00:00
Floor,
2024-01-14 21:04:10 +00:00
/// The cell is an empty seat.
2022-10-03 16:02:40 +00:00
Empty,
2024-01-14 21:04:10 +00:00
/// The cell is an occupied seat.
2022-10-03 16:02:40 +00:00
Occupied,
}
2024-01-14 21:04:10 +00:00
/// The different rulesets for part one and two.
2022-10-03 16:02:40 +00:00
#[derive(Debug, Eq, PartialEq)]
pub enum Ruleset {
2024-01-14 21:04:10 +00:00
/// The ruleset for part one.
2022-10-03 16:02:40 +00:00
PartOne,
2024-01-14 21:04:10 +00:00
/// The ruleset for part two.
2022-10-03 16:02:40 +00:00
PartTwo,
}
impl From<char> for Cell {
fn from(input: char) -> Self {
match input {
'@' => Self::Edge,
'.' => Self::Floor,
'L' => Self::Empty,
'#' => Self::Occupied,
_ => unreachable!("{input}"),
}
}
}
2024-01-14 21:04:10 +00:00
/// The grid of seats.
2022-10-03 16:02:40 +00:00
#[derive(Debug)]
pub struct Grid {
2024-01-14 21:04:10 +00:00
/// The length of lines from the puzzle input.
2022-10-03 16:02:40 +00:00
pub line_length: isize,
2024-01-14 21:04:10 +00:00
/// The amount of [`Cell`]s that are occupied.
2022-10-03 16:02:40 +00:00
pub occupied_cell_count: usize,
2024-01-14 21:04:10 +00:00
/// How tolerant people are for seats to become empty.
2022-10-03 16:02:40 +00:00
pub occupied_cell_tolerance: usize,
2024-01-14 21:04:10 +00:00
/// The list of [`Cell`]s.
2022-10-03 16:02:40 +00:00
pub cells: Vec<Cell>,
2024-01-14 21:04:10 +00:00
/// Which [`Ruleset`] is being used.
2022-10-03 16:02:40 +00:00
pub ruleset: Ruleset,
}
impl Grid {
2024-01-14 21:04:10 +00:00
/// Create a new grid based on the puzzle input and which [`Ruleset`] to use.
2022-10-03 16:02:40 +00:00
pub fn new(input: &str, ruleset: Ruleset) -> Self {
let line_length = input.find('\n').unwrap() + 2;
// Deal with edge cases by just adding an extra cell to the outer edges.
let extra_floor = "@".repeat(line_length - 2);
let data = format!("{}\n{}\n{}", extra_floor, input, extra_floor);
let cells = data
.trim()
.replace('\n', "@@")
.chars()
.map(Into::into)
.collect();
let occupied_cell_tolerance = match ruleset {
Ruleset::PartOne => 4,
Ruleset::PartTwo => 5,
};
Self {
line_length: line_length as isize,
occupied_cell_count: 0,
occupied_cell_tolerance,
cells,
ruleset,
}
}
2024-01-14 21:04:10 +00:00
/// Simulate a single step and return the new list of [`Cell`]s.
2022-10-03 16:02:40 +00:00
pub fn simulate_step(&self) -> Vec<Cell> {
let mut cells = self.cells.clone();
for (index, cell) in self.cells.iter().enumerate() {
let index = index as isize;
let mut occupied_cells = 0;
let adjacencies = vec![
// Top Left
-self.line_length - 1,
// Above
-self.line_length,
// Top Right
-self.line_length + 1,
// Left
-1,
// Right
1,
// Bottom Left
self.line_length - 1,
// Below
self.line_length,
// Bottom Right
self.line_length + 1,
];
if self.ruleset == Ruleset::PartOne {
for mut adjacency in adjacencies {
adjacency += index;
if adjacency < 0 {
continue;
}
if self.cells.get(adjacency as usize) == Some(&Cell::Occupied) {
occupied_cells += 1;
}
}
} else if self.ruleset == Ruleset::PartTwo {
for adjacency in adjacencies {
let mut target_index = index;
'inner: loop {
target_index += adjacency;
if target_index < 0 || target_index as usize > self.cells.len() {
break 'inner;
}
match self.cells.get(target_index as usize) {
Some(&Cell::Empty) | Some(&Cell::Edge) => break 'inner,
Some(&Cell::Occupied) => {
occupied_cells += 1;
break 'inner;
}
_ => (),
};
}
}
}
if cell == &Cell::Edge || cell == &Cell::Floor {
continue;
}
if cell == &Cell::Empty && occupied_cells == 0 {
cells[index as usize] = Cell::Occupied;
}
if cell == &Cell::Occupied
&& occupied_cells >= self.occupied_cell_tolerance
{
cells[index as usize] = Cell::Empty;
}
}
cells
}
2024-01-14 21:04:10 +00:00
/// Count the amount of [`Cell`]s matching a given target.
2022-10-03 16:02:40 +00:00
pub fn count_cells(&self, target: Cell) -> usize {
self.cells.iter().filter(|cell| cell == &&target).count()
}
2024-01-14 21:04:10 +00:00
/// Draw the grid, used for debugging.
2022-10-03 16:02:40 +00:00
pub fn _draw(&self) -> String {
let mut result = String::new();
for (index, cell) in self.cells.iter().enumerate() {
if index % self.line_length as usize == 0 {
result += "\n";
}
result += match cell {
Cell::Edge => "@",
Cell::Floor => ".",
Cell::Empty => "L",
Cell::Occupied => "#",
};
}
result
}
}