Skip to content

Commit

Permalink
Day 23: Unstable Diffusion
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 23, 2022
1 parent 6eb0ebb commit 4c0e48d
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ Development occurs in language-specific directories:
|[Day20.hs](hs/src/Day20.hs)|[Day20.kt](kt/src/commonMain/kotlin/com/github/ephemient/aoc2022/Day20.kt)|[day20.py](py/aoc2022/day20.py)|[day20.rs](rs/src/day20.rs)|
|[Day21.hs](hs/src/Day21.hs)|[Day21.kt](kt/src/commonMain/kotlin/com/github/ephemient/aoc2022/Day21.kt)|[day21.py](py/aoc2022/day21.py)|[day21.rs](rs/src/day21.rs)|
|[Day22.hs](hs/src/Day22.hs)|[Day22.kt](kt/src/commonMain/kotlin/com/github/ephemient/aoc2022/Day22.kt)|[day22.py](py/aoc2022/day22.py)|[day22.rs](rs/src/day22.rs)|
|[Day23.hs](hs/src/Day23.hs)|[Day23.kt](kt/src/commonMain/kotlin/com/github/ephemient/aoc2022/Day23.kt)|[day23.py](py/aoc2022/day23.py)|
|[Day23.hs](hs/src/Day23.hs)|[Day23.kt](kt/src/commonMain/kotlin/com/github/ephemient/aoc2022/Day23.kt)|[day23.py](py/aoc2022/day23.py)|[day23.rs](rs/src/day23.rs)|
6 changes: 5 additions & 1 deletion rs/benches/criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate build_const;

use aoc2022::{
day1, day10, day11, day12, day13, day13_fast, day14, day15, day16, day17, day18, day19, day2,
day20, day21, day22, day3, day4, day5, day6, day7, day8, day9,
day20, day21, day22, day23, day3, day4, day5, day6, day7, day8, day9,
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use gag::Gag;
Expand Down Expand Up @@ -111,6 +111,10 @@ fn aoc2022_bench(c: &mut Criterion) {
g.bench_function("part 1", |b| b.iter(|| day22::part1(black_box(DAY22))));
g.bench_function("part 2", |b| b.iter(|| day22::part2(black_box(DAY22))));
g.finish();
let mut g = c.benchmark_group("day 23");
g.bench_function("part 1", |b| b.iter(|| day23::part1(black_box(DAY23))));
g.bench_function("part 2", |b| b.iter(|| day23::part2(black_box(DAY23))));
g.finish();
}

criterion_group!(aoc2022, aoc2022_bench);
Expand Down
150 changes: 150 additions & 0 deletions rs/src/day23.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use self::Direction::*;
use std::array;
use std::cmp::{max, min};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::Cycle;

#[derive(Clone, Copy)]
enum Direction {
N,
S,
W,
E,
}

fn directions() -> Cycle<array::IntoIter<[Direction; 4], 4>> {
[[N, S, W, E], [S, W, E, N], [W, E, N, S], [E, N, S, W]]
.into_iter()
.cycle()
}

fn sides(direction: Direction, x: isize, y: isize) -> [(isize, isize); 3] {
match direction {
N => [x - 1, x, x + 1].map(|x| (x, y - 1)),
S => [x - 1, x, x + 1].map(|x| (x, y + 1)),
W => [y - 1, y, y + 1].map(|y| (x - 1, y)),
E => [y - 1, y, y + 1].map(|y| (x + 1, y)),
}
}

fn r#move(direction: Direction, x: isize, y: isize) -> (isize, isize) {
match direction {
N => (x, y - 1),
S => (x, y + 1),
W => (x - 1, y),
E => (x + 1, y),
}
}

fn neighbors(x: isize, y: isize) -> [(isize, isize); 8] {
[
(x - 1, y - 1),
(x - 1, y),
(x - 1, y + 1),
(x, y - 1),
(x, y + 1),
(x + 1, y - 1),
(x + 1, y),
(x + 1, y + 1),
]
}

fn parse<'a, I, S>(lines: I) -> BTreeSet<(isize, isize)>
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
lines
.into_iter()
.enumerate()
.flat_map(|(y, line)| {
line.as_ref()
.chars()
.enumerate()
.filter(|(_, c)| c == &'#')
.map(move |(x, _)| (x as isize, y as isize))
})
.collect()
}

fn step(state: &BTreeSet<(isize, isize)>, directions: &[Direction]) -> BTreeSet<(isize, isize)> {
let mut proposals = BTreeMap::new();
for &(x, y) in state {
if !neighbors(x, y).iter().any(|point| state.contains(point)) {
continue;
}
if let Some(&direction) = directions.iter().find(|&&direction| {
!sides(direction, x, y)
.iter()
.any(|point| state.contains(point))
}) {
proposals
.entry(r#move(direction, x, y))
.and_modify(|e: &mut Vec<_>| e.push((x, y)))
.or_insert_with(|| vec![(x, y)]);
}
}
proposals.retain(|_, old| old.len() == 1);
let mut state = state.clone();
for (new, old) in proposals {
state.remove(&old[0]);
state.insert(new);
}
state
}

pub fn part1<'a, I, S>(lines: I) -> usize
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
let state = directions()
.take(10)
.fold(parse(lines), |state, directions| step(&state, &directions));
let (min_x, max_x, min_y, max_y) = state.iter().fold(
(isize::MAX, isize::MIN, isize::MAX, isize::MIN),
|(min_x, max_x, min_y, max_y), &(x, y)| {
(min(min_x, x), max(max_x, x), min(min_y, y), max(max_y, y))
},
);
(max_x - min_x + 1) as usize * (max_y - min_y + 1) as usize - state.len()
}

pub fn part2<'a, I, S>(lines: I) -> usize
where
I: IntoIterator<Item = &'a S>,
S: AsRef<str> + 'a,
{
directions()
.scan(parse(lines), |state, directions| {
let next = step(state, &directions);
if state != &next {
*state = next;
Some(())
} else {
None
}
})
.count()
+ 1
}

#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;

static EXAMPLE: &[&str] = &[
"....#..", "..###.#", "#...#.#", ".#...##", "#.###..", "##.#.##", ".#..#..",
];

#[test]
fn part1_examples() {
assert_eq!(110, part1(EXAMPLE));
}

#[test]
fn part2_examples() {
assert_eq!(20, part2(EXAMPLE));
}
}
1 change: 1 addition & 0 deletions rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod day2;
pub mod day20;
pub mod day21;
pub mod day22;
pub mod day23;
pub mod day3;
pub mod day4;
pub mod day5;
Expand Down
9 changes: 8 additions & 1 deletion rs/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ extern crate build_const;

use aoc2022::{
day1, day10, day11, day12, day13, day13_fast, day14, day15, day16, day17, day18, day19, day2,
day20, day21, day22, day3, day4, day5, day6, day7, day8, day9,
day20, day21, day22, day23, day3, day4, day5, day6, day7, day8, day9,
};
use std::collections::HashSet;
use std::env;
Expand Down Expand Up @@ -177,5 +177,12 @@ fn main() -> io::Result<()> {
println!();
}

if args.is_empty() || args.contains("23") {
println!("Day 23");
println!("{:?}", day23::part1(DAY23));
println!("{:?}", day23::part2(DAY23));
println!();
}

Ok(())
}

0 comments on commit 4c0e48d

Please sign in to comment.