parent
dc69aea676
commit
e43fb3f11c
@ -0,0 +1,10 @@ |
|||||||
|
[package] |
||||||
|
name = "day17-hard" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["inga-lovinde <52715130+inga-lovinde@users.noreply.github.com>"] |
||||||
|
edition = "2018" |
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
ndarray = "0.14.0" |
@ -0,0 +1,124 @@ |
|||||||
|
use ndarray::Array4; |
||||||
|
|
||||||
|
use crate::locations::{CellLocation, MINICUBE_DIFF_ARRAY}; |
||||||
|
|
||||||
|
struct CellInfo { |
||||||
|
is_alive: bool, |
||||||
|
alive_minicube_count: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for CellInfo { |
||||||
|
fn default() -> CellInfo { |
||||||
|
CellInfo { |
||||||
|
is_alive: false, |
||||||
|
alive_minicube_count: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl CellInfo { |
||||||
|
pub fn set_alive(&mut self) { |
||||||
|
self.is_alive = true; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_alive_minicube(&mut self) { |
||||||
|
self.alive_minicube_count += 1; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set_dead(&mut self) { |
||||||
|
self.is_alive = false; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn add_dead_minicube(&mut self) { |
||||||
|
self.alive_minicube_count -= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub const MAX_NUMBER_OF_STEPS: usize = 30; |
||||||
|
|
||||||
|
pub struct Game { |
||||||
|
board: Array4<CellInfo>, |
||||||
|
corner: CellLocation, |
||||||
|
} |
||||||
|
|
||||||
|
impl Game { |
||||||
|
fn make_alive(&mut self, cell_location: CellLocation) { |
||||||
|
self.board[cell_location].set_alive(); |
||||||
|
for &diff in &MINICUBE_DIFF_ARRAY { |
||||||
|
self.board[cell_location + diff].add_alive_minicube(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn make_dead(&mut self, cell_location: CellLocation) { |
||||||
|
self.board[cell_location].set_dead(); |
||||||
|
for &diff in &MINICUBE_DIFF_ARRAY { |
||||||
|
self.board[cell_location + diff].add_dead_minicube(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn next_step(&mut self) -> usize { |
||||||
|
let mut new_alive: Vec<_> = vec![]; |
||||||
|
let mut new_dead: Vec<_> = vec![]; |
||||||
|
for x in 0..self.corner.x { |
||||||
|
for y in 0..self.corner.y { |
||||||
|
for z in 0..self.corner.z { |
||||||
|
for w in 0..self.corner.w { |
||||||
|
let location = CellLocation { x, y, z, w }; |
||||||
|
match &self.board[location] { |
||||||
|
CellInfo { is_alive: true, alive_minicube_count } if *alive_minicube_count < 3 || *alive_minicube_count > 4 => { |
||||||
|
new_dead.push(location); |
||||||
|
}, |
||||||
|
CellInfo { is_alive: false, alive_minicube_count: 3 } => { |
||||||
|
new_alive.push(location); |
||||||
|
}, |
||||||
|
_ => {} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let changes_count = new_alive.len() + new_dead.len(); |
||||||
|
for location in new_alive { |
||||||
|
self.make_alive(location); |
||||||
|
} |
||||||
|
for location in new_dead { |
||||||
|
self.make_dead(location); |
||||||
|
} |
||||||
|
|
||||||
|
changes_count |
||||||
|
} |
||||||
|
|
||||||
|
pub fn from_input(input_data: &[String]) -> Self { |
||||||
|
let rows = input_data.len(); |
||||||
|
let columns = input_data[0].len(); |
||||||
|
let corner = CellLocation { |
||||||
|
x: rows + 2*MAX_NUMBER_OF_STEPS, |
||||||
|
y: columns + 2*MAX_NUMBER_OF_STEPS, |
||||||
|
z: 1 + 2*MAX_NUMBER_OF_STEPS, |
||||||
|
w: 1 + 2*MAX_NUMBER_OF_STEPS, |
||||||
|
}; |
||||||
|
let board = Array4::default((corner.x, corner.y, corner.z, corner.w)); |
||||||
|
let mut game = Game { |
||||||
|
board, |
||||||
|
corner, |
||||||
|
}; |
||||||
|
|
||||||
|
for row in 0..rows { |
||||||
|
let chars = input_data[row].chars().collect::<Vec<_>>(); |
||||||
|
for column in 0..columns { |
||||||
|
let ch = chars[column]; |
||||||
|
if ch == '#' { |
||||||
|
game.make_alive(CellLocation { x: row + MAX_NUMBER_OF_STEPS, y: column + MAX_NUMBER_OF_STEPS, z: MAX_NUMBER_OF_STEPS, w: MAX_NUMBER_OF_STEPS }); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return game; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_alive_count(&self) -> usize { |
||||||
|
(&self.board).iter().filter(|&cell| cell.is_alive).count() |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,78 @@ |
|||||||
|
use std::ops::{Add, Index, IndexMut}; |
||||||
|
|
||||||
|
use ndarray::Array4; |
||||||
|
|
||||||
|
#[derive(Copy, Clone)] |
||||||
|
pub struct CellDiff { |
||||||
|
x: i8, |
||||||
|
y: i8, |
||||||
|
z: i8, |
||||||
|
w: i8, |
||||||
|
} |
||||||
|
|
||||||
|
const fn build_minicube_diff_array() -> [CellDiff; 81] { |
||||||
|
let mut result: [CellDiff; 81] = [CellDiff { x: 0, y: 0, z: 0, w: 0 }; 81]; |
||||||
|
let mut x = -1; |
||||||
|
let mut y = -1; |
||||||
|
let mut z = -1; |
||||||
|
let mut w = -1; |
||||||
|
loop { |
||||||
|
result[((x*27+y*9+z*3+w) + 40) as usize] = CellDiff {x, y, z, w }; |
||||||
|
|
||||||
|
w += 1; |
||||||
|
if w == 2 { |
||||||
|
w -= 3; |
||||||
|
z += 1; |
||||||
|
} |
||||||
|
if z == 2 { |
||||||
|
z -= 3; |
||||||
|
y += 1; |
||||||
|
} |
||||||
|
if y == 2 { |
||||||
|
y -= 3; |
||||||
|
x += 1; |
||||||
|
} |
||||||
|
if x == 2 { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
result |
||||||
|
} |
||||||
|
|
||||||
|
pub const MINICUBE_DIFF_ARRAY: [CellDiff; 81] = build_minicube_diff_array(); |
||||||
|
|
||||||
|
#[derive(Copy, Clone)] |
||||||
|
pub struct CellLocation { |
||||||
|
pub x: usize, |
||||||
|
pub y: usize, |
||||||
|
pub z: usize, |
||||||
|
pub w: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl Add<CellDiff> for CellLocation { |
||||||
|
type Output = Self; |
||||||
|
|
||||||
|
fn add(self, other: CellDiff) -> Self { |
||||||
|
CellLocation { |
||||||
|
x: (self.x as isize + other.x as isize) as usize, |
||||||
|
y: (self.y as isize + other.y as isize) as usize, |
||||||
|
z: (self.z as isize + other.z as isize) as usize, |
||||||
|
w: (self.w as isize + other.w as isize) as usize, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Index<CellLocation> for Array4<T> { |
||||||
|
type Output = T; |
||||||
|
fn index<'a>(&'a self, cell_location: CellLocation) -> &'a T { |
||||||
|
&self[[cell_location.x, cell_location.y, cell_location.z, cell_location.w]] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> IndexMut<CellLocation> for Array4<T> { |
||||||
|
fn index_mut<'a>(&'a mut self, cell_location: CellLocation) -> &'a mut T { |
||||||
|
&mut self[[cell_location.x, cell_location.y, cell_location.z, cell_location.w]] |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,21 @@ |
|||||||
|
use std::io::{self, BufRead}; |
||||||
|
|
||||||
|
mod game; |
||||||
|
mod locations; |
||||||
|
|
||||||
|
use crate::game::{Game, MAX_NUMBER_OF_STEPS}; |
||||||
|
|
||||||
|
fn main() { |
||||||
|
let stdin = io::stdin(); |
||||||
|
let lines: Vec<_> = stdin.lock().lines().map(|line| line.unwrap()).collect(); |
||||||
|
|
||||||
|
let mut game = Game::from_input(&lines); |
||||||
|
|
||||||
|
for i in 1..MAX_NUMBER_OF_STEPS { |
||||||
|
let changes_count = game.next_step(); |
||||||
|
println!("Iteration {}; changed cells: {}; alive_cells: {}", i, changes_count, game.get_alive_count()); |
||||||
|
if changes_count == 0 { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue