Solve day 4 in Rust
This commit is contained in:
parent
3114920494
commit
9fdd0cc28e
@ -4,9 +4,10 @@ use crate::puzzle::Puzzle;
|
||||
use puzzles::day1;
|
||||
use puzzles::day2;
|
||||
use puzzles::day3;
|
||||
use puzzles::day4;
|
||||
use std::fs;
|
||||
|
||||
const PUZZLES: [&dyn SomePuzzle; 3] = [&day1::PUZZLE, &day2::PUZZLE, &day3::PUZZLE];
|
||||
const PUZZLES: [&dyn SomePuzzle; 4] = [&day1::PUZZLE, &day2::PUZZLE, &day3::PUZZLE, &day4::PUZZLE];
|
||||
|
||||
fn main() {
|
||||
[false, true].iter().for_each(|is_real_data| {
|
||||
|
||||
129
rust/puzzles/day4.rs
Normal file
129
rust/puzzles/day4.rs
Normal file
@ -0,0 +1,129 @@
|
||||
use crate::puzzle::Puzzle;
|
||||
use nom::{
|
||||
Parser,
|
||||
branch::alt,
|
||||
character::complete::{char, newline},
|
||||
combinator::{eof, value},
|
||||
error::Error,
|
||||
multi::{many1, separated_list1},
|
||||
sequence::terminated,
|
||||
};
|
||||
|
||||
pub const PUZZLE: Puzzle<Vec<Vec<InTile>>, 2> = Puzzle {
|
||||
number: 4,
|
||||
parser: |input| {
|
||||
terminated::<_, _, Error<&str>, _, _>(
|
||||
terminated(
|
||||
separated_list1(
|
||||
newline,
|
||||
many1(alt((
|
||||
value(InTile::Empty, char('.')),
|
||||
value(InTile::Roll, char('@')),
|
||||
))),
|
||||
),
|
||||
newline,
|
||||
),
|
||||
eof,
|
||||
)
|
||||
.parse(input)
|
||||
.unwrap()
|
||||
.1
|
||||
},
|
||||
parts: [
|
||||
|input| {
|
||||
let initial_rolls = count_rolls(&input);
|
||||
let final_rolls = count_rolls(&remove_accessible_rolls(&find_accessible(&input)));
|
||||
(initial_rolls - final_rolls).to_string()
|
||||
},
|
||||
|input| {
|
||||
let mut grid = input.clone();
|
||||
let initial_rolls = count_rolls(&grid);
|
||||
loop {
|
||||
let out_grid = find_accessible(&grid);
|
||||
if none_accessible(&out_grid) {
|
||||
break;
|
||||
}
|
||||
grid = remove_accessible_rolls(&out_grid);
|
||||
}
|
||||
let final_rolls = count_rolls(&grid);
|
||||
(initial_rolls - final_rolls).to_string()
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum InTile {
|
||||
Empty,
|
||||
Roll,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
enum OutTile {
|
||||
Empty,
|
||||
Roll,
|
||||
Accessible,
|
||||
}
|
||||
|
||||
fn find_accessible(grid: &Vec<Vec<InTile>>) -> Vec<Vec<OutTile>> {
|
||||
grid.iter()
|
||||
.enumerate()
|
||||
.map(|(y, row)| {
|
||||
row.iter()
|
||||
.enumerate()
|
||||
.map(|(x, t)| match t {
|
||||
InTile::Empty => OutTile::Empty,
|
||||
InTile::Roll => {
|
||||
let mut neighbor_rolls = 0;
|
||||
for dx in -1..=1 {
|
||||
for dy in -1..=1 {
|
||||
if dx == 0 && dy == 0 {
|
||||
continue;
|
||||
}
|
||||
if grid
|
||||
.get(y.wrapping_add_signed(dy))
|
||||
.and_then(|r| r.get(x.wrapping_add_signed(dx)))
|
||||
== Some(&InTile::Roll)
|
||||
{
|
||||
neighbor_rolls += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if neighbor_rolls < 4 {
|
||||
OutTile::Accessible
|
||||
} else {
|
||||
OutTile::Roll
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn remove_accessible_rolls(grid: &Vec<Vec<OutTile>>) -> Vec<Vec<InTile>> {
|
||||
grid.iter()
|
||||
.map(|r| {
|
||||
r.iter()
|
||||
.map(|t| {
|
||||
(|tile| match tile {
|
||||
OutTile::Empty => InTile::Empty,
|
||||
OutTile::Roll => InTile::Roll,
|
||||
OutTile::Accessible => InTile::Empty,
|
||||
})(t.clone())
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn none_accessible(grid: &Vec<Vec<OutTile>>) -> bool {
|
||||
!grid
|
||||
.iter()
|
||||
.any(|row| row.iter().any(|t| *t == OutTile::Accessible))
|
||||
}
|
||||
|
||||
fn count_rolls(grid: &Vec<Vec<InTile>>) -> usize {
|
||||
grid.iter()
|
||||
.map(|row| row.iter().filter(|t| **t == InTile::Roll).count())
|
||||
.sum()
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
pub(crate) mod day1;
|
||||
pub(crate) mod day2;
|
||||
pub(crate) mod day3;
|
||||
pub(crate) mod day4;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user