Skip to content

Instantly share code, notes, and snippets.

@skejeton
Created December 17, 2020 15:58
Show Gist options
  • Save skejeton/32e55b0c083687267ee6c8218ae791f9 to your computer and use it in GitHub Desktop.
Save skejeton/32e55b0c083687267ee6c8218ae791f9 to your computer and use it in GitHub Desktop.
Day 17 AOC
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