Add 2020/17/2

This commit is contained in:
kageru 2020-12-17 15:15:51 +01:00
parent a2bee8300b
commit eef4aa7643
2 changed files with 100 additions and 22 deletions

View File

@ -4,24 +4,22 @@ use aoc2020::{
common::*, grid::{cell::Cell, *}
};
type Parsed = Grid<Position3D, Cell>;
fn read_input() -> String {
read_file(17)
}
fn parse_input(raw: &str) -> Parsed {
fn parse_input<P: Position, F: FnMut((usize, usize)) -> P + Copy>(raw: &str, mut pos_gen: F) -> Grid<P, Cell> {
raw.lines()
.enumerate()
.flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, b)| ((x, y, 0).into(), b.into())))
.flat_map(move |(y, l)| l.bytes().enumerate().map(move |(x, b)| (pos_gen((x, y)), b.into())))
.collect()
}
fn count_live_neighbors(p: &Position3D, grid: &Parsed) -> usize {
fn count_live_neighbors<P: Position>(p: &P, grid: &Grid<P, Cell>) -> usize {
p.neighbors().iter().filter(|&n| grid.get(*n) == Cell::Alive).count()
}
fn make_step(input: Parsed) -> Parsed {
fn make_step<P: Position>(input: Grid<P, Cell>) -> Grid<P, Cell> {
let readonly = input.clone();
input
.fields
@ -39,38 +37,66 @@ fn make_step(input: Parsed) -> Parsed {
.collect()
}
fn part1(parsed: &Parsed) -> usize {
fn solve<P: Position>(parsed: &Grid<P, Cell>, steps: usize) -> usize {
let mut clone = parsed.clone();
for _ in 0..6 {
for _ in 0..steps {
clone = make_step(clone);
}
clone.fields.into_iter().filter(|(_, c)| c == &Cell::Alive).count()
}
fn part2(parsed: &Parsed) -> usize {
unimplemented!()
}
fn main() {
let input = parse_input(&read_input());
println!("Part 1: {}", part1(&input));
println!("Part 2: {}", part2(&input));
let raw = read_input();
let input = parse_input(&raw, |(x, y)| Position3D::from((x, y, 0)));
println!("Part 1: {}", solve(&input, 6));
let input = parse_input(&raw, |(x, y)| Position4D::from((x, y, 0, 0)));
println!("Part 2: {}", solve(&input, 6));
}
#[cfg(test)]
mod tests {
use super::*;
use aoc2020::*;
use paste::paste;
use test::black_box;
const TEST_INPUT: &str = ".#.
..#
###";
test!(part1() == 112);
//test!(part2() == 0);
bench!(part1() == 348);
//bench!(part2() == 0);
// bench_input!(fields == 0);
#[test]
fn test_3d() {
let input = parse_input(TEST_INPUT, |(x, y)| Position3D::from((x, y, 0)));
assert_eq!(solve(&input, 6), 112);
}
#[test]
fn test_4d() {
let input = parse_input(TEST_INPUT, |(x, y)| Position4D::from((x, y, 0, 0)));
assert_eq!(solve(&input, 6), 848);
}
#[bench]
fn bench_3d_parse(b: &mut test::Bencher) {
let raw = read_input();
b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position3D::from((x, y, 0))).fields.len(), 64));
}
#[bench]
#[rustfmt::skip]
fn bench_4d_parse(b: &mut test::Bencher) {
let raw = read_input();
b.iter(|| assert_eq!(parse_input(black_box(&raw), |(x, y)| Position4D::from((x, y, 0, 0))).fields.len(), 64));
}
#[bench]
fn bench_3d(b: &mut test::Bencher) {
let input = parse_input(&read_input(), |(x, y)| Position3D::from((x, y, 0)));
b.iter(|| assert_eq!(solve(&input, 6), 348));
}
#[bench]
fn bench_4d(b: &mut test::Bencher) {
let input = parse_input(&read_input(), |(x, y)| Position4D::from((x, y, 0, 0)));
b.iter(|| assert_eq!(solve(&input, 6), 2236));
}
}

View File

@ -4,7 +4,7 @@ use itertools::iproduct;
use std::{convert::TryInto, hash::Hash, ops, ops::AddAssign};
pub trait Position
where Self: Sized + Hash + Eq
where Self: Sized + Hash + PartialEq + Eq + Clone + Copy
{
fn neighbors(&self) -> Vec<Self>;
}
@ -22,6 +22,14 @@ pub struct Position3D {
pub z: i64,
}
#[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)]
pub struct Position4D {
pub x: i64,
pub y: i64,
pub z: i64,
pub w: i64,
}
mod p2d {
use super::*;
@ -131,6 +139,50 @@ mod p3d {
});
}
mod p4d {
use super::*;
impl Position for Position4D {
fn neighbors(&self) -> Vec<Position4D> {
iproduct!((-1..=1), (-1..=1), (-1..=1), (-1..=1))
.filter(|t| t != &(0, 0, 0, 0))
.map(|(x, y, z, w)| *self + Position4D::from((x, y, z, w)))
.collect()
}
}
impl<I> From<(I, I, I, I)> for Position4D
where I: TryInto<i64>
{
fn from((x, y, z, w): (I, I, I, I)) -> Position4D {
Position4D {
x: unwrap_number_result(x),
y: unwrap_number_result(y),
z: unwrap_number_result(z),
w: unwrap_number_result(w),
}
}
}
impl_op!(-|a: Position4D, b: Position4D| -> Position4D {
Position4D {
x: a.x - b.x,
y: a.y - b.y,
z: a.z - b.z,
w: a.w - b.w,
}
});
impl_op!(+|a: Position4D, b: Position4D| -> Position4D {
Position4D {
x: a.x + b.x,
y: a.y + b.y,
z: a.z + b.z,
w: a.w + b.w,
}
});
}
// because calling .unwrap() on a TryInto result isn’t possible without trait bounds on the
// associated Error type.
fn unwrap_number_result<I: TryInto<i64>>(i: I) -> i64 {