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_08;
|
||||||
pub mod day_09;
|
pub mod day_09;
|
||||||
pub mod day_10;
|
pub mod day_10;
|
||||||
|
pub mod day_11;
|
||||||
|
|
||||||
aoc_lib! { year = 2021 }
|
aoc_lib! { year = 2021 }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use num::Num;
|
use num::Num;
|
||||||
|
use std::fmt::Debug;
|
||||||
use yap::{IntoTokens, Tokens};
|
use yap::{IntoTokens, Tokens};
|
||||||
pub fn space(tokens: &mut impl Tokens<Item = char>) -> bool {
|
pub fn space(tokens: &mut impl Tokens<Item = char>) -> bool {
|
||||||
tokens.token(' ')
|
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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use yap::IntoTokens;
|
use yap::IntoTokens;
|
||||||
|
|
Loading…
Reference in a new issue