parent
f777a09f63
commit
07e6072465
@ -0,0 +1,104 @@ |
|||||||
|
use enum_map::Enum; |
||||||
|
use strum_macros::EnumIter; |
||||||
|
|
||||||
|
#[derive(Clone, Copy, Enum, Eq, PartialEq)] |
||||||
|
pub enum State { |
||||||
|
None, |
||||||
|
Floor, |
||||||
|
SeatEmpty, |
||||||
|
SeatOccupied, |
||||||
|
} |
||||||
|
|
||||||
|
impl Default for State { |
||||||
|
fn default() -> Self { Self::None } |
||||||
|
} |
||||||
|
|
||||||
|
impl State { |
||||||
|
fn from_number(number: u8) -> Self { |
||||||
|
match number { |
||||||
|
0 => Self::None, |
||||||
|
1 => Self::Floor, |
||||||
|
2 => Self::SeatEmpty, |
||||||
|
3 => Self::SeatOccupied, |
||||||
|
_ => panic!("unsupported number {}", number), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_number(&self) -> u8 { |
||||||
|
match self { |
||||||
|
Self::None => 0, // border should always be 0
|
||||||
|
Self::Floor => 1, |
||||||
|
Self::SeatEmpty => 2, |
||||||
|
Self::SeatOccupied => 3, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Copy, Clone, Enum, EnumIter)] |
||||||
|
pub enum Direction { |
||||||
|
UpLeft, |
||||||
|
Up, |
||||||
|
UpRight, |
||||||
|
Left, |
||||||
|
Right, |
||||||
|
DownLeft, |
||||||
|
Down, |
||||||
|
DownRight, |
||||||
|
} |
||||||
|
|
||||||
|
impl Direction { |
||||||
|
fn get_offset(&self) -> u16 { |
||||||
|
match self { |
||||||
|
Self::UpLeft => 0, |
||||||
|
Self::Up => 2, |
||||||
|
Self::UpRight => 4, |
||||||
|
Self::Left => 6, |
||||||
|
Self::Right => 8, |
||||||
|
Self::DownLeft => 10, |
||||||
|
Self::Down => 12, |
||||||
|
Self::DownRight => 14, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct CellState { |
||||||
|
neighbours_states: u16, |
||||||
|
state: u8, |
||||||
|
} |
||||||
|
|
||||||
|
impl CellState { |
||||||
|
pub fn new() -> Self { |
||||||
|
Self { |
||||||
|
neighbours_states: 0, |
||||||
|
state: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn update_neighbour_state(&mut self, direction: Direction, new_state: State) -> () { |
||||||
|
self.neighbours_states = (self.neighbours_states & !(0b11 << direction.get_offset())) | ((new_state.get_number() as u16) << direction.get_offset()); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn update_state(&mut self, new_state: State) { |
||||||
|
self.state = new_state.get_number(); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn from_number(number: u32) -> Self { |
||||||
|
CellState { |
||||||
|
state: (number >> 16) as u8, |
||||||
|
neighbours_states: (number & 0xffff) as u16, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_number(&self) -> u32 { |
||||||
|
((self.state as u32) << 16) | (self.neighbours_states as u32) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_state(&self) -> State { |
||||||
|
State::from_number(self.state) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_neighbour_state(&self, direction: Direction) -> State { |
||||||
|
State::from_number(((self.neighbours_states >> direction.get_offset()) & 0b11) as u8) |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,85 @@ |
|||||||
|
use std::default::Default; |
||||||
|
use std::ops::{Index, IndexMut}; |
||||||
|
use ndarray::Array2; |
||||||
|
|
||||||
|
use crate::binary::Direction; |
||||||
|
|
||||||
|
#[derive(Copy, Clone)] |
||||||
|
pub struct CellLocation { |
||||||
|
row: usize, |
||||||
|
column: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl CellLocation { |
||||||
|
pub fn new(row: usize, column: usize) -> Self { |
||||||
|
Self { |
||||||
|
row, |
||||||
|
column, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn new_option(row_option: Option<usize>, column_option: Option<usize>) -> Option<Self> { |
||||||
|
match (row_option, column_option) { |
||||||
|
(Some(row), Some(column)) => Some(Self::new(row, column)), |
||||||
|
_ => None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Index<CellLocation> for Array2<T> { |
||||||
|
type Output = T; |
||||||
|
fn index<'a>(&'a self, cell_location: CellLocation) -> &'a T { |
||||||
|
&self[[cell_location.row, cell_location.column]] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> IndexMut<CellLocation> for Array2<T> { |
||||||
|
fn index_mut<'a>(&'a mut self, cell_location: CellLocation) -> &'a mut T { |
||||||
|
&mut self[[cell_location.row, cell_location.column]] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct BoardMetadata { |
||||||
|
rows: usize, |
||||||
|
columns: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl BoardMetadata { |
||||||
|
pub fn new(rows: usize, columns: usize) -> Self { |
||||||
|
BoardMetadata { |
||||||
|
rows, |
||||||
|
columns, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_neighbour_location(&self, cell_location: CellLocation, direction: Direction) -> Option<CellLocation> { |
||||||
|
let row = cell_location.row; |
||||||
|
let column = cell_location.column; |
||||||
|
|
||||||
|
let up = if row > 0 { Some(row-1) } else { None }; |
||||||
|
let middle = Some(row); |
||||||
|
let down = if row < self.rows-1 { Some(row+1) } else { None }; |
||||||
|
let left = if column > 0 { Some(column-1) } else { None }; |
||||||
|
let center = Some(column); |
||||||
|
let right = if column < self.columns-1 { Some(column+1) } else { None }; |
||||||
|
|
||||||
|
match direction { |
||||||
|
Direction::UpLeft => CellLocation::new_option(up, left), |
||||||
|
Direction::Up => CellLocation::new_option(up, center), |
||||||
|
Direction::UpRight => CellLocation::new_option(up, right), |
||||||
|
Direction::Left => CellLocation::new_option(middle, left), |
||||||
|
Direction::Right => CellLocation::new_option(middle, right), |
||||||
|
Direction::DownLeft => CellLocation::new_option(down, left), |
||||||
|
Direction::Down => CellLocation::new_option(down, center), |
||||||
|
Direction::DownRight => CellLocation::new_option(down, right), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_board_default<T: Default>(&self) -> Array2<T> { |
||||||
|
Array2::default((self.rows, self.columns)) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn create_board_from_shape_fn<T, F: Fn(CellLocation) -> T>(&self, f: F) -> Array2<T> { |
||||||
|
Array2::from_shape_fn((self.rows, self.columns), |(row, column)| f(CellLocation::new(row, column))) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,161 @@ |
|||||||
|
use enum_map::EnumMap; |
||||||
|
use ndarray::Array2; |
||||||
|
use strum::IntoEnumIterator; |
||||||
|
|
||||||
|
use crate::binary::CellState; |
||||||
|
use crate::binary::Direction; |
||||||
|
use crate::binary::State; |
||||||
|
use crate::board_metadata::BoardMetadata; |
||||||
|
use crate::board_metadata::CellLocation; |
||||||
|
use crate::rules::Rules; |
||||||
|
|
||||||
|
struct CellInfo { |
||||||
|
neighbours: EnumMap<Direction, Option<CellLocation>>, |
||||||
|
state: CellState, |
||||||
|
} |
||||||
|
|
||||||
|
impl CellInfo { |
||||||
|
fn new(neighbours: EnumMap<Direction, Option<CellLocation>>) -> CellInfo { |
||||||
|
CellInfo { |
||||||
|
neighbours, |
||||||
|
state: CellState::new(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn update_neighbour_state(&mut self, direction: Direction, new_state: State) -> () { |
||||||
|
self.state.update_neighbour_state(direction, new_state) |
||||||
|
} |
||||||
|
|
||||||
|
fn update_state(&mut self, new_state: State) { |
||||||
|
self.state.update_state(new_state) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct Game { |
||||||
|
cell_rules: Vec<State>, |
||||||
|
board: Array2<CellInfo>, |
||||||
|
rows: usize, |
||||||
|
columns: usize, |
||||||
|
} |
||||||
|
|
||||||
|
impl Game { |
||||||
|
// only updates the state of this cell for it and its neighbours;
|
||||||
|
// only state of this cell is used from new_cell
|
||||||
|
fn update_cell(&mut self, location: CellLocation, new_state: State) { |
||||||
|
//println!("Updating cell {}:{}", location.row, location.column);
|
||||||
|
self.board[location].update_state(new_state); |
||||||
|
|
||||||
|
for direction in Direction::iter() { |
||||||
|
match self.board[location].neighbours[direction] { |
||||||
|
Some(neighbour_location) => { |
||||||
|
//println!("Updating neighbour cell {}:{}", neighbour_location.row, neighbour_location.column);
|
||||||
|
self.board[neighbour_location].update_neighbour_state(direction, new_state); |
||||||
|
}, |
||||||
|
_ => {}, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn build_cell_rules<T: Rules>() -> Vec<State> { |
||||||
|
let mut result = vec![State::None; 1 << 18]; |
||||||
|
|
||||||
|
for i in 0..1usize << 18 { |
||||||
|
let original_state = CellState::from_number(i as u32); |
||||||
|
let mut neighbour_counts = EnumMap::new(); |
||||||
|
for direction in Direction::iter() { |
||||||
|
neighbour_counts[original_state.get_neighbour_state(direction)] += 1usize; |
||||||
|
} |
||||||
|
|
||||||
|
let new_state = T::get_next_state(original_state.get_state(), neighbour_counts); |
||||||
|
result[i] = new_state; |
||||||
|
//println!("Rule #{}: for state_counts [{}, {}, {}, {}] and old state {} new state is {}", i, state_counts[0], state_counts[1], state_counts[2], state_counts[3], current_state, new_state);
|
||||||
|
} |
||||||
|
|
||||||
|
result |
||||||
|
} |
||||||
|
|
||||||
|
fn get_next_state(&self, cell_info: &CellInfo) -> State { |
||||||
|
self.cell_rules[cell_info.state.get_number() as usize] |
||||||
|
} |
||||||
|
|
||||||
|
pub fn next_step(&mut self) -> usize { |
||||||
|
let mut changes: Vec<_> = vec![]; |
||||||
|
for row in 0..self.rows { |
||||||
|
for column in 0..self.columns { |
||||||
|
let location = CellLocation::new(row, column); |
||||||
|
let cell = &self.board[location]; |
||||||
|
let next_state = self.get_next_state(cell); |
||||||
|
//println!("location: {}:{}, neighbours state {}, old state {}, next state {}", location.row, location.column, cell.neighbours_states, cell.state, next_state);
|
||||||
|
if next_state != cell.state.get_state() { |
||||||
|
changes.push((location, next_state)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let changes_count = changes.len(); |
||||||
|
for (location, new_state) in changes { |
||||||
|
self.update_cell(location, new_state); |
||||||
|
} |
||||||
|
|
||||||
|
changes_count |
||||||
|
} |
||||||
|
|
||||||
|
pub fn from_input<R: Rules>(input_data: &[String]) -> Self { |
||||||
|
let rows = input_data.len(); |
||||||
|
let columns = input_data[0].len(); |
||||||
|
let board_metadata = BoardMetadata::new(rows, columns); |
||||||
|
let mut states = board_metadata.create_board_default(); |
||||||
|
|
||||||
|
for row in 0..rows { |
||||||
|
let chars = input_data[row].chars().collect::<Vec<_>>(); |
||||||
|
for column in 0..columns { |
||||||
|
let ch = chars[column]; |
||||||
|
states[[row, column]] = match ch { |
||||||
|
'.' => State::Floor, |
||||||
|
'L' => State::SeatEmpty, |
||||||
|
'#' => State::SeatOccupied, |
||||||
|
_ => State::None, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
let board = board_metadata.create_board_from_shape_fn(|cell_location| { |
||||||
|
CellInfo::new(R::get_neighbours(cell_location, &board_metadata, &states)) |
||||||
|
}); |
||||||
|
|
||||||
|
let cell_rules = Self::build_cell_rules::<R>(); |
||||||
|
|
||||||
|
let mut game = Game { |
||||||
|
rows, |
||||||
|
columns, |
||||||
|
board, |
||||||
|
cell_rules, |
||||||
|
}; |
||||||
|
|
||||||
|
for row in 0..rows { |
||||||
|
for column in 0..columns { |
||||||
|
let location = CellLocation::new(row, column); |
||||||
|
game.update_cell(location, states[location]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return game; |
||||||
|
} |
||||||
|
|
||||||
|
pub fn print_board(&self) { |
||||||
|
for row in (&self.board).genrows() { |
||||||
|
println!("{}", row.iter().map(|cell| { |
||||||
|
match cell.state.get_state() { |
||||||
|
State::Floor => '.', |
||||||
|
State::SeatEmpty => 'L', |
||||||
|
State::SeatOccupied => '#', |
||||||
|
State::None => '0', |
||||||
|
} |
||||||
|
}).collect::<String>()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get_count_of_cells_for_state(&self, state: State) -> usize { |
||||||
|
(&self.board).iter().filter(|&cell| cell.state.get_state() == state).count() |
||||||
|
} |
||||||
|
} |
@ -1,193 +1,33 @@ |
|||||||
#![feature(trait_alias)] |
#![feature(trait_alias)] |
||||||
|
|
||||||
use std::io::{self, BufRead}; |
use std::io::{self, BufRead}; |
||||||
use ndarray::Array2; |
|
||||||
|
|
||||||
// state (u32 for simplicity reasons): 0/1/2/3 (in this case, 1 = floor, 2 = seat free, 3 = seat taken)
|
mod binary; |
||||||
|
mod board_metadata; |
||||||
|
mod game; |
||||||
|
mod rules; |
||||||
|
mod rules_easy; |
||||||
|
|
||||||
// every cell is u32, where:
|
use binary::State; |
||||||
// * lowest 16 bits describe its neighbours:
|
use game::Game; |
||||||
// * bits 0-1 (cell & 3) is the state of upper left neighbour,
|
use rules_easy::RulesEasy; |
||||||
// * bits 2-3 ((cell >> 2) & 3) is the state of upper neighbour,
|
|
||||||
// * bits 4-5 is the state of upper right neighbour,
|
|
||||||
// * bits 6-7, left,
|
|
||||||
// * bits 8-9, right,
|
|
||||||
// * bits 10-11, bottom left,
|
|
||||||
// * bits 12-13, bottom,
|
|
||||||
// * bits 14-15, bottom right
|
|
||||||
// * bits 16-17 ((cell >> 16) & 3) describe the cell itself
|
|
||||||
|
|
||||||
// rule: cell (u32, 18 bits used) -> new cell (u32)
|
|
||||||
|
|
||||||
// board is indexed by [row, column],
|
|
||||||
// where row is from top to bottom and column is from left to right
|
|
||||||
|
|
||||||
trait StateRules = Fn([usize; 4], u32) -> u32; |
|
||||||
|
|
||||||
struct Game { |
|
||||||
cell_rules: Vec<u32>, |
|
||||||
board: Array2<u32>, |
|
||||||
rows: usize, |
|
||||||
columns: usize, |
|
||||||
} |
|
||||||
|
|
||||||
impl Game { |
|
||||||
// only updates the state of this cell for it and its neighbours;
|
|
||||||
// only state of this cell is used from new_cell
|
|
||||||
fn update_cell(&mut self, row: usize, column: usize, new_cell: u32) { |
|
||||||
let state_diff = (new_cell ^ self.board[[row, column]]) >> 16; |
|
||||||
|
|
||||||
self.board[[row, column]] ^= state_diff << 16; |
|
||||||
|
|
||||||
self.board[[row+1, column+1]] ^= state_diff; |
|
||||||
self.board[[row+1, column ]] ^= state_diff << 2; |
|
||||||
self.board[[row+1, column-1]] ^= state_diff << 4; |
|
||||||
self.board[[row , column+1]] ^= state_diff << 6; |
|
||||||
self.board[[row , column-1]] ^= state_diff << 8; |
|
||||||
self.board[[row-1, column+1]] ^= state_diff << 10; |
|
||||||
self.board[[row-1, column ]] ^= state_diff << 12; |
|
||||||
self.board[[row-1, column-1]] ^= state_diff << 14; |
|
||||||
} |
|
||||||
|
|
||||||
fn build_cell_rules<T: StateRules>(state_rules: T) -> Vec<u32> { |
|
||||||
let mut result = vec![0u32; 1 << 18]; |
|
||||||
|
|
||||||
for i in 0..1usize << 18 { |
|
||||||
let cell = i as u32; |
|
||||||
let current_state = (cell >> 16) & 3; |
|
||||||
let mut state_counts = [0usize; 4]; |
|
||||||
for j in 0..8 { |
|
||||||
state_counts[((cell >> (2*j)) & 3) as usize] += 1; |
|
||||||
} |
|
||||||
|
|
||||||
let new_state = state_rules(state_counts, current_state); |
|
||||||
let new_cell = cell ^ ((current_state ^ new_state) << 16); |
|
||||||
result[i] = new_cell; |
|
||||||
} |
|
||||||
|
|
||||||
result |
|
||||||
} |
|
||||||
|
|
||||||
pub fn next_step(&mut self) -> usize { |
|
||||||
let mut changes: Vec<_> = vec![]; |
|
||||||
for row in 1..self.rows-1 { |
|
||||||
for column in 1..self.columns-1 { |
|
||||||
let old_cell = self.board[[row, column]]; |
|
||||||
let new_cell = self.cell_rules[old_cell as usize]; |
|
||||||
if new_cell != old_cell { |
|
||||||
changes.push((row, column, new_cell)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
let changes_count = changes.len(); |
|
||||||
for (row, column, new_cell) in changes { |
|
||||||
self.update_cell(row, column, new_cell); |
|
||||||
} |
|
||||||
|
|
||||||
changes_count |
|
||||||
} |
|
||||||
|
|
||||||
pub fn from_input<T: StateRules>(input_data: &[String], state_rules: T) -> Game { |
|
||||||
let rows = input_data.len() + 2; |
|
||||||
let columns = input_data[0].len() + 2; |
|
||||||
let mut states = Array2::zeros((rows, columns)); |
|
||||||
|
|
||||||
for row in 1..rows-1 { |
|
||||||
let chars = input_data[row-1].chars().collect::<Vec<_>>(); |
|
||||||
for column in 1..columns-1 { |
|
||||||
let ch = chars[column-1]; |
|
||||||
states[[row, column]] = match ch { |
|
||||||
'.' => 1, |
|
||||||
'L' => 2, |
|
||||||
'#' => 3, |
|
||||||
_ => 0, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
let mut board = Array2::zeros((rows, columns)); |
|
||||||
|
|
||||||
/* |
|
||||||
board[[0, 0]] = states[[1, 1]] << 14; |
|
||||||
board[[0, columns-1]] = states[[1, columns-2]] << 10; |
|
||||||
board[[rows-1, 0]] = states[[rows-2, 1]] << 4; |
|
||||||
board[[rows-1, columns-1]] = states[[rows-2, columns-2]]; |
|
||||||
|
|
||||||
for row in 1..rows-1 { |
|
||||||
board[[row, 0]] = (states[[row-1, 1]] << 4) ^ (states[[row, 1]] << 8) ^ (states[[row+1, 1]] << 14); |
|
||||||
board[[row, columns-1]] = (states[[row-1, columns-2]]) ^ (states[[row, columns-2]] << 6) ^ (states[[row+1, columns-2]] << 10); |
|
||||||
} |
|
||||||
|
|
||||||
for column in 1..columns-1 { |
|
||||||
board[[0, column]] = (states[[1, column-1]] << 10) ^ (states[[1, column]] << 12) ^ (states[[1, column+1]] << 14); |
|
||||||
board[[rows-1, column]] = (states[[rows-2, column-1]]) ^ (states[[rows-2, column]] << 2) ^ (states[[rows-2, column+1]] << 4); |
|
||||||
} |
|
||||||
*/ |
|
||||||
|
|
||||||
for row in 1..rows-1 { |
|
||||||
for column in 1..columns-1 { |
|
||||||
board[[row, column]] = |
|
||||||
(states[[row-1, column-1]] ) ^ |
|
||||||
(states[[row-1, column ]] << 2) ^ |
|
||||||
(states[[row-1, column+1]] << 4) ^ |
|
||||||
(states[[row , column-1]] << 6) ^ |
|
||||||
(states[[row , column+1]] << 8) ^ |
|
||||||
(states[[row+1, column-1]] << 10) ^ |
|
||||||
(states[[row+1, column ]] << 12) ^ |
|
||||||
(states[[row+1, column+1]] << 14) ^ |
|
||||||
(states[[row, column]] << 16); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
let cell_rules = Self::build_cell_rules(state_rules); |
|
||||||
|
|
||||||
Game { |
|
||||||
rows, |
|
||||||
columns, |
|
||||||
board, |
|
||||||
cell_rules, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pub fn print_board(&self) { |
|
||||||
for row in (&self.board).genrows() { |
|
||||||
println!("{}", row.iter().map(|state| { |
|
||||||
match (state >> 16) & 3 { |
|
||||||
1 => '.', |
|
||||||
2 => 'L', |
|
||||||
3 => '#', |
|
||||||
_ => '0', |
|
||||||
} |
|
||||||
}).collect::<String>()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pub fn get_count_of_cells_for_state(&self, state: u32) -> usize { |
|
||||||
(&self.board).iter().filter(|&&cell| ((cell >> 16) & 3) == state).count() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fn main() { |
fn main() { |
||||||
let stdin = io::stdin(); |
let stdin = io::stdin(); |
||||||
let lines: Vec<_> = stdin.lock().lines().map(|line| line.unwrap()).collect(); |
let lines: Vec<_> = stdin.lock().lines().map(|line| line.unwrap()).collect(); |
||||||
let mut game = Game::from_input(&lines, |state_counts: [usize; 4], current_state| { |
let mut game = Game::from_input::<RulesEasy>(&lines); |
||||||
match current_state { |
|
||||||
2 => if state_counts[3] == 0 { 3 } else { 2 }, |
//game.print_board();
|
||||||
3 => if state_counts[3] >= 4 { 2 } else { 3 }, |
|
||||||
other => other |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
for i in 1.. { |
for i in 1.. { |
||||||
let changes_count = game.next_step(); |
let changes_count = game.next_step(); |
||||||
println!("Iteration {}; changed cells: {}", i, changes_count); |
println!("Iteration {}; changed cells: {}", i, changes_count); |
||||||
|
//game.print_board();
|
||||||
if changes_count == 0 { |
if changes_count == 0 { |
||||||
break; |
break; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
println!("Board stabilized at {} occupied seats", game.get_count_of_cells_for_state(3)); |
|
||||||
game.print_board(); |
game.print_board(); |
||||||
println!("Board stabilized at {} occupied seats", game.get_count_of_cells_for_state(3)); |
println!("Board stabilized at {} occupied seats", game.get_count_of_cells_for_state(State::SeatOccupied)); |
||||||
} |
} |
||||||
|
@ -0,0 +1,9 @@ |
|||||||
|
use enum_map::EnumMap; |
||||||
|
use ndarray::Array2; |
||||||
|
use crate::binary::{Direction, State}; |
||||||
|
use crate::board_metadata::{BoardMetadata,CellLocation}; |
||||||
|
|
||||||
|
pub trait Rules { |
||||||
|
fn get_next_state(current_state: State, neighbour_counts: EnumMap<State, usize>) -> State; |
||||||
|
fn get_neighbours(cell_location: CellLocation, board_metadata: &BoardMetadata, original_states: &Array2<State>) -> EnumMap<Direction, Option<CellLocation>>; |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
use enum_map::EnumMap; |
||||||
|
use ndarray::Array2; |
||||||
|
use strum::IntoEnumIterator; |
||||||
|
use crate::binary::{Direction, State}; |
||||||
|
use crate::board_metadata::{BoardMetadata,CellLocation}; |
||||||
|
use crate::rules::Rules; |
||||||
|
|
||||||
|
pub struct RulesEasy {} |
||||||
|
|
||||||
|
impl Rules for RulesEasy { |
||||||
|
fn get_next_state(current_state: State, neighbour_counts: EnumMap<State, usize>) -> State { |
||||||
|
match current_state { |
||||||
|
State::SeatEmpty => if neighbour_counts[State::SeatOccupied] == 0 { State::SeatOccupied } else { State::SeatEmpty }, |
||||||
|
State::SeatOccupied => if neighbour_counts[State::SeatOccupied] >= 4 { State::SeatEmpty } else { State::SeatOccupied }, |
||||||
|
other => other |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fn get_neighbours(cell_location: CellLocation, board_metadata: &BoardMetadata, _original_states: &Array2<State>) -> EnumMap<Direction, Option<CellLocation>> { |
||||||
|
let mut neighbours = EnumMap::new(); |
||||||
|
|
||||||
|
for direction in Direction::iter() { |
||||||
|
neighbours[direction] = board_metadata.get_neighbour_location(cell_location, direction); |
||||||
|
} |
||||||
|
|
||||||
|
neighbours |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue