Compare commits
2 commits
5eb76e73ca
...
c473ee4fc7
Author | SHA1 | Date | |
---|---|---|---|
c473ee4fc7 | |||
743f1e46fc |
67
src/day_11/mod.rs
Normal file
67
src/day_11/mod.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
mod model;
|
||||
mod parsing;
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
pub use model::OctopusGrid;
|
||||
pub use parsing::parse_octopus_grid;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[aoc_generator(day11)]
|
||||
pub fn parse_input(input: &str) -> OctopusGrid {
|
||||
parse_octopus_grid(&mut input.into_tokens()).unwrap()
|
||||
}
|
||||
|
||||
#[aoc(day11, part1)]
|
||||
pub fn part1(input: &OctopusGrid) -> usize {
|
||||
let mut grid = input.clone();
|
||||
let mut sum = 0;
|
||||
for _ in 0..100 {
|
||||
sum += grid.step();
|
||||
}
|
||||
sum
|
||||
}
|
||||
|
||||
#[aoc(day11, part2)]
|
||||
pub fn part2(input: &OctopusGrid) -> usize {
|
||||
let mut grid = input.clone();
|
||||
let mut counter = 0;
|
||||
loop {
|
||||
counter += 1;
|
||||
if grid.step() == 100 {
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const EXAMPLE_INPUT: &str = "5483143223
|
||||
2745854711
|
||||
5264556173
|
||||
6141336146
|
||||
6357385478
|
||||
4167524645
|
||||
2176841721
|
||||
6882881134
|
||||
4846848554
|
||||
5283751526";
|
||||
const RESULT_PART_1: usize = 1656;
|
||||
const RESULT_PART_2: usize = 195;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example() {
|
||||
super::parse_input(EXAMPLE_INPUT);
|
||||
}
|
||||
}
|
85
src/day_11/model.rs
Normal file
85
src/day_11/model.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use itertools::Itertools;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct OctopusGrid {
|
||||
pub grid: [[u8; 10]; 10],
|
||||
}
|
||||
|
||||
impl OctopusGrid {
|
||||
pub fn step(&mut self) -> usize {
|
||||
let mut flash_grid: [[bool; 10]; 10] = Default::default();
|
||||
grid_iter().for_each(|(x, y)| self.grid[y][x] += 1);
|
||||
let mut flash_count = 0;
|
||||
loop {
|
||||
grid_iter().for_each(|(x, y)| {
|
||||
if self.grid[y][x] > 9 && !flash_grid[y][x] {
|
||||
flash_grid[y][x] = true;
|
||||
surrounding((x, y)).for_each(|(x, y)| self.grid[y][x] += 1);
|
||||
}
|
||||
});
|
||||
let new_flash_count = flash_grid
|
||||
.iter()
|
||||
.flat_map(|col| col.iter())
|
||||
.filter(|val| **val)
|
||||
.count();
|
||||
if new_flash_count == flash_count {
|
||||
break;
|
||||
} else {
|
||||
flash_count = new_flash_count;
|
||||
}
|
||||
}
|
||||
grid_iter().for_each(|(x, y)| {
|
||||
if flash_grid[y][x] {
|
||||
self.grid[y][x] = 0;
|
||||
}
|
||||
});
|
||||
flash_count
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for OctopusGrid {
|
||||
fn to_string(&self) -> String {
|
||||
self.grid
|
||||
.iter()
|
||||
.map(|line| line.iter().map(u8::to_string).collect::<String>())
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
fn surrounding((x, y): (usize, usize)) -> impl Iterator<Item = (usize, usize)> {
|
||||
let (x, y) = (x as isize, y as isize);
|
||||
(-1..=1)
|
||||
.cartesian_product(-1..=1)
|
||||
.filter_map(move |(x_off, y_off)| {
|
||||
if x + x_off >= 0
|
||||
&& x + x_off < 10
|
||||
&& y + y_off >= 0
|
||||
&& y + y_off < 10
|
||||
&& (x_off != 0 || y_off != 0)
|
||||
{
|
||||
Some(((x + x_off) as usize, (y + y_off) as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn grid_iter() -> impl Iterator<Item = (usize, usize)> {
|
||||
(0..10).cartesian_product(0..10)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::OctopusGrid;
|
||||
|
||||
#[test]
|
||||
fn flash() {
|
||||
let mut grid = OctopusGrid {
|
||||
grid: Default::default(),
|
||||
};
|
||||
for _ in 0..9 {
|
||||
assert_eq!(grid.step(), 0);
|
||||
}
|
||||
assert_eq!(grid.step(), 100);
|
||||
}
|
||||
}
|
14
src/day_11/parsing.rs
Normal file
14
src/day_11/parsing.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use yap::Tokens;
|
||||
|
||||
use crate::parsing::{newline, parse_digit, parse_n};
|
||||
|
||||
use super::OctopusGrid;
|
||||
|
||||
pub fn parse_octopus_grid(tokens: &mut impl Tokens<Item = char>) -> Option<OctopusGrid> {
|
||||
parse_n(
|
||||
tokens,
|
||||
&|t| parse_n(t, &|t| parse_digit(t), &|_| true),
|
||||
&|t| newline(t),
|
||||
)
|
||||
.map(|grid| OctopusGrid { grid })
|
||||
}
|
|
@ -12,5 +12,6 @@ pub mod day_07;
|
|||
pub mod day_08;
|
||||
pub mod day_09;
|
||||
pub mod day_10;
|
||||
pub mod day_11;
|
||||
|
||||
aoc_lib! { year = 2021 }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use num::Num;
|
||||
use std::fmt::Debug;
|
||||
use yap::{IntoTokens, Tokens};
|
||||
pub fn space(tokens: &mut impl Tokens<Item = char>) -> bool {
|
||||
tokens.token(' ')
|
||||
|
@ -36,6 +37,19 @@ pub fn parse_number_with_radix<T: Num>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_n<T: Debug, P: Tokens<Item = char>, const N: usize>(
|
||||
tokens: &mut P,
|
||||
parser: &dyn Fn(&mut P) -> Option<T>,
|
||||
separator: &dyn Fn(&mut P) -> bool,
|
||||
) -> Option<[T; N]> {
|
||||
let elements: Vec<T> = tokens.sep_by(parser, separator).collect();
|
||||
if elements.len() != 10 {
|
||||
None
|
||||
} else {
|
||||
Some(elements.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use yap::IntoTokens;
|
||||
|
|
Loading…
Reference in a new issue