try to make const generics work for day 17

This commit is contained in:
kageru 2020-12-17 21:30:30 +01:00
parent b3e81ed412
commit b8ae6f5711
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
4 changed files with 138 additions and 26 deletions

View File

@ -1,36 +1,41 @@
#![feature(test)]
#![allow(incomplete_features)]
#![feature(test, const_generics, const_evaluatable_checked)]
extern crate test;
use itertools::Itertools;
use aoc2020::{
common::*, grid::{cell::Cell, *}
};
use itertools::Itertools;
fn read_input() -> String {
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, F: FnMut((usize, usize)) -> PositionND<DIMS> + Copy>(raw: &str, mut pos_gen: F) -> Grid<DIMS, Cell> {
raw.lines()
.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)
.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()
}
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> {
let readonly = input.clone();
input
.fields
.keys()
.flat_map(|p| p.neighbors())
.flat_map(|p| p.neighbors().iter())
.unique()
.map(|pos| {
let cell = readonly.get(&pos);
let new = match (&cell, count_live_neighbors(&pos, &readonly)) {
let new = match (&cell, count_live_neighbors::<D>(&pos, &readonly)) {
(Cell::Alive, 2..=3) => Cell::Alive,
(Cell::Dead, 3) => Cell::Alive,
_ => Cell::Dead,
@ -41,7 +46,7 @@ fn make_step<P: Position>(input: Grid<P, Cell>) -> Grid<P, Cell> {
.collect()
}
fn solve<P: Position>(parsed: &Grid<P, Cell>, steps: usize) -> usize {
fn solve<const D: usize>(parsed: &Grid<D, Cell>, steps: usize) -> usize {
let mut clone = parsed.clone();
for _ in 0..steps {
clone = make_step(clone);

View File

@ -8,37 +8,37 @@ use itertools::join;
use std::{collections::HashMap, fmt::Display, hash::BuildHasher};
#[derive(Debug, Clone)]
pub struct Grid<P: Position, T: Display + Default> {
pub fields: HashMap<P, T>,
pub struct Grid<const D: usize, T: Display + Default> {
pub fields: HashMap<PositionND<D>, T>,
}
impl<P: Position, T: Display + Default + Copy> Grid<P, T> {
pub fn get_convert<Pos: Into<P>>(&self, pos: Pos) -> T {
self.fields.get(&pos.into()).copied().unwrap_or_else(|| T::default())
}
impl<const D: usize, T: Display + Default + Copy> Grid<D, T> {
//pub fn get_convert<Pos: Into<P>>(&self, pos: Pos) -> T {
//self.fields.get(&pos.into()).copied().unwrap_or_else(|| T::default())
//}
pub fn get(&self, pos: &P) -> T {
pub fn get(&self, pos: &PositionND<D>) -> T {
self.fields.get(pos).copied().unwrap_or_else(|| T::default())
}
pub fn insert<Pos: Into<P>>(&mut self, pos: Pos, t: T) {
pub fn insert<Pos: Into<PositionND<D>>>(&mut self, pos: Pos, t: T) {
self.fields.insert(pos.into(), t);
}
}
impl<P: Position, T: Display + Default> std::iter::FromIterator<(P, T)> for Grid<P, T> {
fn from_iter<I: IntoIterator<Item = (P, T)>>(iter: I) -> Self {
impl<const D: usize, T: Display + Default> std::iter::FromIterator<(PositionND<D>, T)> for Grid<D, T> {
fn from_iter<I: IntoIterator<Item = (PositionND<D>, T)>>(iter: I) -> Self {
Grid {
fields: iter.into_iter().collect(),
}
}
}
impl<T: Display + Default + Copy> Grid<Position2D, T> {
fn draw_ascii(&self) -> String {
draw_ascii(&self.fields)
}
}
// impl<T: Display + Default + Copy> Grid<Position2D, T> {
// fn draw_ascii(&self) -> String {
// draw_ascii(&self.fields)
// }
// }
struct Boundaries {
x_min: i64,

View File

@ -1,7 +1,9 @@
use super::direction::*;
use impl_ops::*;
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
where Self: Sized + Hash + PartialEq + Eq + Clone + Copy
@ -30,6 +32,109 @@ pub struct Position4D {
pub w: i64,
}
#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)]
pub struct PositionND<const DIMS: usize> {
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 }
}
}
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,
{
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(&[x, 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(&[x, y, 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(&[x, y, z, 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 {
use super::*;

View File

@ -1,3 +1,5 @@
pub mod teststuff;
#![allow(incomplete_features)]
#![feature(const_generics, const_evaluatable_checked)]
pub mod common;
pub mod grid;
pub mod teststuff;