Solve day 4
This commit is contained in:
@@ -35,3 +35,4 @@ Timings are given as: [lower-bound **best-estimate** upper-bound]
|
|||||||
| 01 | [101.34 µs **101.95 µs** 102.61 µs] | [105.90 µs **106.40 µs** 106.95 µs] |
|
| 01 | [101.34 µs **101.95 µs** 102.61 µs] | [105.90 µs **106.40 µs** 106.95 µs] |
|
||||||
| 02 | [2.0990 ms **2.1113 ms** 2.1236 ms] | [2.0954 ms **2.1055 ms** 2.1157 ms] |
|
| 02 | [2.0990 ms **2.1113 ms** 2.1236 ms] | [2.0954 ms **2.1055 ms** 2.1157 ms] |
|
||||||
| 03 | [38.717 µs **39.002 µs** 39.311 µs] | [175.35 µs **176.59 µs** 177.92 µs] |
|
| 03 | [38.717 µs **39.002 µs** 39.311 µs] | [175.35 µs **176.59 µs** 177.92 µs] |
|
||||||
|
| 04 | [233.55 µs **234.88 µs** 236.20 µs] | [3.1026 ms **3.1174 ms** 3.1326 ms] |
|
||||||
|
|||||||
10
src/day04/input/test1.txt
Normal file
10
src/day04/input/test1.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
..@@.@@@@.
|
||||||
|
@@@.@.@.@@
|
||||||
|
@@@@@.@.@@
|
||||||
|
@.@@@@..@.
|
||||||
|
@@.@@@@.@@
|
||||||
|
.@@@@@@@.@
|
||||||
|
.@.@.@.@@@
|
||||||
|
@.@@@.@@@@
|
||||||
|
.@@@@@@@@.
|
||||||
|
@.@.@@@.@.
|
||||||
168
src/day04/mod.rs
Normal file
168
src/day04/mod.rs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
use std::{
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use color_eyre::{Result, eyre::eyre};
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
pub const INPUT: &str = include_str!("input/input.txt");
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum Cell {
|
||||||
|
Empty,
|
||||||
|
Paper,
|
||||||
|
AccessiblePaper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Cell {
|
||||||
|
type Err = color_eyre::Report;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"." => Ok(Cell::Empty),
|
||||||
|
"@" => Ok(Cell::Paper),
|
||||||
|
"x" => Ok(Cell::AccessiblePaper),
|
||||||
|
_ => Err(eyre!("Invalid cell character: {}", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cell {
|
||||||
|
fn from_byte(b: u8) -> Result<Self, color_eyre::Report> {
|
||||||
|
match b {
|
||||||
|
b'.' => Ok(Cell::Empty),
|
||||||
|
b'@' => Ok(Cell::Paper),
|
||||||
|
b'x' => Ok(Cell::AccessiblePaper),
|
||||||
|
_ => Err(eyre!("Invalid cell byte: {}", b)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Grid<const R: usize, const C: usize> {
|
||||||
|
cells: [[Cell; C]; R],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const R: usize, const C: usize> FromStr for Grid<R, C> {
|
||||||
|
type Err = color_eyre::Report;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut cells = [[Cell::Empty; C]; R];
|
||||||
|
|
||||||
|
for (row, line) in s.lines().enumerate() {
|
||||||
|
for (col, byte) in line.bytes().enumerate() {
|
||||||
|
cells[row][col] = Cell::from_byte(byte)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Grid { cells })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const R: usize, const C: usize> Display for Grid<R, C> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
for row in 0..R {
|
||||||
|
for col in 0..C {
|
||||||
|
let symbol = match self.cells[row][col] {
|
||||||
|
Cell::Empty => '.',
|
||||||
|
Cell::Paper => '@',
|
||||||
|
Cell::AccessiblePaper => 'x',
|
||||||
|
};
|
||||||
|
write!(f, "{}", symbol)?;
|
||||||
|
}
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const R: usize, const C: usize> Grid<R, C> {
|
||||||
|
fn get_cell(&self, row: isize, col: isize) -> Option<Cell> {
|
||||||
|
if row >= 0 && col >= 0 && (row as usize) < R && (col as usize) < C {
|
||||||
|
Some(self.cells[row as usize][col as usize])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_accessible_papers(&mut self, replace_with: Cell) -> usize {
|
||||||
|
let mut count = 0;
|
||||||
|
for row in 0..R {
|
||||||
|
for col in 0..C {
|
||||||
|
if self.cells[row][col] != Cell::Paper {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut adjacent_papers = 0;
|
||||||
|
for dr in -1..=1 {
|
||||||
|
for dc in -1..=1 {
|
||||||
|
if dr == 0 && dc == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let adjacent = self
|
||||||
|
.get_cell(row as isize + dr, col as isize + dc)
|
||||||
|
.unwrap_or(Cell::Empty);
|
||||||
|
if adjacent == Cell::Paper || adjacent == Cell::AccessiblePaper {
|
||||||
|
adjacent_papers += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if adjacent_papers < 4 {
|
||||||
|
self.cells[row][col] = replace_with;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_part1<const R: usize, const C: usize>(input: &str) -> Result<usize> {
|
||||||
|
let mut grid = Grid::<R, C>::from_str(input)?;
|
||||||
|
debug!("Parsed grid:\n{}", grid);
|
||||||
|
let count = grid.count_accessible_papers(Cell::AccessiblePaper);
|
||||||
|
debug!("Processed grid:\n{}", grid);
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(input))]
|
||||||
|
pub fn part1(input: &str) -> Result<usize> {
|
||||||
|
solve_part1::<135, 135>(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve_part2<const R: usize, const C: usize>(input: &str) -> Result<usize> {
|
||||||
|
let mut grid = Grid::<R, C>::from_str(input)?;
|
||||||
|
debug!("Parsed grid:\n{}", grid);
|
||||||
|
let mut count = 0;
|
||||||
|
loop {
|
||||||
|
let removed = grid.count_accessible_papers(Cell::Empty);
|
||||||
|
if removed == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
debug!("Removed {} in grid:\n{}", removed, grid);
|
||||||
|
count += removed;
|
||||||
|
}
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(input))]
|
||||||
|
pub fn part2(input: &str) -> Result<usize> {
|
||||||
|
solve_part2::<135, 135>(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use test_log::test;
|
||||||
|
|
||||||
|
const TEST_INPUT1: &str = include_str!("input/test1.txt");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part1() {
|
||||||
|
assert_eq!(solve_part1::<10, 10>(TEST_INPUT1).unwrap(), 13);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_part2() {
|
||||||
|
assert_eq!(solve_part2::<10, 10>(TEST_INPUT1).unwrap(), 43);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ macro_rules! all_days {
|
|||||||
1 => day01,
|
1 => day01,
|
||||||
2 => day02,
|
2 => day02,
|
||||||
3 => day03,
|
3 => day03,
|
||||||
|
4 => day04,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod day01;
|
pub mod day01;
|
||||||
pub mod day02;
|
pub mod day02;
|
||||||
pub mod day03;
|
pub mod day03;
|
||||||
|
pub mod day04;
|
||||||
pub mod days;
|
pub mod days;
|
||||||
|
|||||||
Reference in New Issue
Block a user