add ability to speed up, slow down
This commit is contained in:
parent
59bd2f3cf2
commit
816cc2c8c3
10
src/game.rs
10
src/game.rs
|
@ -3,14 +3,20 @@ use servicepoint2::Grid;
|
||||||
use crate::rules::Rules;
|
use crate::rules::Rules;
|
||||||
|
|
||||||
pub(crate) struct Game<TState, TGrid, TKernel, const KERNEL_SIZE: usize>
|
pub(crate) struct Game<TState, TGrid, TKernel, const KERNEL_SIZE: usize>
|
||||||
where TGrid: Grid<TState>, TState: Copy + PartialEq, TKernel: Copy
|
where
|
||||||
|
TGrid: Grid<TState>,
|
||||||
|
TState: Copy + PartialEq,
|
||||||
|
TKernel: Copy,
|
||||||
{
|
{
|
||||||
pub field: TGrid,
|
pub field: TGrid,
|
||||||
pub rules: Rules<TState, TKernel, KERNEL_SIZE>,
|
pub rules: Rules<TState, TKernel, KERNEL_SIZE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TState, TGrid, TKernel, const KERNEL_SIZE: usize> Game<TState, TGrid, TKernel, KERNEL_SIZE>
|
impl<TState, TGrid, TKernel, const KERNEL_SIZE: usize> Game<TState, TGrid, TKernel, KERNEL_SIZE>
|
||||||
where TGrid: Grid<TState>, TState: Copy + PartialEq, TKernel: Copy
|
where
|
||||||
|
TGrid: Grid<TState>,
|
||||||
|
TState: Copy + PartialEq,
|
||||||
|
TKernel: Copy,
|
||||||
{
|
{
|
||||||
pub fn step(&mut self) {
|
pub fn step(&mut self) {
|
||||||
self.field = self.field_iteration();
|
self.field = self.field_iteration();
|
||||||
|
|
127
src/main.rs
127
src/main.rs
|
@ -12,7 +12,10 @@ use crossterm::terminal::{
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distributions::{Distribution, Standard};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use servicepoint2::{ByteGrid, CompressionCode, Connection, Grid, Origin, PixelGrid, TILE_HEIGHT, TILE_WIDTH};
|
use servicepoint2::{
|
||||||
|
ByteGrid, CompressionCode, Connection, FRAME_PACING, Grid, Origin, PixelGrid, TILE_HEIGHT,
|
||||||
|
TILE_WIDTH,
|
||||||
|
};
|
||||||
use servicepoint2::Command::{BitmapLinearWin, CharBrightness};
|
use servicepoint2::Command::{BitmapLinearWin, CharBrightness};
|
||||||
|
|
||||||
use crate::game::Game;
|
use crate::game::Game;
|
||||||
|
@ -20,12 +23,12 @@ use crate::print::{println_debug, println_info, println_warning};
|
||||||
use crate::rules::{generate_bb3, generate_u8b3};
|
use crate::rules::{generate_bb3, generate_u8b3};
|
||||||
|
|
||||||
mod game;
|
mod game;
|
||||||
mod rules;
|
|
||||||
mod print;
|
mod print;
|
||||||
|
mod rules;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(short, long, default_value = "localhost:2342")]
|
#[arg(short, long, default_value = "172.23.42.29:2342")]
|
||||||
destination: String,
|
destination: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,16 +65,18 @@ fn main() {
|
||||||
|
|
||||||
let mut iteration = Wrapping(0u8);
|
let mut iteration = Wrapping(0u8);
|
||||||
|
|
||||||
|
let mut target_duration = FRAME_PACING;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
if iteration % Wrapping(5) == Wrapping(0) {
|
left_pixels.step();
|
||||||
left_pixels.step();
|
right_pixels.step();
|
||||||
right_pixels.step();
|
|
||||||
}
|
|
||||||
|
|
||||||
left_luma.step();
|
if iteration % Wrapping(10) == Wrapping(0) {
|
||||||
right_luma.step();
|
left_luma.step();
|
||||||
|
right_luma.step();
|
||||||
|
}
|
||||||
|
|
||||||
iteration += Wrapping(1u8);
|
iteration += Wrapping(1u8);
|
||||||
|
|
||||||
|
@ -97,10 +102,21 @@ fn main() {
|
||||||
right_luma.rules = generate_u8b3();
|
right_luma.rules = generate_u8b3();
|
||||||
}
|
}
|
||||||
|
|
||||||
split_pixel = i32::clamp(split_pixel as i32 + split_speed, 0, pixels.width() as i32) as usize;
|
split_pixel =
|
||||||
|
i32::clamp(split_pixel as i32 + split_speed, 0, pixels.width() as i32) as usize;
|
||||||
|
|
||||||
draw_pixels(&mut pixels, &left_pixels.field, &right_pixels.field, split_pixel);
|
draw_pixels(
|
||||||
draw_luma(&mut luma, &left_luma.field, &right_luma.field, split_pixel / 8);
|
&mut pixels,
|
||||||
|
&left_pixels.field,
|
||||||
|
&right_pixels.field,
|
||||||
|
split_pixel,
|
||||||
|
);
|
||||||
|
draw_luma(
|
||||||
|
&mut luma,
|
||||||
|
&left_luma.field,
|
||||||
|
&right_luma.field,
|
||||||
|
split_pixel / 8,
|
||||||
|
);
|
||||||
send_to_screen(&connection, &pixels, &luma);
|
send_to_screen(&connection, &pixels, &luma);
|
||||||
|
|
||||||
while event::poll(Duration::from_secs(0)).expect("could not poll") {
|
while event::poll(Duration::from_secs(0)).expect("could not poll") {
|
||||||
|
@ -108,34 +124,47 @@ fn main() {
|
||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
Ok(AppEvent::RandomizeLeftPixels) => {
|
Ok(AppEvent::RandomizeLeftPixels) => {
|
||||||
randomize(&mut left_pixels.field);
|
randomize(&mut left_pixels.field);
|
||||||
|
println_debug("randomized left pixels");
|
||||||
}
|
}
|
||||||
Ok(AppEvent::RandomizeRightPixels) => {
|
Ok(AppEvent::RandomizeRightPixels) => {
|
||||||
randomize(&mut right_pixels.field);
|
randomize(&mut right_pixels.field);
|
||||||
|
println_info("randomized right pixels");
|
||||||
}
|
}
|
||||||
Ok(AppEvent::RandomizeLeftLuma) => {
|
Ok(AppEvent::RandomizeLeftLuma) => {
|
||||||
randomize(&mut left_luma.field);
|
randomize(&mut left_luma.field);
|
||||||
|
println_info("randomized left luma");
|
||||||
}
|
}
|
||||||
Ok(AppEvent::RandomizeRightLuma) => {
|
Ok(AppEvent::RandomizeRightLuma) => {
|
||||||
randomize(&mut right_luma.field);
|
randomize(&mut right_luma.field);
|
||||||
|
println_info("randomized right luma");
|
||||||
}
|
}
|
||||||
Ok(AppEvent::Accelerate) => {
|
Ok(AppEvent::SeparatorAccelerate) => {
|
||||||
split_speed += 1;
|
split_speed += 1;
|
||||||
|
println_info(format!("increased separator speed to {split_speed}"));
|
||||||
}
|
}
|
||||||
Ok(AppEvent::Decelerate) => {
|
Ok(AppEvent::SeparatorDecelerate) => {
|
||||||
split_speed -= 1;
|
split_speed -= 1;
|
||||||
|
println_info(format!("decreased separator speed to {split_speed}"));
|
||||||
}
|
}
|
||||||
Ok(AppEvent::Close) => {
|
Ok(AppEvent::Close) => {
|
||||||
|
println_warning("terminating");
|
||||||
de_init();
|
de_init();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Ok(AppEvent::SimulationSpeedUp) => {
|
||||||
|
target_duration = target_duration.saturating_sub(Duration::from_millis(1));
|
||||||
|
println_info(format!("increased simulation speed to {} ups", 1f64 / target_duration.as_secs_f64()));
|
||||||
|
}
|
||||||
|
Ok(AppEvent::SimulationSpeedDown) => {
|
||||||
|
target_duration = target_duration.saturating_add(Duration::from_millis(1));
|
||||||
|
println_info(format!("decreased simulation speed to {} ups", 1f64 / target_duration.as_secs_f64()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let wanted_time = Duration::from_millis(100);
|
|
||||||
let tick_time = start.elapsed();
|
let tick_time = start.elapsed();
|
||||||
if tick_time < wanted_time {
|
if tick_time < target_duration {
|
||||||
thread::sleep(wanted_time - tick_time);
|
thread::sleep(target_duration - tick_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,8 +175,10 @@ enum AppEvent {
|
||||||
RandomizeRightPixels,
|
RandomizeRightPixels,
|
||||||
RandomizeLeftLuma,
|
RandomizeLeftLuma,
|
||||||
RandomizeRightLuma,
|
RandomizeRightLuma,
|
||||||
Accelerate,
|
SeparatorAccelerate,
|
||||||
Decelerate,
|
SeparatorDecelerate,
|
||||||
|
SimulationSpeedUp,
|
||||||
|
SimulationSpeedDown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Event> for AppEvent {
|
impl TryFrom<Event> for AppEvent {
|
||||||
|
@ -168,32 +199,15 @@ impl TryFrom<Event> for AppEvent {
|
||||||
println_info("[←] accelerate divider left");
|
println_info("[←] accelerate divider left");
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
KeyCode::Char('q') => {
|
KeyCode::Char('q') => Ok(AppEvent::Close),
|
||||||
println_warning("terminating");
|
KeyCode::Char('d') => Ok(AppEvent::RandomizeLeftPixels),
|
||||||
Ok(AppEvent::Close)
|
KeyCode::Char('e') => Ok(AppEvent::RandomizeLeftLuma),
|
||||||
}
|
KeyCode::Char('f') => Ok(AppEvent::RandomizeRightPixels),
|
||||||
KeyCode::Char('d') => {
|
KeyCode::Char('r') => Ok(AppEvent::RandomizeRightLuma),
|
||||||
println_debug("randomizing left pixels");
|
KeyCode::Right => Ok(AppEvent::SeparatorAccelerate),
|
||||||
Ok(AppEvent::RandomizeLeftPixels)
|
KeyCode::Left => Ok(AppEvent::SeparatorDecelerate),
|
||||||
}
|
KeyCode::Up => Ok(AppEvent::SimulationSpeedUp),
|
||||||
KeyCode::Char('e') => {
|
KeyCode::Down => Ok(AppEvent::SimulationSpeedDown),
|
||||||
println_info("randomizing left luma");
|
|
||||||
Ok(AppEvent::RandomizeLeftLuma)
|
|
||||||
}
|
|
||||||
KeyCode::Char('f') => {
|
|
||||||
println_info("randomizing right pixels");
|
|
||||||
Ok(AppEvent::RandomizeRightPixels)
|
|
||||||
}
|
|
||||||
KeyCode::Char('r') => {
|
|
||||||
println_info("randomizing right luma");
|
|
||||||
Ok(AppEvent::RandomizeRightLuma)
|
|
||||||
}
|
|
||||||
KeyCode::Right => {
|
|
||||||
Ok(AppEvent::Accelerate)
|
|
||||||
}
|
|
||||||
KeyCode::Left => {
|
|
||||||
Ok(AppEvent::Decelerate)
|
|
||||||
}
|
|
||||||
key_code => {
|
key_code => {
|
||||||
println_debug(format!("unhandled KeyCode {key_code:?}"));
|
println_debug(format!("unhandled KeyCode {key_code:?}"));
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -223,14 +237,16 @@ fn draw_luma(luma: &mut ByteGrid, left: &ByteGrid, right: &ByteGrid, split_tile:
|
||||||
let left_or_right = if x < split_tile { left } else { right };
|
let left_or_right = if x < split_tile { left } else { right };
|
||||||
for y in 0..luma.height() {
|
for y in 0..luma.height() {
|
||||||
let set = u8::max(48, left_or_right.get(x, y));
|
let set = u8::max(48, left_or_right.get(x, y));
|
||||||
luma.set(x, y, set);
|
|
||||||
|
let set = set as f32 / u8::MAX as f32 * 12f32;
|
||||||
|
|
||||||
|
luma.set(x, y, set as u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_to_screen(connection: &Connection, pixels: &PixelGrid, luma: &ByteGrid) {
|
fn send_to_screen(connection: &Connection, pixels: &PixelGrid, luma: &ByteGrid) {
|
||||||
let pixel_cmd =
|
let pixel_cmd = BitmapLinearWin(Origin(0, 0), pixels.clone(), CompressionCode::Uncompressed);
|
||||||
BitmapLinearWin(Origin(0, 0), pixels.clone(), CompressionCode::Uncompressed);
|
|
||||||
connection
|
connection
|
||||||
.send(pixel_cmd.into())
|
.send(pixel_cmd.into())
|
||||||
.expect("could not send pixels");
|
.expect("could not send pixels");
|
||||||
|
@ -241,7 +257,9 @@ fn send_to_screen(connection: &Connection, pixels: &PixelGrid, luma: &ByteGrid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn randomize<TGrid, TValue>(field: &mut TGrid)
|
fn randomize<TGrid, TValue>(field: &mut TGrid)
|
||||||
where TGrid: Grid<TValue>, Standard: Distribution<TValue>
|
where
|
||||||
|
TGrid: Grid<TValue>,
|
||||||
|
Standard: Distribution<TValue>,
|
||||||
{
|
{
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
@ -260,16 +278,13 @@ fn init() -> Connection {
|
||||||
|
|
||||||
execute!(stdout(), EnterAlternateScreen, EnableLineWrap)
|
execute!(stdout(), EnterAlternateScreen, EnableLineWrap)
|
||||||
.expect("could not enter alternate screen");
|
.expect("could not enter alternate screen");
|
||||||
enable_raw_mode()
|
enable_raw_mode().expect("could not enable raw terminal mode");
|
||||||
.expect("could not enable raw terminal mode");
|
|
||||||
|
|
||||||
Connection::open(Cli::parse().destination)
|
Connection::open(Cli::parse().destination)
|
||||||
.expect("Could not connect. Did you forget `--destination`?")
|
.expect("Could not connect. Did you forget `--destination`?")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn de_init() {
|
fn de_init() {
|
||||||
disable_raw_mode()
|
disable_raw_mode().expect("could not disable raw terminal mode");
|
||||||
.expect("could not disable raw terminal mode");
|
execute!(stdout(), LeaveAlternateScreen).expect("could not leave alternate screen");
|
||||||
execute!(stdout(), LeaveAlternateScreen)
|
|
||||||
.expect("could not leave alternate screen");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io::stdout;
|
|
||||||
use crossterm::queue;
|
use crossterm::queue;
|
||||||
use crossterm::style::{Print, PrintStyledContent, Stylize};
|
use crossterm::style::{Print, PrintStyledContent, Stylize};
|
||||||
|
use std::io::stdout;
|
||||||
|
|
||||||
pub fn println_info(text: impl Into<String>) {
|
pub fn println_info(text: impl Into<String>) {
|
||||||
println_command(PrintStyledContent(text.into().white()))
|
println_command(PrintStyledContent(text.into().white()))
|
||||||
|
@ -16,4 +16,4 @@ pub fn println_warning(text: impl Into<String>) {
|
||||||
|
|
||||||
pub fn println_command(command: impl crossterm::Command) {
|
pub fn println_command(command: impl crossterm::Command) {
|
||||||
queue!(stdout(), command, Print("\r\n")).expect("could not print");
|
queue!(stdout(), command, Print("\r\n")).expect("could not print");
|
||||||
}
|
}
|
||||||
|
|
55
src/rules.rs
55
src/rules.rs
|
@ -1,37 +1,41 @@
|
||||||
use rand::{Rng, thread_rng};
|
|
||||||
use rand::rngs::ThreadRng;
|
use rand::rngs::ThreadRng;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::print::println_info;
|
use crate::print::println_info;
|
||||||
|
|
||||||
|
const MAX_BRIGHTNESS: u8 = 12;
|
||||||
|
|
||||||
pub struct Rules<TState, TKernel, const KERNEL_SIZE: usize>
|
pub struct Rules<TState, TKernel, const KERNEL_SIZE: usize>
|
||||||
where TState: Copy + PartialEq, TKernel: Copy
|
where
|
||||||
|
TState: Copy + PartialEq,
|
||||||
|
TKernel: Copy,
|
||||||
{
|
{
|
||||||
pub kernel: [[TKernel; KERNEL_SIZE]; KERNEL_SIZE],
|
pub kernel: [[TKernel; KERNEL_SIZE]; KERNEL_SIZE],
|
||||||
pub count_neighbor: Box<dyn Fn(TState, TKernel) -> i32>,
|
pub count_neighbor: Box<dyn Fn(TState, TKernel) -> i32>,
|
||||||
pub next_state: Box<dyn Fn(TState, i32) -> TState>,
|
pub next_state: Box<dyn Fn(TState, i32) -> TState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const MOORE_NEIGHBORHOOD: [[bool; 3]; 3] = [
|
pub const MOORE_NEIGHBORHOOD: [[bool; 3]; 3] =
|
||||||
[true, true, true],
|
[[true, true, true], [true, false, true], [true, true, true]];
|
||||||
[true, false, true],
|
|
||||||
[true, true, true]
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const NEUMANN_NEIGHBORHOOD: [[bool; 3]; 3] = [
|
pub const NEUMANN_NEIGHBORHOOD: [[bool; 3]; 3] = [
|
||||||
[false, true, false],
|
[false, true, false],
|
||||||
[true, false, true],
|
[true, false, true],
|
||||||
[false, true, false]
|
[false, true, false],
|
||||||
];
|
];
|
||||||
|
|
||||||
pub const DIAGONALS_NEIGHBORHOOD: [[bool; 3]; 3] = [
|
pub const DIAGONALS_NEIGHBORHOOD: [[bool; 3]; 3] = [
|
||||||
[true, false, true],
|
[true, false, true],
|
||||||
[false, false, false],
|
[false, false, false],
|
||||||
[true, false, true]
|
[true, false, true],
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn count_true_neighbor(neighbor_state: bool, kernel_value: bool) -> i32
|
pub fn count_true_neighbor(neighbor_state: bool, kernel_value: bool) -> i32 {
|
||||||
{
|
if neighbor_state && kernel_value {
|
||||||
if neighbor_state && kernel_value { 1 } else { 0 }
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -39,26 +43,31 @@ pub fn generate_bb3() -> Rules<bool, bool, 3> {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
let is_moore = rng.gen_bool(1.0 / 2.0);
|
let is_moore = rng.gen_bool(1.0 / 2.0);
|
||||||
let kernel = if is_moore { MOORE_NEIGHBORHOOD } else { NEUMANN_NEIGHBORHOOD };
|
let kernel = if is_moore {
|
||||||
|
MOORE_NEIGHBORHOOD
|
||||||
|
} else {
|
||||||
|
NEUMANN_NEIGHBORHOOD
|
||||||
|
};
|
||||||
let max_neighbors = if is_moore { 8 } else { 4 };
|
let max_neighbors = if is_moore { 8 } else { 4 };
|
||||||
|
|
||||||
let birth = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[0]);
|
let birth = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[0]);
|
||||||
let survive = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[]);
|
let survive = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[]);
|
||||||
|
|
||||||
println_info(format!("generated bb3: Birth {birth:?} Survival {survive:?}, kernel: {kernel:?}"));
|
println_info(format!(
|
||||||
|
"generated bb3: Birth {birth:?} Survival {survive:?}, kernel: {kernel:?}"
|
||||||
|
));
|
||||||
|
|
||||||
Rules {
|
Rules {
|
||||||
kernel,
|
kernel,
|
||||||
count_neighbor: Box::new(count_true_neighbor),
|
count_neighbor: Box::new(count_true_neighbor),
|
||||||
next_state: Box::new(move |old_state, neighbors| {
|
next_state: Box::new(move |old_state, neighbors| {
|
||||||
old_state && survive.contains(&neighbors)
|
old_state && survive.contains(&neighbors) || !old_state && birth.contains(&neighbors)
|
||||||
|| !old_state && birth.contains(&neighbors)
|
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_neighbor_counts(count: u8, rng: &mut ThreadRng, exclude: &[i32]) -> Vec<i32> {
|
fn generate_neighbor_counts(count: u8, rng: &mut ThreadRng, exclude: &[i32]) -> Vec<i32> {
|
||||||
let mut result = vec!();
|
let mut result = vec![];
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let value = rng.gen_range(0..=count) as i32;
|
let value = rng.gen_range(0..=count) as i32;
|
||||||
if !exclude.contains(&value) {
|
if !exclude.contains(&value) {
|
||||||
|
@ -76,13 +85,17 @@ pub fn generate_u8b3() -> Rules<u8, bool, 3> {
|
||||||
0 => MOORE_NEIGHBORHOOD,
|
0 => MOORE_NEIGHBORHOOD,
|
||||||
1 => NEUMANN_NEIGHBORHOOD,
|
1 => NEUMANN_NEIGHBORHOOD,
|
||||||
2 => DIAGONALS_NEIGHBORHOOD,
|
2 => DIAGONALS_NEIGHBORHOOD,
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let alive_threshold = rng.gen();
|
let alive_threshold = rng.gen();
|
||||||
|
|
||||||
let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]);
|
let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]);
|
||||||
let survive = generate_neighbor_counts(rng.gen_range(1..=9 - birth.len()) as u8, &mut rng, &[]);
|
let survive = generate_neighbor_counts(
|
||||||
|
rng.gen_range(1..=u8::max(1, 9 - birth.len() as u8)),
|
||||||
|
&mut rng,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
|
||||||
let add = rng.gen_range(5..40);
|
let add = rng.gen_range(5..40);
|
||||||
let sub = rng.gen_range(5..40);
|
let sub = rng.gen_range(5..40);
|
||||||
|
@ -91,9 +104,7 @@ pub fn generate_u8b3() -> Rules<u8, bool, 3> {
|
||||||
|
|
||||||
Rules {
|
Rules {
|
||||||
kernel,
|
kernel,
|
||||||
count_neighbor: Box::new(|state, kernel| {
|
count_neighbor: Box::new(|state, kernel| if kernel { state as i32 } else { 0 }),
|
||||||
if kernel { state as i32 } else { 0 }
|
|
||||||
}),
|
|
||||||
next_state: Box::new(move |old_state, neighbors| {
|
next_state: Box::new(move |old_state, neighbors| {
|
||||||
let neighbors = neighbors / alive_threshold as i32;
|
let neighbors = neighbors / alive_threshold as i32;
|
||||||
let old_is_alive = old_state >= alive_threshold;
|
let old_is_alive = old_state >= alive_threshold;
|
||||||
|
|
Loading…
Reference in a new issue