[TASK[ Finished day 17

This commit is contained in:
2020-12-17 21:45:27 +01:00
parent 040965a034
commit 9967283916
6 changed files with 288 additions and 3 deletions

8
input/day17.txt Normal file
View File

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

3
input/day17_example.txt Normal file
View File

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

View File

@@ -33,7 +33,7 @@ fn play_until(max_turn: usize, starting_numbers: &Vec<usize>) -> usize {
} else {
previous_number = turn - prev_occurrence;
}
println!("Turn {}: {}", turn + 1, previous_number);
// println!("Turn {}: {}", turn + 1, previous_number);
}
return previous_number;

View File

@@ -58,7 +58,7 @@ fn not_in_ranges(n: &u32, ranges: &Vec<ValidRange>) -> bool {
fn resolve_column_ordering(tickets: &Vec<&Vec<u32>>, range_sets: &Vec<ValidRangeSet>) -> Vec<ValidRangeSet> {
let mut available_order_per_range_set = Vec::new();
for i in 0..range_sets.len() {
for _ in 0..range_sets.len() {
available_order_per_range_set.push(vec!{ true; range_sets.len() });
}
let mut solved_range_sets = vec!{ false; range_sets.len() };

272
src/day17.rs Normal file
View File

@@ -0,0 +1,272 @@
use super::util;
use std::cmp::{min, max};
pub fn solve() {
let lines = util::read_file("input/day17.txt");
let initial_width = lines[0].len() as i32;
let initial_height = lines.len() as i32;
let cycles = 6;
// The grid grows by at most 1 index per cycle, so this should be big enough:
let lower = Vec4::of(-cycles-1, -cycles-1, -cycles-1, -cycles-1);
let upper = Vec4::of(initial_width + cycles+1, initial_height + cycles+1, cycles + 2, cycles + 2);
let mut initial_state = BoolGrid3D::new(lower, upper);
for y in 0..initial_height {
let mut line_chars = lines[y as usize].chars();
for x in 0..initial_width {
if line_chars.next().unwrap() == '#' {
initial_state.set(&x, &y, &0, &0, true);
}
}
}
let res1 = run_conway_cube_simulation(&initial_state, cycles as u32, true);
let part1: u32 = res1.data.data.iter().map(|c| c.count_ones()).sum();
println!("Day 17 Part 1: {}", part1);
let res2 = run_conway_cube_simulation(&initial_state, cycles as u32, false);
let part2: u32 = res2.data.data.iter().map(|c| c.count_ones()).sum();
println!("Day 17 Part 2: {}", part2);
}
fn run_conway_cube_simulation(initial_state: &BoolGrid3D, cycles: u32, restrict_fourth_dimension: bool) -> BoolGrid3D {
let mut prev_state = initial_state.clone();
let mut next_state = initial_state.clone();
let mut lower_activity = Vec4::of(initial_state.lower.x + 1, initial_state.lower.y + 1, initial_state.lower.z + 1,
if restrict_fourth_dimension { 0 } else { initial_state.lower.w + 1 });
let mut upper_activity = Vec4::of(initial_state.upper.x - 1, initial_state.upper.y - 1, initial_state.upper.z - 1,
if restrict_fourth_dimension { 1 } else { initial_state.upper.w - 1 });
for _cycle in 0..cycles {
let mut next_lower_activity = prev_state.upper.clone();
let mut next_upper_activity = prev_state.lower.clone();
if restrict_fourth_dimension {
next_lower_activity.w = 0;
next_upper_activity.w = 1;
}
for w in lower_activity.w..upper_activity.w {
for z in lower_activity.z..upper_activity.z {
for y in lower_activity.y..upper_activity.y {
for x in lower_activity.x..upper_activity.x {
let active_neighbors: usize = prev_state.count_active_neighbors(&x, &y, &z, &w, &restrict_fourth_dimension, 4);
let active_self = prev_state.get(&x, &y, &z, &w);
let active_next = (active_self && (active_neighbors == 2 || active_neighbors == 3)) || (!active_self && active_neighbors == 3);
next_state.set(&x, &y, &z, &w, active_next);
if active_next != active_self {
next_lower_activity.x = min(next_lower_activity.x, x - 1);
next_lower_activity.y = min(next_lower_activity.y, y - 1);
next_lower_activity.z = min(next_lower_activity.z, z - 1);
next_upper_activity.x = max(next_upper_activity.x, x + 2);
next_upper_activity.y = max(next_upper_activity.y, y + 2);
next_upper_activity.z = max(next_upper_activity.z, z + 2);
if !restrict_fourth_dimension {
next_lower_activity.w = min(next_lower_activity.w, w - 1);
next_upper_activity.w = max(next_upper_activity.w, w + 2);
}
}
}
}
}
}
lower_activity = next_lower_activity;
upper_activity = next_upper_activity;
// if !restrict_fourth_dimension {
// println!("After {} cycles:", _cycle + 1);
// next_state.print();
// }
if lower_activity.x >= upper_activity.x {
panic!("No activity!");
}
prev_state = next_state.clone();
}
return prev_state;
}
#[derive(Clone)]
struct Vec4 {
x: i32,
y: i32,
z: i32,
w: i32
}
impl Vec4 {
fn of(x: i32, y: i32, z: i32, w: i32) -> Vec4 {
return Vec4 { x, y, z, w };
}
}
#[derive(Clone)]
struct BoolGrid3D {
data: BitArray,
lower: Vec4,
upper: Vec4,
size: Vec4,
}
impl BoolGrid3D {
fn new(lower: Vec4, upper: Vec4) -> BoolGrid3D {
assert!(lower.x < upper.x && lower.y < upper.y && lower.z < upper.z);
let size = Vec4 {
x: upper.x - lower.x,
y: upper.y - lower.y,
z: upper.z - lower.z,
w: upper.w - lower.w
};
return BoolGrid3D {
data: BitArray::new((size.x * size.y * size.z * size.w) as usize, false),
lower, upper, size
}
}
fn get_idx(&self, x: &i32, y: &i32, z: &i32, w: &i32) -> usize {
assert!(x >= &self.lower.x && x < &self.upper.x);
assert!(y >= &self.lower.y && y < &self.upper.y);
assert!(z >= &self.lower.z && z < &self.upper.z);
assert!(w >= &self.lower.w && w < &self.upper.w);
return (x - self.lower.x) as usize +
(y - self.lower.y) as usize * self.size.x as usize +
(z - self.lower.z) as usize * self.size.x as usize * self.size.y as usize +
(w - self.lower.w) as usize * self.size.x as usize * self.size.y as usize * self.size.z as usize;
}
fn get(&self, x: &i32, y: &i32, z: &i32, w: &i32) -> bool {
return self.data.get(self.get_idx(x, y, z, w));
}
fn set(&mut self, x: &i32, y: &i32, z: &i32, w: &i32, v: bool) {
let idx = self.get_idx(x, y, z, w);
self.data.set(idx, v);
}
fn count_active_neighbors(&self, x: &i32, y: &i32, z: &i32, w: &i32, restrict_fourth_dimension: &bool, count_until: usize) -> usize {
assert!(x - 1 >= self.lower.x && x + 1 < self.upper.x);
assert!(y - 1 >= self.lower.y && y + 1 < self.upper.y);
assert!(z - 1 >= self.lower.z && z + 1 < self.upper.z);
assert!(w - 1 >= self.lower.w && w + 1 < self.upper.w);
let mut res = 0;
for nw in if *restrict_fourth_dimension { *w..w+1 } else { w-1..w+2 } {
for nz in z - 1..z + 2 {
for ny in y - 1..y + 2 {
for nx in x - 1..x + 2 {
// Skip self (i.e. not the neighbor)
if &nz == z && &ny == y && &nx == x && &nw == w { continue };
if self.get(&nx, &ny, &nz, &nw) {
res += 1;
if res >= count_until {
return res;
}
}
}
}
}
}
return res;
}
#[allow(dead_code)]
fn print(&self) {
for w in self.lower.w..self.upper.w {
if !self.any_in_w(&w) { continue; }
for z in self.lower.z..self.upper.z {
if !self.any_in_wz(&w, &z) { continue; }
println!("z={}, w={}", z, w);
for y in self.lower.y..self.upper.y {
for x in self.lower.x..self.upper.x {
print!("{}", if self.get(&x, &y, &z, &0) { '#' } else { '.' });
}
println!();
}
}
}
}
fn any_in_w(&self, w: &i32) -> bool {
for i in self.get_idx(&self.lower.x, &self.lower.y, &self.lower.z, w)..
(self.get_idx(&(self.upper.x - 1), &(self.upper.y - 1), &(self.upper.z - 1), w) + 1) {
if self.data.get(i) { return true; }
}
return false;
}
fn any_in_wz(&self, w: &i32, z: &i32) -> bool {
for i in self.get_idx(&self.lower.x, &self.lower.y, z, w)..
(self.get_idx(&(self.upper.x - 1), &(self.upper.y - 1), z, w) + 1) {
if self.data.get(i) { return true; }
}
return false;
}
}
#[derive(Clone)]
struct BitArray {
data: Vec<u32>,
length: usize,
}
impl BitArray {
fn new(length: usize, default: bool) -> BitArray {
return BitArray{
data: vec!{if default { !0 } else { 0 }; (length / 32) + 1},
length,
}
}
fn get(&self, i: usize) -> bool {
return BitArray::get_bit(&self.data[i / 32], &(i % 32));
}
fn get_bit(d: &u32, i: &usize) -> bool {
return d & (1 << i) != 0
}
fn set(&mut self, i: usize, v: bool) {
let mask = 1 << (i % 32);
self.data[i / 32] &= !mask;
if v { self.data[i / 32] |= mask; }
}
}

View File

@@ -18,8 +18,9 @@ mod day13;
mod day14;
mod day15;
mod day16;
mod day17;
const MAX_DAY: u8 = 16;
const MAX_DAY: u8 = 17;
const BENCHMARK_AMOUNT: u32 = 100;
fn solve(day: u8) {
@@ -40,6 +41,7 @@ fn solve(day: u8) {
14 => day14::solve(),
15 => day15::solve(),
16 => day16::solve(),
17 => day17::solve(),
_ => println!("This day is not yet implemented")
}
}