day17
This commit is contained in:
parent
fe0876afbf
commit
ef4ae63d33
8
data/day17/input
Normal file
8
data/day17/input
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
...#.#.#
|
||||||
|
..#..#..
|
||||||
|
#.#.##.#
|
||||||
|
###.##..
|
||||||
|
#####.##
|
||||||
|
#.......
|
||||||
|
#..#..##
|
||||||
|
...##.##
|
222
src/bin/day17.rs
Normal file
222
src/bin/day17.rs
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
const INPUT: &str = include_str!("../../data/day17/input");
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct Dimension {
|
||||||
|
offset: u32,
|
||||||
|
size: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dimension {
|
||||||
|
fn map(&self, pos: i32) -> Option<usize> {
|
||||||
|
let p = (self.offset as i32) + pos;
|
||||||
|
if p >= 0 && p < (self.size as i32) {
|
||||||
|
Some(p as usize)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn include(&self, pos: i32) -> Self {
|
||||||
|
let left = std::cmp::min(pos, -(self.offset as i32));
|
||||||
|
let right = std::cmp::max(pos, (self.size - self.offset - 1) as i32);
|
||||||
|
Self {
|
||||||
|
offset: (-left) as u32,
|
||||||
|
size: (right - left + 1) as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
offset: self.offset + 1,
|
||||||
|
size: self.size + 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for Dimension {
|
||||||
|
type IntoIter = Range<i32>;
|
||||||
|
type Item = i32;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
-(self.offset as i32)..((self.size - self.offset) as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Field {
|
||||||
|
x_dim: Dimension,
|
||||||
|
y_dim: Dimension,
|
||||||
|
z_dim: Dimension,
|
||||||
|
w_dim: Dimension,
|
||||||
|
cells: Vec<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Field {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
x_dim: Dimension { offset: 0, size: 1},
|
||||||
|
y_dim: Dimension { offset: 0, size: 1},
|
||||||
|
z_dim: Dimension { offset: 0, size: 1},
|
||||||
|
w_dim: Dimension { offset: 0, size: 1},
|
||||||
|
cells: vec![false],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
fn alloc(x_dim: Dimension, y_dim: Dimension, z_dim: Dimension, w_dim: Dimension) -> Self {
|
||||||
|
let mut cells = Vec::new();
|
||||||
|
let size = (x_dim.size * y_dim.size * z_dim.size * w_dim.size) as usize;
|
||||||
|
cells.resize(size, false);
|
||||||
|
Self { x_dim, y_dim, z_dim, w_dim, cells }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _addr(&self, x: i32, y: i32, z: i32, w: i32) -> Option<usize> {
|
||||||
|
let x = self.x_dim.map(x)?;
|
||||||
|
let y = self.y_dim.map(y)?;
|
||||||
|
let z = self.z_dim.map(z)?;
|
||||||
|
let w = self.w_dim.map(w)?;
|
||||||
|
let addr = ((w * (self.z_dim.size as usize) + z) * (self.y_dim.size as usize) + y) * (self.x_dim.size as usize) + x;
|
||||||
|
Some(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _get(&self, x: i32, y: i32, z: i32, w: i32) -> Option<bool> {
|
||||||
|
let addr = self._addr(x, y, z, w)?;
|
||||||
|
Some(self.cells[addr])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, x: i32, y: i32, z: i32, w: i32) -> bool {
|
||||||
|
self._get(x, y, z, w).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, x: i32, y: i32, z: i32, w: i32, value: bool) {
|
||||||
|
if let Some(addr) = self._addr(x, y, z, w) {
|
||||||
|
self.cells[addr] = value;
|
||||||
|
} else if value {
|
||||||
|
// don't resize to set "false"
|
||||||
|
let x_dim = self.x_dim.include(x);
|
||||||
|
let y_dim = self.y_dim.include(y);
|
||||||
|
let z_dim = self.z_dim.include(z);
|
||||||
|
let w_dim = self.w_dim.include(w);
|
||||||
|
let mut new_field = Self::alloc(x_dim, y_dim, z_dim, w_dim);
|
||||||
|
for w in self.w_dim {
|
||||||
|
for z in self.z_dim {
|
||||||
|
for y in self.y_dim {
|
||||||
|
for x in self.x_dim {
|
||||||
|
let addr = new_field._addr(x, y, z, w).unwrap();
|
||||||
|
new_field.cells[addr] = self.get(x, y, z, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let addr = new_field._addr(x, y, z, w).unwrap();
|
||||||
|
new_field.cells[addr] = value;
|
||||||
|
*self = new_field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(data: &str) -> Self {
|
||||||
|
let mut this = Self::default();
|
||||||
|
for (y, line) in data.lines().enumerate() {
|
||||||
|
for (x, chr) in line.chars().enumerate() {
|
||||||
|
this.set(x as i32, y as i32, 0, 0, chr == '#');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_active_neighbors(&self, x: i32, y: i32, z: i32, w: i32) -> u32 {
|
||||||
|
let mut count = 0;
|
||||||
|
for dw in -1..=1 {
|
||||||
|
for dz in -1..=1 {
|
||||||
|
for dy in -1..=1 {
|
||||||
|
for dx in -1..=1 {
|
||||||
|
if dw == 0 && dz == 0 && dy == 0 && dx == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.get(x + dx, y + dy, z + dz, w + dw) {
|
||||||
|
count += 1;
|
||||||
|
if count > 3 { return count; } // more than 3 is always bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cycle_3dim(&self) -> Self {
|
||||||
|
let mut result = self.clone();
|
||||||
|
let w = 0;
|
||||||
|
for z in self.z_dim.extend() {
|
||||||
|
for y in self.y_dim.extend() {
|
||||||
|
for x in self.x_dim.extend() {
|
||||||
|
let count = self.count_active_neighbors(x, y, z, w);
|
||||||
|
let active = count == 3 || (count == 2 && self.get(x, y, z, w));
|
||||||
|
result.set(x, y, z, w, active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cycle_4dim(&self) -> Self {
|
||||||
|
let mut result = self.clone();
|
||||||
|
for w in self.w_dim.extend() {
|
||||||
|
for z in self.z_dim.extend() {
|
||||||
|
for y in self.y_dim.extend() {
|
||||||
|
for x in self.x_dim.extend() {
|
||||||
|
let count = self.count_active_neighbors(x, y, z, w);
|
||||||
|
let active = count == 3 || (count == 2 && self.get(x, y, z, w));
|
||||||
|
result.set(x, y, z, w, active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Field {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
use std::fmt::Write;
|
||||||
|
for z in self.z_dim {
|
||||||
|
for w in self.w_dim {
|
||||||
|
writeln!(f, "z = {}, w = {}", z, w)?;
|
||||||
|
for y in self.y_dim {
|
||||||
|
for x in self.x_dim {
|
||||||
|
if x == 0 && y == 0 {
|
||||||
|
f.write_char(
|
||||||
|
if self.get(x, y, z, w) { 'X' } else { '+' }
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
f.write_char(
|
||||||
|
if self.get(x, y, z, w) { '#' } else { '.' }
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.write_char('\n')?;
|
||||||
|
}
|
||||||
|
f.write_char('\n')?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input = Field::parse(INPUT);
|
||||||
|
let mut field = input.clone();
|
||||||
|
for _ in 0..6 {
|
||||||
|
field = field.cycle_3dim();
|
||||||
|
}
|
||||||
|
println!("Active after 6 3-dim rounds: {}", field.cells.iter().filter(|&&c| c).count());
|
||||||
|
let mut field = input.clone();
|
||||||
|
for _ in 0..6 {
|
||||||
|
field = field.cycle_4dim();
|
||||||
|
}
|
||||||
|
println!("Active after 6 4-dim rounds: {}", field.cells.iter().filter(|&&c| c).count());
|
||||||
|
println!("{:?}", input);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user