Browse Source

Solution for day 17 part 2

main
Inga 🏳‍🌈 2 years ago
parent
commit
e43fb3f11c
  1. 10
      day17-hard/Cargo.toml
  2. 124
      day17-hard/src/game.rs
  3. 78
      day17-hard/src/locations.rs
  4. 21
      day17-hard/src/main.rs

10
day17-hard/Cargo.toml

@ -0,0 +1,10 @@ @@ -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"

124
day17-hard/src/game.rs

@ -0,0 +1,124 @@ @@ -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()
}
}

78
day17-hard/src/locations.rs

@ -0,0 +1,78 @@ @@ -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]]
}
}

21
day17-hard/src/main.rs

@ -0,0 +1,21 @@ @@ -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…
Cancel
Save