Compare commits
2 Commits
faa452149a
...
d49157dd79
| Author | SHA1 | Date | |
|---|---|---|---|
| d49157dd79 | |||
| fa7f62cacf |
39
src/day4.rs
39
src/day4.rs
@@ -1,20 +1,22 @@
|
|||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
use grid::Grid;
|
use grid::Grid;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[aoc_generator(day4)]
|
#[aoc_generator(day4)]
|
||||||
fn parse(input: &str) -> Grid<u8> {
|
fn parse(input: &str) -> Grid<u8> {
|
||||||
input.parse().unwrap()
|
input.parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day4, part1)]
|
#[aoc(day4, part1, Brute)]
|
||||||
fn part1(input: &Grid<u8>) -> u64 {
|
fn part1(input: &Grid<u8>) -> u64 {
|
||||||
(0..input.height() * input.width())
|
(0..input.height() * input.width())
|
||||||
.filter(|i| *input.get(&input.coord(*i as i64).unwrap()).unwrap() == b'@')
|
.filter(|i| *input.get(&input.coord(*i as i64).unwrap()).unwrap() == b'@')
|
||||||
.map(|i| input.neighbours_count(&input.coord(i as i64).unwrap(), |c| *c == b'@'))
|
.map(|i| input.adjacent_count(&input.coord(i as i64).unwrap(), |c| *c == b'@'))
|
||||||
.filter(|n| *n < 4)
|
.filter(|n| *n < 4)
|
||||||
.count() as u64
|
.count() as u64
|
||||||
}
|
}
|
||||||
#[aoc(day4, part2)]
|
|
||||||
|
#[aoc(day4, part2, Brute)]
|
||||||
fn part2(input: &Grid<u8>) -> u64 {
|
fn part2(input: &Grid<u8>) -> u64 {
|
||||||
let mut grid = input.clone();
|
let mut grid = input.clone();
|
||||||
let mut removed = 0;
|
let mut removed = 0;
|
||||||
@@ -24,7 +26,7 @@ fn part2(input: &Grid<u8>) -> u64 {
|
|||||||
for i in 0..grid.width() * grid.height() {
|
for i in 0..grid.width() * grid.height() {
|
||||||
let pos = grid.coord(i as i64).unwrap();
|
let pos = grid.coord(i as i64).unwrap();
|
||||||
if grid.get(&pos).is_some_and(|c| *c == b'@')
|
if grid.get(&pos).is_some_and(|c| *c == b'@')
|
||||||
&& grid.neighbours_count(&pos, |c| *c == b'@') < 4
|
&& grid.adjacent_count(&pos, |c| *c == b'@') < 4
|
||||||
{
|
{
|
||||||
// remove the roll
|
// remove the roll
|
||||||
grid.set(&pos, b'.');
|
grid.set(&pos, b'.');
|
||||||
@@ -38,6 +40,30 @@ fn part2(input: &Grid<u8>) -> u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[aoc(day4, part2, RollList)]
|
||||||
|
fn part2_list(input: &Grid<u8>) -> u64 {
|
||||||
|
let mut grid = input.clone();
|
||||||
|
let mut to_check = grid.find_all(&b'@').collect_vec();
|
||||||
|
let mut removed = 0;
|
||||||
|
|
||||||
|
while let Some(roll) = to_check.pop() {
|
||||||
|
if grid.get(&roll).is_none_or(|c| *c == b'.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let adjacent_rolls = grid
|
||||||
|
.adjacent_iter(&roll)
|
||||||
|
.filter_map(|i| if *i.value == b'@' { Some(i.pos) } else { None })
|
||||||
|
.collect_vec();
|
||||||
|
if adjacent_rolls.len() < 4 {
|
||||||
|
grid.set(&roll, b'.');
|
||||||
|
removed += 1;
|
||||||
|
to_check.extend_from_slice(&adjacent_rolls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removed
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -62,4 +88,9 @@ mod tests {
|
|||||||
fn part2_example() {
|
fn part2_example() {
|
||||||
assert_eq!(part2(&parse(EXAMPLE)), 43);
|
assert_eq!(part2(&parse(EXAMPLE)), 43);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_list_example() {
|
||||||
|
assert_eq!(part2_list(&parse(EXAMPLE)), 43);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// NW, N, NE, W, E, SW, S, SE
|
/// NW, N, NE, W, E, SW, S, SE
|
||||||
const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
pub const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
||||||
&(-1, -1),
|
&(-1, -1),
|
||||||
&(0, -1),
|
&(0, -1),
|
||||||
&(1, -1),
|
&(1, -1),
|
||||||
@@ -20,14 +20,20 @@ const ADJACENT_OFFSETS: [&(i64, i64); 8] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/// NESW
|
/// NESW
|
||||||
const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
|
pub const CARDINAL_OFFSETS: [&(i64, i64); 4] = [&(0, -1), &(-1, 0), &(1, 0), &(0, 1)];
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Coord2d {
|
pub struct Coord2d {
|
||||||
pub x: i64,
|
pub x: i64,
|
||||||
pub y: i64,
|
pub y: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Coord2d {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("({}, {})", self.x, self.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait AsCoord2d {
|
pub trait AsCoord2d {
|
||||||
fn to_coord(self) -> Coord2d;
|
fn to_coord(self) -> Coord2d;
|
||||||
fn x(&self) -> i64;
|
fn x(&self) -> i64;
|
||||||
@@ -402,7 +408,7 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
/// Get all of the coordinates having value `needle`
|
/// Get all of the coordinates having value `needle`
|
||||||
pub fn find_all<'a>(&'a self, needle: &'a T) -> impl Iterator<Item = Coord2d> + 'a {
|
pub fn find_all<'a>(&'a self, needle: &'a T) -> impl DoubleEndedIterator<Item = Coord2d> + 'a {
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -430,19 +436,23 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the count of neighbours (8 directions) matching predicate p
|
/// Return the count of neighbours (8 directions) matching predicate p
|
||||||
pub fn neighbours_count<C: AsCoord2d + Copy, P>(&self, c: &C, mut p: P) -> usize
|
pub fn adjacent_count<C: AsCoord2d + Copy, P>(&self, c: &C, mut p: P) -> usize
|
||||||
where
|
where
|
||||||
P: FnMut(&T) -> bool,
|
P: FnMut(&T) -> bool,
|
||||||
{
|
{
|
||||||
ADJACENT_OFFSETS
|
self.adjacent_iter(c).filter(|i| p(i.value)).count()
|
||||||
.iter()
|
}
|
||||||
.map(|d| c.to_coord() + *d)
|
|
||||||
.filter(|c| self.get(c).is_some_and(&mut p))
|
/// Return the count of cardinal neighbours (4 directions) matching predicate p
|
||||||
.count()
|
pub fn cardinal_count<C: AsCoord2d + Copy, P>(&self, c: &C, mut p: P) -> usize
|
||||||
|
where
|
||||||
|
P: FnMut(&T) -> bool,
|
||||||
|
{
|
||||||
|
self.cardinal_iter(c).filter(|i| p(i.value)).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an iterator over the 8 neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
/// Return an iterator over the 8 neighbours of c. The iterator skips neighbouring positions outside of the grid.
|
||||||
pub fn neighbours_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
pub fn adjacent_iter<C: AsCoord2d + Copy>(&self, c: &C) -> OffsetsIter<T> {
|
||||||
OffsetsIter {
|
OffsetsIter {
|
||||||
grid: self,
|
grid: self,
|
||||||
origin: c.to_coord(),
|
origin: c.to_coord(),
|
||||||
@@ -636,7 +646,7 @@ FBCG";
|
|||||||
fn neighbours_iter() {
|
fn neighbours_iter() {
|
||||||
let grid = unchecked_load();
|
let grid = unchecked_load();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
grid.neighbours_iter(&(0, 1)).collect::<Vec<_>>(),
|
grid.adjacent_iter(&(0, 1)).collect::<Vec<_>>(),
|
||||||
[
|
[
|
||||||
Item {
|
Item {
|
||||||
pos: Coord2d { x: 0, y: 0 },
|
pos: Coord2d { x: 0, y: 0 },
|
||||||
|
|||||||
Reference in New Issue
Block a user