add day 17

This commit is contained in:
echo 2020-12-17 20:54:17 -05:00
parent 1a5c98aa4d
commit 5fd6ab1156
5 changed files with 184 additions and 0 deletions

16
Cargo.lock generated
View file

@ -5,6 +5,7 @@ name = "advent_of_code_2020"
version = "0.1.0"
dependencies = [
"clap",
"itertools",
"num_enum",
]
@ -74,6 +75,12 @@ dependencies = [
"syn",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "hashbrown"
version = "0.9.1"
@ -108,6 +115,15 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "lazy_static"
version = "1.4.0"

View file

@ -9,3 +9,4 @@ edition = "2018"
[dependencies]
clap = "3.0.0-beta.2"
num_enum = "0.5.1"
itertools = "0.9.0"

8
input/day17 Normal file
View file

@ -0,0 +1,8 @@
##.#....
...#...#
.#.#.##.
..#.#...
.###....
.##.#...
#.##..##
#.####..

157
src/day17.rs Normal file
View file

@ -0,0 +1,157 @@
use std::io::BufRead;
use std::collections::HashSet;
use std::ops::RangeInclusive;
use itertools::Itertools;
#[derive(Debug, PartialEq)]
struct PocketDimension {
active_cubes: HashSet<Vec<i32>>,
bbox: Vec<RangeInclusive<i32>>,
}
impl PocketDimension {
fn with_dimension_count(dimensions: usize) -> Self {
PocketDimension {
active_cubes: HashSet::new(),
bbox: (0..dimensions).map(|_| 0..=0).collect()
}
}
fn init_from_str(&mut self, s: &str) {
self.active_cubes = s.lines()
.enumerate()
.map(|(line_idx, line)|
line.chars()
.enumerate()
.filter(|(_idx, ch)| *ch == '#')
.map(|(idx, _ch)| {
let mut cube = vec![0; self.bbox.len()];
cube[0] = idx as i32;
cube[1] = line_idx as i32;
cube
}).collect::<HashSet<_>>()
).fold(HashSet::new(), |acc, coords| {
acc.union(&coords).cloned().collect()
});
self.update_bbox();
}
fn update_bbox(&mut self) {
let mut it = self.active_cubes.iter();
let first = it.next().unwrap();
let mut new_box: Vec<(i32, i32)> = first.iter().map(|c| (*c, *c)).collect();
for cube in it {
for (dimension, coord) in cube.iter().enumerate() {
if *coord < new_box[dimension].0 {
new_box[dimension].0 = *coord;
} else if *coord > new_box[dimension].1 {
new_box[dimension].1 = *coord;
}
}
}
for (dimension, range) in new_box.iter().enumerate() {
self.bbox[dimension] = (range.0 - 1)..=(range.1 + 1);
}
}
fn tick(&mut self) {
let active_cubes = self.bbox.iter().cloned()
.multi_cartesian_product()
.filter_map(|cube| {
let count = self.neighbours_count(&cube);
if self.active_cubes.contains(&cube) && (2..=3).contains(&count) {
Some(cube)
} else if !self.active_cubes.contains(&cube) && count == 3 {
Some(cube)
} else {
None
}
}).collect();
self.active_cubes = active_cubes;
self.update_bbox()
}
fn neighbours_count(&self, center_cube: &Vec<i32>) -> usize {
center_cube.iter().map(|c| (c - 1)..=(c + 1))
.multi_cartesian_product()
.filter(|cube| cube != center_cube && self.active_cubes.contains(cube))
.count()
}
fn simulate(&mut self, cycle_count: usize) {
(0..cycle_count).for_each(|_| self.tick());
}
}
pub fn part1<F: BufRead> (mut input: F) {
let mut buffer = String::new();
input.read_to_string(&mut buffer).unwrap();
let mut pocket = PocketDimension::with_dimension_count(3);
pocket.init_from_str(&buffer);
pocket.simulate(6);
println!("{}", pocket.active_cubes.len());
}
pub fn part2<F: BufRead> (mut input: F) {
let mut buffer = String::new();
input.read_to_string(&mut buffer).unwrap();
let mut pocket = PocketDimension::with_dimension_count(4);
pocket.init_from_str(&buffer);
pocket.simulate(6);
println!("{}", pocket.active_cubes.len());
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_parse() {
let input = ".#.\n..#\n###";
let expected = PocketDimension {
active_cubes: [vec![1, 0, 0], vec![2, 1, 0], vec![0, 2, 0], vec![1, 2, 0], vec![2, 2, 0]].iter().cloned().collect(),
bbox: vec![
-1..=3,
-1..=3,
-1..=1,
]
};
let mut pocket = PocketDimension::with_dimension_count(3);
pocket.init_from_str(input);
assert_eq!(expected, pocket);
}
#[test]
pub fn test_simulate3d() {
let mut pocket = PocketDimension {
active_cubes: [vec![1, 0, 0], vec![2, 1, 0], vec![0, 2, 0], vec![1, 2, 0], vec![2, 2, 0]].iter().cloned().collect(),
bbox: vec![
-1..=3,
-1..=3,
-1..=1,
]
};
pocket.simulate(6);
assert_eq!(112, pocket.active_cubes.len());
}
#[test]
pub fn test_simulate4d() {
let mut pocket = PocketDimension {
active_cubes: [vec![1, 0, 0, 0], vec![2, 1, 0, 0], vec![0, 2, 0, 0], vec![1, 2, 0, 0], vec![2, 2, 0, 0]].iter().cloned().collect(),
bbox: vec![
-1..=3,
-1..=3,
-1..=1,
-1..=1,
]
};
pocket.simulate(6);
assert_eq!(848, pocket.active_cubes.len());
}
}

View file

@ -21,6 +21,7 @@ mod day14;
mod day14part2;
mod day15;
mod day16;
mod day17;
fn main() {
let matches = App::new("Advent of Code 2020")
@ -66,6 +67,7 @@ fn main() {
day14::part1, day14part2::part2,
day15::part1, day15::part2,
day16::part1, day16::part2,
day17::part1, day17::part2,
];
if let Some(f) = challenges.get(challenge) {