Skip to content

Instantly share code, notes, and snippets.

@whiter4bbit
Created December 17, 2020 13:30
Show Gist options
  • Save whiter4bbit/3effbac2a58029548346bb5b4af7bf5d to your computer and use it in GitHub Desktop.
Save whiter4bbit/3effbac2a58029548346bb5b4af7bf5d to your computer and use it in GitHub Desktop.
use std::collections::{HashMap, HashSet};
use std::convert::Into;
use std::fs;
use std::io;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct Point {
d: [i64; 4],
}
#[derive(Clone, Copy)]
enum Dimensions {
Three,
Four,
}
struct Neighbors {
base: [i64; 4],
submask: u32,
mask: u32,
}
fn has_0b11(submask: u32) -> bool {
for i in 0 as u32..4 {
if (submask >> (2 * i)) & 0b11 == 0b11 {
return true;
}
}
false
}
const SHIFTS: [i64; 3] = [0, -1, 1];
impl Iterator for Neighbors {
type Item = Point;
fn next(&mut self) -> Option<Point> {
while has_0b11(self.submask) {
self.submask = (self.submask - 1) & self.mask;
}
match self.submask {
0 => None,
_ => {
let mut d = self.base.clone();
for i in 0u32..4 {
d[i as usize] += SHIFTS[((self.submask >> (2 * i)) & 0b11) as usize];
}
self.submask = (self.submask - 1) & self.mask;
Some(Point { d: d })
}
}
}
}
impl Point {
fn neighbors(&self, dimensions: Dimensions) -> Neighbors {
let mask: u32 = match dimensions {
Dimensions::Three => 0b00111111,
Dimensions::Four => 0b11111111,
};
Neighbors {
base: self.d.clone(),
submask: mask,
mask: mask,
}
}
}
#[derive(Debug, Clone)]
struct Cubes {
active: HashSet<Point>,
}
impl Into<Cubes> for String {
fn into(self) -> Cubes {
Cubes {
active: self
.lines()
.enumerate()
.flat_map(|(y, line)| {
line.bytes()
.enumerate()
.filter_map(move |(x, cell)| match cell {
b'#' => Some(Point {
d: [x as i64, y as i64, 0, 0],
}),
_ => None,
})
})
.collect(),
}
}
}
fn transition(cubes: &Cubes, dimensions: Dimensions) -> Cubes {
let mut to_active = HashSet::new();
let mut inactive_neighbors: HashMap<Point, usize> = HashMap::new();
for cube in cubes.active.iter().copied() {
let mut active_neighbors = 0usize;
for neighbor in cube.neighbors(dimensions) {
if cubes.active.contains(&neighbor) {
active_neighbors += 1;
} else {
*inactive_neighbors.entry(neighbor).or_insert(0) += 1;
}
}
if (2usize..=3).contains(&active_neighbors) {
to_active.insert(cube);
}
}
for (cube, count) in inactive_neighbors {
if count == 3 {
to_active.insert(cube);
}
}
Cubes { active: to_active }
}
fn run_transitions<T>(init: T, count: usize, dimensions: Dimensions) -> Cubes
where
T: Into<Cubes>,
{
(0..count)
.into_iter()
.fold(init.into(), |result, _| transition(&result, dimensions))
}
#[test]
fn test_run_transitions() {
assert_eq!(
112,
run_transitions(
"
.#.
..#
###
"
.to_string(),
6,
Dimensions::Three,
)
.active
.len()
);
}
#[allow(dead_code)]
pub fn solve_p1(input: &str) -> io::Result<usize> {
Ok(
run_transitions(fs::read_to_string(input)?.to_string(), 6, Dimensions::Three)
.active
.len(),
)
}
#[allow(dead_code)]
pub fn solve_p2(input: &str) -> io::Result<usize> {
Ok(
run_transitions(fs::read_to_string(input)?.to_string(), 6, Dimensions::Four)
.active
.len(),
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment