[TASK[ Finished day 17
This commit is contained in:
8
input/day17.txt
Normal file
8
input/day17.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
..##.#.#
|
||||
.#####..
|
||||
#.....##
|
||||
##.##.#.
|
||||
..#...#.
|
||||
.#..##..
|
||||
.#...#.#
|
||||
#..##.##
|
||||
3
input/day17_example.txt
Normal file
3
input/day17_example.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
.#.
|
||||
..#
|
||||
###
|
||||
@@ -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;
|
||||
|
||||
@@ -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
272
src/day17.rs
Normal 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; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user