From b8ae6f5711d20364a42f2e299565690e897f7cf1 Mon Sep 17 00:00:00 2001 From: kageru Date: Thu, 17 Dec 2020 21:30:30 +0100 Subject: [PATCH] try to make const generics work for day 17 --- 2020/src/bin/day17.rs | 23 ++++---- 2020/src/grid.rs | 30 +++++------ 2020/src/grid/position.rs | 107 +++++++++++++++++++++++++++++++++++++- 2020/src/lib.rs | 4 +- 4 files changed, 138 insertions(+), 26 deletions(-) diff --git a/2020/src/bin/day17.rs b/2020/src/bin/day17.rs index eae1ad5..3adcad8 100644 --- a/2020/src/bin/day17.rs +++ b/2020/src/bin/day17.rs @@ -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 + Copy>(raw: &str, mut pos_gen: F) -> Grid { +fn parse_input PositionND + Copy>(raw: &str, mut pos_gen: F) -> Grid { 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::::from_padded(&[x as i64, y as i64]), b.into())) + }) .filter(|(_, c)| c == &Cell::Alive) .collect() } -fn count_live_neighbors(p: &P, grid: &Grid) -> usize { +fn count_live_neighbors(p: PositionND, grid: &Grid) -> usize { p.neighbors().iter().filter(|&n| grid.get(n) == Cell::Alive).count() } -fn make_step(input: Grid) -> Grid { +fn make_step(input: Grid) -> Grid { 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::(&pos, &readonly)) { (Cell::Alive, 2..=3) => Cell::Alive, (Cell::Dead, 3) => Cell::Alive, _ => Cell::Dead, @@ -41,7 +46,7 @@ fn make_step(input: Grid) -> Grid { .collect() } -fn solve(parsed: &Grid, steps: usize) -> usize { +fn solve(parsed: &Grid, steps: usize) -> usize { let mut clone = parsed.clone(); for _ in 0..steps { clone = make_step(clone); diff --git a/2020/src/grid.rs b/2020/src/grid.rs index a287722..eb0a69a 100644 --- a/2020/src/grid.rs +++ b/2020/src/grid.rs @@ -8,37 +8,37 @@ use itertools::join; use std::{collections::HashMap, fmt::Display, hash::BuildHasher}; #[derive(Debug, Clone)] -pub struct Grid { - pub fields: HashMap, +pub struct Grid { + pub fields: HashMap, T>, } -impl Grid { - pub fn get_convert>(&self, pos: Pos) -> T { - self.fields.get(&pos.into()).copied().unwrap_or_else(|| T::default()) - } +impl Grid { + //pub fn get_convert>(&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) -> T { self.fields.get(pos).copied().unwrap_or_else(|| T::default()) } - pub fn insert>(&mut self, pos: Pos, t: T) { + pub fn insert>>(&mut self, pos: Pos, t: T) { self.fields.insert(pos.into(), t); } } -impl std::iter::FromIterator<(P, T)> for Grid { - fn from_iter>(iter: I) -> Self { +impl std::iter::FromIterator<(PositionND, T)> for Grid { + fn from_iter, T)>>(iter: I) -> Self { Grid { fields: iter.into_iter().collect(), } } } -impl Grid { - fn draw_ascii(&self) -> String { - draw_ascii(&self.fields) - } -} +// impl Grid { + // fn draw_ascii(&self) -> String { + // draw_ascii(&self.fields) + // } +// } struct Boundaries { x_min: i64, diff --git a/2020/src/grid/position.rs b/2020/src/grid/position.rs index 074d308..f7d7268 100644 --- a/2020/src/grid/position.rs +++ b/2020/src/grid/position.rs @@ -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 { + points: [i64; DIMS], +} + +impl From<[I; D]> for PositionND +where I: TryInto + 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 PositionND { + pub const fn zero() -> Self { + PositionND { points: [0; DIMS] } + } + + pub fn from_padded(slice: &[i64]) -> PositionND { + 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; num_neighbors(DIMS)] + where + [PositionND; 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::::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::::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::::from_padded(&[x, y, z, w])) + .enumerate() + { + out[i] = n; + } + } + _ => unimplemented!(), + } + out + } + + // Maybe one day :( + /* + fn neighbors_inner(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 Add> for PositionND { + type Output = PositionND; + + fn add(self, rhs: PositionND) -> 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::*; diff --git a/2020/src/lib.rs b/2020/src/lib.rs index 9c7da59..76b81db 100644 --- a/2020/src/lib.rs +++ b/2020/src/lib.rs @@ -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;