1
0
www.mikescher.com/www/statics/aoc/2020/11_solution.rs

249 lines
6.5 KiB
Rust

use crate::common::AdventOfCodeDay;
use std::fmt::Display;
#[derive(Debug, PartialEq, Clone)]
enum BoardCell {
Floor,
Empty,
Full,
}
#[derive(Clone)]
struct Board {
cells: Vec<Vec<BoardCell>>,
width: usize,
height: usize,
}
impl Board {
fn parse(dat: &str) -> Board {
Board {
height: dat.lines().count(),
width: dat.lines().next().unwrap().len(),
cells: dat.lines().map(Board::parse_line).collect()
}
}
fn parse_line(dat: &str) -> Vec<BoardCell> {
dat.chars().map(|c| match c {
'.' => BoardCell::Floor,
'L' => BoardCell::Empty,
'#' => BoardCell::Full,
_ => panic!(),
}).collect()
}
fn adjac(&self, x: i32, y: i32) -> u32 {
let mut c = 0;
for dx in -1..=1 {
for dy in -1..=1 {
if dx == 0 && dy == 0 {
continue;
}
if x+dx < 0 || y+dy < 0 || x+dx >= self.width as i32 || y+dy >= self.height as i32 {
continue;
}
if self.cells[(y+dy) as usize][(x+dx) as usize] == BoardCell::Full {
c+=1;
}
}
}
return c;
}
fn adjac2(&self, x: i32, y: i32) -> u32 {
let mut c = 0;
for dx in -1..=1 {
for dy in -1..=1 {
if dx == 0 && dy == 0 {
continue;
}
if x+dx < 0 || y+dy < 0 || x+dx >= self.width as i32 || y+dy >= self.height as i32 {
continue;
}
if self.adjac_ray(x, y, dx, dy) {
c+=1;
}
}
}
return c;
}
fn adjac_ray(&self, x : i32, y: i32, dx: i32, dy: i32) -> bool {
for i in 1.. {
let rx = x + dx * i;
let ry = y + dy * i;
if rx < 0 || ry < 0 || rx >= self.width as i32 || ry >= self.height as i32 {
return false;
}
if self.cells[ry as usize][rx as usize] == BoardCell::Full {
return true;
}
if self.cells[ry as usize][rx as usize] == BoardCell::Empty {
return false;
}
}
panic!();
}
fn step(&self) -> Board {
let mut nc = self.cells.clone();
for y in 0..self.height {
for x in 0..self.width {
if self.cells[y][x] == BoardCell::Full {
if self.adjac(x as i32, y as i32) >= 4 {
nc[y][x] = BoardCell::Empty; // If a seat is occupied (#) and four or more seats adjacent to it are also occupied, the seat becomes empty.
}
} else if self.cells[y][x] == BoardCell::Empty {
if self.adjac(x as i32, y as i32) == 0 {
nc[y][x] = BoardCell::Full; // If a seat is empty (L) and there are no occupied seats adjacent to it, the seat becomes occupied.
}
}
}
}
Board {
width: self.width,
height: self.height,
cells: nc,
}
}
fn step2(&self) -> Board {
let mut nc = self.cells.clone();
for y in 0..self.height {
for x in 0..self.width {
if self.cells[y][x] == BoardCell::Full {
if self.adjac2(x as i32, y as i32) >= 5 {
nc[y][x] = BoardCell::Empty; // it now takes five or more visible occupied seats for an occupied seat to become empty
}
} else if self.cells[y][x] == BoardCell::Empty {
if self.adjac2(x as i32, y as i32) == 0 {
nc[y][x] = BoardCell::Full; // If a seat is empty (L) and there are no occupied seats adjacent to it, the seat becomes occupied.
}
}
}
}
Board {
width: self.width,
height: self.height,
cells: nc,
}
}
fn total_occupied(&self) -> u32 {
self.cells.iter().map(|p| p.iter().filter(|p| **p == BoardCell::Full).count() as u32).sum()
}
}
impl PartialEq for Board {
fn eq(&self, other: &Self) -> bool {
if self.width != other.width {
return false;
}
if self.height != other.height {
return false;
}
for y in 0..self.height {
for x in 0..self.width {
if self.cells[y][x] != other.cells[y][x] {
return false;
}
}
}
return true;
}
}
impl Display for Board {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut r = String::with_capacity(self.width * self.height + self.height + 1);
for y in 0..self.height {
for x in 0..self.width {
r.push_str(match self.cells[y][x] {
BoardCell::Floor => ".",
BoardCell::Empty => "L",
BoardCell::Full => "#",
});
}
r.push_str("\n");
}
writeln!(f, "{}", r)
}
}
pub struct Day11 {
input: Board,
}
impl Day11 {
pub fn new() -> Self {
let input_bytes = include_bytes!("../res/11_input.txt");
let input_str = String::from_utf8_lossy(input_bytes);
Self {
input: Board::parse(&input_str)
}
}
}
impl AdventOfCodeDay for Day11 {
fn task_1(&self) -> String {
verboseln!("{}", self.input);
verboseln!("> Initial");
let mut board = self.input.clone();
loop {
let newboard = board.step();
verboseln!("{}", newboard);
verboseln!("> {}", newboard.total_occupied());
verboseln!();
if newboard == board {
return newboard.total_occupied().to_string();
}
board = newboard;
}
}
fn task_2(&self) -> String {
verboseln!("{}", self.input);
verboseln!("> Initial");
let mut board = self.input.clone();
loop {
let newboard = board.step2();
verboseln!("{}", newboard);
verboseln!("> {}", newboard.total_occupied());
verboseln!();
if newboard == board {
return newboard.total_occupied().to_string();
}
board = newboard;
}
}
}