Remove hardcoded neighbors implementation
Not that this one is much better, but after hours of trying, it’s all I got to compile. :(
This commit is contained in:
parent
4b4f4fbf80
commit
a570cf6fda
|
@ -23,14 +23,14 @@ fn parse_input<const DIMS: usize>(raw: &str) -> Grid<DIMS, Cell> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_live_neighbors<const D: usize>(p: &PositionND<D>, grid: &Grid<D, Cell>) -> usize
|
fn count_live_neighbors<const D: usize>(p: &PositionND<D>, grid: &Grid<D, Cell>) -> usize
|
||||||
where [(); grid::num_neighbors(D)]: Sized {
|
where [(); grid::num_neighbors(D) + 1]: Sized {
|
||||||
IntoIterator::into_iter(p.neighbors())
|
IntoIterator::into_iter(p.neighbors())
|
||||||
.filter(|n| grid.get(n) == Cell::Alive)
|
.filter(|n| grid.get(n) == Cell::Alive)
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_step<const D: usize>(input: Grid<D, Cell>) -> Grid<D, Cell>
|
fn make_step<const D: usize>(input: Grid<D, Cell>) -> Grid<D, Cell>
|
||||||
where [(); grid::num_neighbors(D)]: Sized {
|
where [(); grid::num_neighbors(D) + 1]: Sized {
|
||||||
let readonly = input.clone();
|
let readonly = input.clone();
|
||||||
input
|
input
|
||||||
.fields
|
.fields
|
||||||
|
@ -43,7 +43,7 @@ where [(); grid::num_neighbors(D)]: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_state<const D: usize>(pos: &PositionND<D>, grid: &Grid<D, Cell>) -> Cell
|
fn next_state<const D: usize>(pos: &PositionND<D>, grid: &Grid<D, Cell>) -> Cell
|
||||||
where [(); grid::num_neighbors(D)]: Sized {
|
where [(); grid::num_neighbors(D) + 1]: Sized {
|
||||||
let cell = grid.get(pos);
|
let cell = grid.get(pos);
|
||||||
match (&cell, count_live_neighbors::<D>(pos, grid)) {
|
match (&cell, count_live_neighbors::<D>(pos, grid)) {
|
||||||
(Cell::Alive, 2..=3) => Cell::Alive,
|
(Cell::Alive, 2..=3) => Cell::Alive,
|
||||||
|
@ -53,7 +53,7 @@ where [(); grid::num_neighbors(D)]: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve<const D: usize>(parsed: &Grid<D, Cell>, steps: usize) -> usize
|
fn solve<const D: usize>(parsed: &Grid<D, Cell>, steps: usize) -> usize
|
||||||
where [(); grid::num_neighbors(D)]: Sized {
|
where [(); grid::num_neighbors(D) + 1]: Sized {
|
||||||
let mut clone = parsed.clone();
|
let mut clone = parsed.clone();
|
||||||
for _ in 0..steps {
|
for _ in 0..steps {
|
||||||
clone = make_step(clone);
|
clone = make_step(clone);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use super::direction::*;
|
use super::direction::*;
|
||||||
use itertools::iproduct;
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryInto, hash::Hash, ops::{Add, Mul, Sub}
|
convert::TryInto, hash::Hash, ops::{Add, Mul, Sub}
|
||||||
};
|
};
|
||||||
|
@ -54,64 +53,60 @@ impl<const DIMS: usize> PositionND<DIMS> {
|
||||||
PositionND { points }
|
PositionND { points }
|
||||||
}
|
}
|
||||||
|
|
||||||
// until I can figure out how to properly do that, here’s a “good enough” solution :^)
|
|
||||||
pub fn neighbors(&self) -> [PositionND<DIMS>; num_neighbors(DIMS)]
|
pub fn neighbors(&self) -> [PositionND<DIMS>; num_neighbors(DIMS)]
|
||||||
where
|
where [PositionND<DIMS>; num_neighbors(DIMS) + 1]: Sized {
|
||||||
[PositionND<DIMS>; num_neighbors(DIMS)]: Sized,
|
let ns = neighbor_vectors::<DIMS>();
|
||||||
[(); num_neighbors(DIMS)]: Sized,
|
let mut out = [*self; num_neighbors(DIMS)];
|
||||||
{
|
for (out, dir) in out.iter_mut().zip(IntoIterator::into_iter(ns).filter(|n| n != &[0; DIMS])) {
|
||||||
let mut out = [PositionND::zero(); num_neighbors(DIMS)];
|
*out = *out + PositionND::from(dir);
|
||||||
match DIMS {
|
|
||||||
2 => {
|
|
||||||
for (i, n) in iproduct!((-1..=1), (-1..=1))
|
|
||||||
.filter(|t| t != &(0, 0))
|
|
||||||
.map(|(x, y)| PositionND::<DIMS>::from_padded(&[self.points[0] + x, self.points[1] + y]))
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
out[i] = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1))
|
|
||||||
.filter(|t| t != &(0, 0, 0))
|
|
||||||
.map(|(x, y, z)| PositionND::<DIMS>::from_padded(&[self.points[0] + x, self.points[1] + y, self.points[2] + z]))
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
out[i] = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4 => {
|
|
||||||
for (i, n) in iproduct!((-1..=1), (-1..=1), (-1..=1), (-1..=1))
|
|
||||||
.filter(|t| t != &(0, 0, 0, 0))
|
|
||||||
.map(|(x, y, z, w)| {
|
|
||||||
PositionND::<DIMS>::from_padded(&[self.points[0] + x, self.points[1] + y, self.points[2] + z, self.points[3] + w])
|
|
||||||
})
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
out[i] = n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe one day :(
|
#[macro_export]
|
||||||
/*
|
macro_rules! dim {
|
||||||
fn neighbors_inner<const D: usize>(existing: [i64; DIMS]) -> [[i64; DIMS]; (DIMS - D).pow(3)] {
|
($d: expr) => {{
|
||||||
let out = [[0; DIMS]; (DIMS - D).pow(3)];
|
let mut out = [[0; D]; num_neighbors(D) + 1];
|
||||||
let mut index = 0;
|
let mut i = 0;
|
||||||
for i in -1..=1 {
|
for offset in -1..=1 {
|
||||||
existing[D] = i;
|
for inner in neighbor_vectors::<$d>() {
|
||||||
// I guess that means no recursion with const generics?
|
out[i][0] = offset;
|
||||||
for xs in neighbors_inner(existing.clone()) {
|
let mut j = 1;
|
||||||
out[index] = xs;
|
for e in inner {
|
||||||
index += 1;
|
out[i][j] = e;
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out
|
out
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neighbor_vectors<const D: usize>() -> [[i64; D]; num_neighbors(D) + 1]
|
||||||
|
where
|
||||||
|
{
|
||||||
|
// I would love to just call neighbor_vectors::<D-1>(), but it seems to be impossible to get the
|
||||||
|
// correct constraints for that.
|
||||||
|
match D {
|
||||||
|
0 => unreachable!(),
|
||||||
|
1 => {
|
||||||
|
let mut out = [[0; D]; num_neighbors(D) + 1];
|
||||||
|
out[0] = [-1; D];
|
||||||
|
out[1] = [0; D];
|
||||||
|
out[2] = [1; D];
|
||||||
|
out
|
||||||
|
}
|
||||||
|
2 => dim!(1),
|
||||||
|
3 => dim!(2),
|
||||||
|
4 => dim!(3),
|
||||||
|
5 => dim!(4),
|
||||||
|
6 => dim!(5),
|
||||||
|
7 => dim!(6),
|
||||||
|
// Adding more causes a stackoverflow. How curious.
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const D: usize> Mul<i64> for PositionND<D> {
|
impl<const D: usize> Mul<i64> for PositionND<D> {
|
||||||
|
@ -233,4 +228,30 @@ mod tests {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_neighbor_vectors() {
|
||||||
|
let n = neighbor_vectors::<2>();
|
||||||
|
assert_eq!(n, [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 0], [0, 1], [1, -1], [1, 0], [1, 1],]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_neighbor_vectors_2d(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| test::black_box(neighbor_vectors::<2>()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_neighbor_vectors_3d(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| test::black_box(neighbor_vectors::<3>()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_neighbor_vectors_4d(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| test::black_box(neighbor_vectors::<4>()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_neighbor_vectors_5d(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| test::black_box(neighbor_vectors::<5>()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user