Merge branch 'd17-constgenerics'
This commit is contained in:
commit
eee3183dc0
|
@ -1,47 +1,60 @@
|
||||||
#![feature(test)]
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(test, const_generics, const_evaluatable_checked)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
use itertools::Itertools;
|
|
||||||
use aoc2020::{
|
use aoc2020::{
|
||||||
common::*, grid::{cell::Cell, *}
|
common::*, grid::{self, cell::Cell, *}
|
||||||
};
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
fn read_input() -> String {
|
fn read_input() -> String {
|
||||||
read_file(17)
|
read_file(17)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_input<P: Position, F: FnMut((usize, usize)) -> P + Copy>(raw: &str, mut pos_gen: F) -> Grid<P, Cell> {
|
fn parse_input<const DIMS: usize>(raw: &str) -> Grid<DIMS, Cell> {
|
||||||
raw.lines()
|
raw.lines()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, b)| (pos_gen((x, y)), b.into())))
|
.flat_map(move |(y, l)| {
|
||||||
|
l.bytes()
|
||||||
|
.enumerate()
|
||||||
|
.map(move |(x, b)| (PositionND::<DIMS>::from_padded(&[x as i64, y as i64]), b.into()))
|
||||||
|
})
|
||||||
.filter(|(_, c)| c == &Cell::Alive)
|
.filter(|(_, c)| c == &Cell::Alive)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn count_live_neighbors<P: Position>(p: &P, grid: &Grid<P, Cell>) -> usize {
|
fn count_live_neighbors<const D: usize>(p: &PositionND<D>, grid: &Grid<D, Cell>) -> usize
|
||||||
p.neighbors().iter().filter(|&n| grid.get(n) == Cell::Alive).count()
|
where [(); grid::num_neighbors(D)]: Sized {
|
||||||
|
IntoIterator::into_iter(p.neighbors())
|
||||||
|
.filter(|n| grid.get(n) == Cell::Alive)
|
||||||
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_step<P: Position>(input: Grid<P, Cell>) -> Grid<P, Cell> {
|
fn make_step<const D: usize>(input: Grid<D, Cell>) -> Grid<D, Cell>
|
||||||
|
where [(); grid::num_neighbors(D)]: Sized {
|
||||||
let readonly = input.clone();
|
let readonly = input.clone();
|
||||||
input
|
input
|
||||||
.fields
|
.fields
|
||||||
.keys()
|
.keys()
|
||||||
.flat_map(|p| p.neighbors())
|
.flat_map(|p| p.neighbors())
|
||||||
.unique()
|
.unique()
|
||||||
.map(|pos| {
|
.map(|pos| (pos, next_state(&pos, &readonly)))
|
||||||
let cell = readonly.get(&pos);
|
|
||||||
let new = match (&cell, count_live_neighbors(&pos, &readonly)) {
|
|
||||||
(Cell::Alive, 2..=3) => Cell::Alive,
|
|
||||||
(Cell::Dead, 3) => Cell::Alive,
|
|
||||||
_ => Cell::Dead,
|
|
||||||
};
|
|
||||||
(pos, new)
|
|
||||||
})
|
|
||||||
.filter(|(_, c)| c == &Cell::Alive)
|
.filter(|(_, c)| c == &Cell::Alive)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve<P: Position>(parsed: &Grid<P, Cell>, steps: usize) -> usize {
|
fn next_state<const D: usize>(pos: &PositionND<D>, grid: &Grid<D, Cell>) -> Cell
|
||||||
|
where [(); grid::num_neighbors(D)]: Sized {
|
||||||
|
let cell = grid.get(pos);
|
||||||
|
let new = match (&cell, count_live_neighbors::<D>(pos, &grid)) {
|
||||||
|
(Cell::Alive, 2..=3) => Cell::Alive,
|
||||||
|
(Cell::Dead, 3) => Cell::Alive,
|
||||||
|
_ => Cell::Dead,
|
||||||
|
};
|
||||||
|
new
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve<const D: usize>(parsed: &Grid<D, Cell>, steps: usize) -> usize
|
||||||
|
where [(); grid::num_neighbors(D)]: 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);
|
||||||
|
@ -51,9 +64,9 @@ fn solve<P: Position>(parsed: &Grid<P, Cell>, steps: usize) -> usize {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let raw = read_input();
|
let raw = read_input();
|
||||||
let input = parse_input(&raw, |(x, y)| Position3D::from((x, y, 0)));
|
let input = parse_input::<3>(&raw);
|
||||||
println!("Part 1: {}", solve(&input, 6));
|
println!("Part 1: {}", solve(&input, 6));
|
||||||
let input = parse_input(&raw, |(x, y)| Position4D::from((x, y, 0, 0)));
|
let input = parse_input::<4>(&raw);
|
||||||
println!("Part 2: {}", solve(&input, 6));
|
println!("Part 2: {}", solve(&input, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,40 +80,82 @@ mod tests {
|
||||||
..#
|
..#
|
||||||
###";
|
###";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_step() {
|
||||||
|
let input = parse_input::<3>(TEST_INPUT);
|
||||||
|
let changed = make_step(input.clone());
|
||||||
|
let expected = Grid {
|
||||||
|
fields: IntoIterator::into_iter([
|
||||||
|
(PositionND { points: [1, 3, 0] }, Cell::Alive),
|
||||||
|
(PositionND { points: [0, 1, 0] }, Cell::Alive),
|
||||||
|
(PositionND { points: [2, 2, 0] }, Cell::Alive),
|
||||||
|
(PositionND { points: [2, 2, 1] }, Cell::Alive),
|
||||||
|
(PositionND { points: [0, 1, 1] }, Cell::Alive),
|
||||||
|
(PositionND { points: [2, 1, 0] }, Cell::Alive),
|
||||||
|
(PositionND { points: [1, 3, -1] }, Cell::Alive),
|
||||||
|
(PositionND { points: [0, 1, -1] }, Cell::Alive),
|
||||||
|
(PositionND { points: [1, 2, 0] }, Cell::Alive),
|
||||||
|
(PositionND { points: [1, 3, 1] }, Cell::Alive),
|
||||||
|
(PositionND { points: [2, 2, -1] }, Cell::Alive),
|
||||||
|
])
|
||||||
|
.collect(),
|
||||||
|
};
|
||||||
|
assert_eq!(changed, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_count_live_neighbors() {
|
||||||
|
let input = parse_input::<2>(TEST_INPUT);
|
||||||
|
let one_one = PositionND { points: [1, 1] };
|
||||||
|
let live = count_live_neighbors(&one_one, &input);
|
||||||
|
assert_eq!(live, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_next_state() {
|
||||||
|
let input = parse_input::<2>(TEST_INPUT);
|
||||||
|
let one_one = PositionND { points: [1, 1] };
|
||||||
|
assert_eq!(next_state(&one_one, &input), Cell::Dead);
|
||||||
|
let one_three = PositionND { points: [1, 3] };
|
||||||
|
assert_eq!(next_state(&one_three, &input), Cell::Alive);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_3d() {
|
fn test_3d() {
|
||||||
let input = parse_input(TEST_INPUT, |(x, y)| Position3D::from((x, y, 0)));
|
let input = parse_input::<3>(TEST_INPUT);
|
||||||
|
assert_eq!(solve(&input, 1), 11);
|
||||||
|
assert_eq!(solve(&input, 2), 21);
|
||||||
assert_eq!(solve(&input, 6), 112);
|
assert_eq!(solve(&input, 6), 112);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_4d() {
|
fn test_4d() {
|
||||||
let input = parse_input(TEST_INPUT, |(x, y)| Position4D::from((x, y, 0, 0)));
|
let input = parse_input::<4>(TEST_INPUT);
|
||||||
assert_eq!(solve(&input, 6), 848);
|
assert_eq!(solve(&input, 6), 848);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_3d_parse(b: &mut test::Bencher) {
|
fn bench_3d_parse(b: &mut test::Bencher) {
|
||||||
let raw = read_input();
|
let raw = read_input();
|
||||||
b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position3D::from((x, y, 0))).fields.len(), 43));
|
b.iter(|| assert_eq!(parse_input::<3>(black_box(&raw)).fields.len(), 43));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn bench_4d_parse(b: &mut test::Bencher) {
|
fn bench_4d_parse(b: &mut test::Bencher) {
|
||||||
let raw = read_input();
|
let raw = read_input();
|
||||||
b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position4D::from((x, y, 0, 0))).fields.len(), 43));
|
b.iter(|| assert_eq!(parse_input::<4>(black_box(&raw)).fields.len(), 43));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_3d(b: &mut test::Bencher) {
|
fn bench_3d(b: &mut test::Bencher) {
|
||||||
let input = parse_input(&read_input(), |(x, y)| Position3D::from((x, y, 0)));
|
let input = parse_input::<3>(&read_input());
|
||||||
b.iter(|| assert_eq!(solve(&input, 6), 348));
|
b.iter(|| assert_eq!(solve(&input, 6), 348));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_4d(b: &mut test::Bencher) {
|
fn bench_4d(b: &mut test::Bencher) {
|
||||||
let input = parse_input(&read_input(), |(x, y)| Position4D::from((x, y, 0, 0)));
|
let input = parse_input::<4>(&read_input());
|
||||||
b.iter(|| assert_eq!(solve(&input, 6), 2236));
|
b.iter(|| assert_eq!(solve(&input, 6), 2236));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,39 +7,29 @@ pub use position::*;
|
||||||
use itertools::join;
|
use itertools::join;
|
||||||
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Grid<P: Position, T: Display + Default> {
|
pub struct Grid<const D: usize, T: Display + Default> {
|
||||||
pub fields: HashMap<P, T>,
|
pub fields: HashMap<PositionND<D>, T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Position, T: Display + Default + Copy> Grid<P, T> {
|
impl<const D: usize, T: Display + Default + Copy> Grid<D, T> {
|
||||||
pub fn get_convert<Pos: Into<P>>(&self, pos: Pos) -> T {
|
pub fn get(&self, pos: &PositionND<D>) -> T {
|
||||||
self.fields.get(&pos.into()).copied().unwrap_or_default()
|
self.fields.get(pos).copied().unwrap_or_else(|| T::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, pos: &P) -> T {
|
pub fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
|
||||||
self.fields.get(pos).copied().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert<Pos: Into<P>>(&mut self, pos: Pos, t: T) {
|
|
||||||
self.fields.insert(pos.into(), t);
|
self.fields.insert(pos.into(), t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Position, T: Display + Default> std::iter::FromIterator<(P, T)> for Grid<P, T> {
|
impl<const D: usize, T: Display + Default> std::iter::FromIterator<(PositionND<D>, T)> for Grid<D, T> {
|
||||||
fn from_iter<I: IntoIterator<Item = (P, T)>>(iter: I) -> Self {
|
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
|
||||||
Grid {
|
Grid {
|
||||||
fields: iter.into_iter().collect(),
|
fields: iter.into_iter().collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display + Default + Copy> Grid<Position2D, T> {
|
|
||||||
pub fn draw_ascii(&self) -> String {
|
|
||||||
draw_ascii(&self.fields)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Boundaries {
|
struct Boundaries {
|
||||||
x_min: i64,
|
x_min: i64,
|
||||||
x_max: i64,
|
x_max: i64,
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
extern crate test;
|
||||||
use super::direction::*;
|
use super::direction::*;
|
||||||
use impl_ops::*;
|
use impl_ops::*;
|
||||||
use itertools::iproduct;
|
use itertools::iproduct;
|
||||||
use std::{convert::TryInto, hash::Hash, ops, ops::AddAssign};
|
use std::{
|
||||||
|
convert::TryInto, hash::Hash, ops, ops::{Add, AddAssign}
|
||||||
|
};
|
||||||
|
|
||||||
pub trait Position
|
pub trait Position
|
||||||
where Self: Sized + Hash + PartialEq + Eq + Clone + Copy
|
where Self: Sized + Hash + PartialEq + Eq + Clone + Copy
|
||||||
|
@ -30,6 +33,110 @@ pub struct Position4D {
|
||||||
pub w: i64,
|
pub w: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)]
|
||||||
|
pub struct PositionND<const DIMS: usize> {
|
||||||
|
pub points: [i64; DIMS],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const D: usize, I> From<[I; D]> for PositionND<D>
|
||||||
|
where I: TryInto<i64> + Copy
|
||||||
|
{
|
||||||
|
fn from(s: [I; D]) -> Self {
|
||||||
|
let mut points = [0; D];
|
||||||
|
for i in 0..D {
|
||||||
|
points[i] = unwrap_number_result(s[i]);
|
||||||
|
}
|
||||||
|
Self { points }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn num_neighbors(d: usize) -> usize {
|
||||||
|
3usize.pow(d as u32) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const DIMS: usize> PositionND<DIMS> {
|
||||||
|
pub const fn zero() -> Self {
|
||||||
|
PositionND { points: [0; DIMS] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_padded(slice: &[i64]) -> PositionND<DIMS> {
|
||||||
|
let mut points = [0; DIMS];
|
||||||
|
for i in 0..(DIMS.min(slice.len())) {
|
||||||
|
points[i] = slice[i];
|
||||||
|
}
|
||||||
|
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)]
|
||||||
|
where
|
||||||
|
[PositionND<DIMS>; num_neighbors(DIMS)]: Sized,
|
||||||
|
[(); num_neighbors(DIMS)]: Sized,
|
||||||
|
{
|
||||||
|
let mut out = [PositionND::zero(); num_neighbors(DIMS)];
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe one day :(
|
||||||
|
/*
|
||||||
|
fn neighbors_inner<const D: usize>(existing: [i64; DIMS]) -> [[i64; DIMS]; (DIMS - D).pow(3)] {
|
||||||
|
let out = [[0; DIMS]; (DIMS - D).pow(3)];
|
||||||
|
let mut index = 0;
|
||||||
|
for i in -1..=1 {
|
||||||
|
existing[D] = i;
|
||||||
|
// I guess that means no recursion with const generics?
|
||||||
|
for xs in neighbors_inner(existing.clone()) {
|
||||||
|
out[index] = xs;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const D: usize> Add<PositionND<D>> for PositionND<D> {
|
||||||
|
type Output = PositionND<D>;
|
||||||
|
|
||||||
|
fn add(self, rhs: PositionND<D>) -> Self::Output {
|
||||||
|
let mut points = [0; D];
|
||||||
|
for i in 0..D {
|
||||||
|
points[i] = self.points[i] + rhs.points[i];
|
||||||
|
}
|
||||||
|
PositionND { points }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod p2d {
|
mod p2d {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -191,3 +298,80 @@ fn unwrap_number_result<I: TryInto<i64>>(i: I) -> i64 {
|
||||||
_ => panic!("Bad coordinate"),
|
_ => panic!("Bad coordinate"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_neighbors_2d() {
|
||||||
|
let p = PositionND { points: [0, 0] };
|
||||||
|
let n = p.neighbors();
|
||||||
|
assert_eq!(
|
||||||
|
n,
|
||||||
|
[
|
||||||
|
PositionND { points: [-1, -1] },
|
||||||
|
PositionND { points: [-1, 0] },
|
||||||
|
PositionND { points: [-1, 1] },
|
||||||
|
PositionND { points: [0, -1] },
|
||||||
|
PositionND { points: [0, 1] },
|
||||||
|
PositionND { points: [1, -1] },
|
||||||
|
PositionND { points: [1, 0] },
|
||||||
|
PositionND { points: [1, 1] },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
let p = PositionND { points: [1, 1] };
|
||||||
|
let n = p.neighbors();
|
||||||
|
assert_eq!(
|
||||||
|
n,
|
||||||
|
[
|
||||||
|
PositionND { points: [0, 0] },
|
||||||
|
PositionND { points: [0, 1] },
|
||||||
|
PositionND { points: [0, 2] },
|
||||||
|
PositionND { points: [1, 0] },
|
||||||
|
PositionND { points: [1, 2] },
|
||||||
|
PositionND { points: [2, 0] },
|
||||||
|
PositionND { points: [2, 1] },
|
||||||
|
PositionND { points: [2, 2] },
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_neighbors_3d() {
|
||||||
|
let p = PositionND { points: [0, 0, 0] };
|
||||||
|
let n = p.neighbors();
|
||||||
|
assert_eq!(
|
||||||
|
n,
|
||||||
|
[
|
||||||
|
PositionND { points: [-1, -1, -1] },
|
||||||
|
PositionND { points: [-1, -1, 0] },
|
||||||
|
PositionND { points: [-1, -1, 1] },
|
||||||
|
PositionND { points: [-1, 0, -1] },
|
||||||
|
PositionND { points: [-1, 0, 0] },
|
||||||
|
PositionND { points: [-1, 0, 1] },
|
||||||
|
PositionND { points: [-1, 1, -1] },
|
||||||
|
PositionND { points: [-1, 1, 0] },
|
||||||
|
PositionND { points: [-1, 1, 1] },
|
||||||
|
PositionND { points: [0, -1, -1] },
|
||||||
|
PositionND { points: [0, -1, 0] },
|
||||||
|
PositionND { points: [0, -1, 1] },
|
||||||
|
PositionND { points: [0, 0, -1] },
|
||||||
|
PositionND { points: [0, 0, 1] },
|
||||||
|
PositionND { points: [0, 1, -1] },
|
||||||
|
PositionND { points: [0, 1, 0] },
|
||||||
|
PositionND { points: [0, 1, 1] },
|
||||||
|
PositionND { points: [1, -1, -1] },
|
||||||
|
PositionND { points: [1, -1, 0] },
|
||||||
|
PositionND { points: [1, -1, 1] },
|
||||||
|
PositionND { points: [1, 0, -1] },
|
||||||
|
PositionND { points: [1, 0, 0] },
|
||||||
|
PositionND { points: [1, 0, 1] },
|
||||||
|
PositionND { points: [1, 1, -1] },
|
||||||
|
PositionND { points: [1, 1, 0] },
|
||||||
|
PositionND { points: [1, 1, 1] },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod teststuff;
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(const_generics, const_evaluatable_checked, test)]
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
|
pub mod teststuff;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user