Created
December 17, 2020 15:58
-
-
Save ske2004/32e55b0c083687267ee6c8218ae791f9 to your computer and use it in GitHub Desktop.
Day 17 AOC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::hash_map::*; | |
use std::time::SystemTime; | |
#[derive(Hash, Copy, Clone, PartialEq, Debug, Eq)] | |
struct Vec3(i8, i8, i8); | |
#[derive(Hash, Copy, Clone, PartialEq, Debug, Eq)] | |
struct Vec4(i8, i8, i8, i8); | |
impl Vec4 | |
{ | |
fn add_asn(&mut self, other: Vec4) -> &mut Self | |
{ | |
self.0 += other.0; | |
self.1 += other.1; | |
self.2 += other.2; | |
self.3 += other.3; | |
self | |
} | |
} | |
impl Vec3 | |
{ | |
fn add_asn(&mut self, other: Vec3) -> &mut Self | |
{ | |
self.0 += other.0; | |
self.1 += other.1; | |
self.2 += other.2; | |
self | |
} | |
} | |
trait Spatial: Sized | |
{ | |
fn neighbours(&self) -> Vec<Self>; | |
} | |
impl From<(i8, i8)> for Vec3 | |
{ | |
fn from(val: (i8, i8)) -> Self | |
{ | |
Self(val.0, val.1, 0) | |
} | |
} | |
impl From<(i8, i8)> for Vec4 | |
{ | |
fn from(val: (i8, i8)) -> Self | |
{ | |
Self(val.0, val.1, 0, 0) | |
} | |
} | |
impl Spatial for Vec3 | |
{ | |
fn neighbours(&self) -> Vec<Self> | |
{ | |
let mut values = vec![*self; 26]; | |
// Count index of values array | |
let mut counter = 0; | |
for x in -1..=1 | |
{ | |
for y in -1..=1 | |
{ | |
for z in -1..=1 | |
{ | |
if let (0, 0, 0) = (x, y, z) | |
{ | |
continue; | |
} | |
assert!(counter < 26, "Counter exceeded maximum neigh count for Vec4 {}", counter); | |
values.get_mut(counter).unwrap().add_asn(Vec3(x, y, z)); | |
counter += 1; | |
} | |
} | |
} | |
values | |
} | |
} | |
impl Spatial for Vec4 | |
{ | |
fn neighbours(&self) -> Vec<Self> | |
{ | |
let mut values = vec![*self; (3*3*3*3)-1]; | |
// Count index of values array | |
let mut counter = 0; | |
for x in -1..=1 | |
{ | |
for y in -1..=1 | |
{ | |
for z in -1..=1 | |
{ | |
for w in -1..=1 | |
{ | |
if let (0, 0, 0, 0) = (x, y, z, w) | |
{ | |
continue; | |
} | |
assert!(counter < (3*3*3*3)-1, "Counter exceeded maximum neigh count for Vec4 {}", counter); | |
values.get_mut(counter).unwrap().add_asn(Vec4(x, y, z, w)); | |
counter += 1; | |
} | |
} | |
} | |
} | |
values | |
} | |
} | |
struct World<T> | |
{ | |
map: HashMap<T, Option<u8>> | |
} | |
impl<T: Copy + Spatial + Eq + std::hash::Hash> World<T> | |
{ | |
fn cached_neigh_count(&mut self, pos: &T) -> usize | |
{ | |
let got = self.map.get(pos); | |
if let Some(Some(x)) = got | |
{ | |
return *x as usize | |
} | |
let neigh = self.neigh_count(pos); | |
if let Some(t) = self.map.get_mut(pos) | |
{ | |
*t = Some(neigh as u8); | |
} | |
neigh | |
} | |
fn neigh_count(&self, pos: &T) -> usize | |
{ | |
pos.neighbours().iter().map(|e| self.is_active(e) as usize).fold(0, |a, b| a + b) | |
} | |
#[inline] | |
fn is_active(&self, pos: &T) -> bool | |
{ | |
self.map.contains_key(pos) | |
} | |
fn iterate(&mut self) | |
{ | |
let mut new_map = HashMap::new(); | |
let mut visit = vec![]; | |
for (pos, i) in self.map.iter_mut() | |
{ | |
for neigh in &pos.neighbours() | |
{ | |
visit.push(*neigh); | |
} | |
} | |
for neigh in visit | |
{ | |
let count = self.cached_neigh_count(&neigh); | |
if let (true, 2..=3) | (false, 3) = (self.is_active(&neigh), count) | |
{ | |
new_map.insert(neigh, None); | |
} | |
} | |
self.map = new_map; | |
} | |
fn active_count(&self) -> usize | |
{ | |
self.map.len() | |
} | |
} | |
fn z_slice(world: &World<Vec3>, offs: i8) -> String | |
{ | |
let mut res = "".to_string(); | |
for x in -10..=10 | |
{ | |
for y in -10..=10 | |
{ | |
res += match world.is_active(&Vec3(x, y, offs)) | |
{ | |
true => "#", | |
false => "." | |
} | |
} | |
res += "\n"; | |
} | |
res | |
} | |
fn zw_slice(world: &World<Vec4>, z: i8, w: i8) -> String | |
{ | |
let mut res = "".to_string(); | |
for x in -10..=10 | |
{ | |
for y in -10..=10 | |
{ | |
res += match world.is_active(&Vec4(x, y, z, w)) | |
{ | |
true => "#", | |
false => "." | |
} | |
} | |
res += "\n"; | |
} | |
res | |
} | |
pub fn solve_day17() | |
{ | |
let input = std::fs::read_to_string("./day17.txt").unwrap(); | |
let mut world = parse::<Vec3>(&input).unwrap(); | |
let v = std::time::SystemTime::now(); | |
world.iterate(); | |
world.iterate(); | |
world.iterate(); | |
world.iterate(); | |
world.iterate(); | |
world.iterate(); | |
println!("{:?}ms {}", (std::time::SystemTime::now() - v.elapsed().unwrap()).elapsed().unwrap().as_millis(), world.active_count()); | |
let mut world4 = parse::<Vec4>(&input).unwrap(); | |
let v = std::time::SystemTime::now(); | |
world4.iterate(); | |
world4.iterate(); | |
world4.iterate(); | |
world4.iterate(); | |
world4.iterate(); | |
world4.iterate(); | |
println!("{:?}ms {}", (std::time::SystemTime::now() - v.elapsed().unwrap()).elapsed().unwrap().as_millis(), world4.active_count()); | |
} | |
fn parse<T: Spatial + From<(i8, i8)> + Eq + std::hash::Hash + Copy>(text: &str) -> Result<World<T>, String> | |
{ | |
let mut res = World{map: HashMap::new()}; | |
let mut x = 0; | |
let mut y = 0; | |
for i in text.chars() | |
{ | |
match i | |
{ | |
'\n' => { | |
y += 1; | |
x = 0; | |
continue; | |
}, | |
'#' => { | |
res.map.insert(T::from((x, y)), None); | |
}, | |
'.' => {}, | |
ch => { | |
return Err(format!("Unknown character {} met at position ({}, {})", ch, x, y)); | |
} | |
} | |
x += 1; | |
} | |
Ok(res) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment