Solution for day 24 (part 2)

main
Inga 🏳‍🌈 4 years ago
parent b6ff7fb54b
commit 574e1422af
  1. 1
      day24/Cargo.toml
  2. 121
      day24/src/game.rs
  3. 49
      day24/src/locations.rs
  4. 40
      day24/src/main.rs

@ -7,3 +7,4 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
ndarray = "0.14.0"

@ -0,0 +1,121 @@
use ndarray::Array2;
use crate::locations::{CellLocation, MINICUBE_DIFF_ARRAY};
struct CellInfo {
is_alive: bool, // alive = black, dead = white
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 struct Game {
board: Array2<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 {
let location = CellLocation { x, y };
match &self.board[location] {
CellInfo { is_alive: true, alive_minicube_count } if *alive_minicube_count == 0 || *alive_minicube_count > 2 => {
new_dead.push(location);
},
CellInfo { is_alive: false, alive_minicube_count: 2 } => {
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: &[(i16, i16)], max_number_of_steps: usize) -> Self {
let min_x = input_data.iter().map(|(x, _y)| *x).min().unwrap();
let max_x = input_data.iter().map(|(x, _y)| *x).max().unwrap();
let min_y = input_data.iter().map(|(_x, y)| *y).min().unwrap();
let max_y = input_data.iter().map(|(_x, y)| *y).max().unwrap();
let input_size_x = max_x - min_x;
let input_size_y = max_y - min_y;
let size_x = (input_size_x as usize) + max_number_of_steps * 2;
let size_y = (input_size_y as usize) + max_number_of_steps * 2;
let offset_x = (max_number_of_steps as i16) - min_x;
let offset_y = (max_number_of_steps as i16) - min_y;
let corner = CellLocation {
x: size_x,
y: size_y,
};
let board = Array2::default((corner.x, corner.y));
let mut game = Game {
board,
corner,
};
for (input_x, input_y) in input_data {
game.make_alive(CellLocation {
x: (input_x + offset_x) as usize,
y: (input_y + offset_y) as usize,
});
}
return game;
}
pub fn get_alive_count(&self) -> usize {
(&self.board).iter().filter(|&cell| cell.is_alive).count()
}
}

@ -0,0 +1,49 @@
use std::ops::{Add, Index, IndexMut};
use ndarray::Array2;
#[derive(Copy, Clone)]
pub struct CellDiff {
x: i8,
y: i8,
}
pub const MINICUBE_DIFF_ARRAY: [CellDiff; 6] = [
CellDiff { x: -1, y: 0 },
CellDiff { x: 0, y: 1 },
CellDiff { x: 1, y: 1 },
CellDiff { x: 1, y: 0 },
CellDiff { x: 0, y: -1 },
CellDiff { x: -1, y: -1 },
];
#[derive(Copy, Clone)]
pub struct CellLocation {
pub x: usize,
pub y: 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,
}
}
}
impl<T> Index<CellLocation> for Array2<T> {
type Output = T;
fn index<'a>(&'a self, cell_location: CellLocation) -> &'a T {
&self[[cell_location.x, cell_location.y]]
}
}
impl<T> IndexMut<CellLocation> for Array2<T> {
fn index_mut<'a>(&'a mut self, cell_location: CellLocation) -> &'a mut T {
&mut self[[cell_location.x, cell_location.y]]
}
}

@ -1,35 +1,47 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{self, BufRead}; use std::io::{self, BufRead};
mod game;
mod locations;
use crate::game::Game;
const MAX_NUMBER_OF_STEPS: usize = 100;
fn main() { fn main() {
let stdin = io::stdin(); let stdin = io::stdin();
let mut changed_tiles = HashSet::new(); let mut alive_tiles = HashSet::new();
for line_result in stdin.lock().lines() { for line_result in stdin.lock().lines() {
let processed_line = line_result.unwrap().replace("nw", "7").replace("ne", "9").replace("sw", "1").replace("se", "3"); let processed_line = line_result.unwrap().replace("nw", "n").replace("se", "s");
let mut x = 0; let mut x = 0i16;
let mut y = 0; let mut y = 0i16;
for ch in processed_line.chars() { for ch in processed_line.chars() {
x += match ch { x += match ch {
'e' => 2, 'e' => 1,
'w' => -2, 'w' => -1,
'9' | '3' => 1,
'7' | '1' => -1,
_ => 0, _ => 0,
}; };
y += match ch { y += match ch {
'9' | '7' => 1, 'n' => 1,
'3' | '1' => -1, 's' => -1,
_ => 0, _ => 0,
}; };
} }
let tile = (x, y); let tile = (x, y);
if changed_tiles.contains(&tile) { if alive_tiles.contains(&tile) {
changed_tiles.remove(&tile); alive_tiles.remove(&tile);
} else { } else {
changed_tiles.insert(tile); alive_tiles.insert(tile);
} }
} }
println!("{}", changed_tiles.len()); let mut game = Game::from_input(&alive_tiles.iter().cloned().collect::<Vec<_>>(), MAX_NUMBER_OF_STEPS);
println!("{}", game.get_alive_count());
for i in 1..=MAX_NUMBER_OF_STEPS {
game.next_step();
println!("Day {}: {}", i, game.get_alive_count());
}
} }

Loading…
Cancel
Save