Skip to content

Instantly share code, notes, and snippets.

@iamlouk
Last active February 25, 2021 09:11
Show Gist options
  • Save iamlouk/98e0f822044936ec03b6b8341e0d4436 to your computer and use it in GitHub Desktop.
Save iamlouk/98e0f822044936ec03b6b8341e0d4436 to your computer and use it in GitHub Desktop.
"Smoth" Cellular Automata
use sdl2::rect::Rect;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use rayon::prelude::*;
use crate::rand::Rng;
static mut neighbours: [(isize, isize); 216] = [(0, 0); 216];
const CELLS_X: u32 = 400;
const CELLS_Y: u32 = 400;
type Cell = f32;
struct App {
canvas: sdl2::render::WindowCanvas,
cells_prev: Option<Box<[[Cell; CELLS_Y as usize]; CELLS_X as usize]>>,
cells_curr: Option<Box<[[Cell; CELLS_Y as usize]; CELLS_X as usize]>>,
iter: usize,
}
impl App {
fn render(&mut self) {
let cells = std::mem::replace(&mut self.cells_curr, None).unwrap();
self.canvas.set_draw_color(Color::BLACK);
self.canvas.clear();
let (window_width, window_height) = self.canvas.window().size();
let (cell_width, cell_height) = (window_width / CELLS_X, window_height / CELLS_Y);
for i in 0..(CELLS_X as usize) {
for j in 0..(CELLS_Y as usize) {
let cell = cells[i][j];
let abs = cells[i][j].abs();
/*
let color = match cell > 0. {
false => Color::RGB((abs * 255.0) as u8, 0, 0),
true => Color::RGB(0, (abs * 255.0) as u8, 0),
};
*/
let color = Color::RGB((abs * 255.0) as u8, (abs * 255.0) as u8, (abs * 255.0) as u8);
let x = (i as i32) * (cell_width as i32);
let y = (j as i32) * (cell_height as i32);
self.canvas.set_draw_color(color);
self.canvas.fill_rect(Rect::new(x, y, cell_width, cell_height)).ok().unwrap();
}
}
self.canvas.present();
std::mem::replace(&mut self.cells_curr, Some(cells));
}
fn update(&mut self) {
fn wrap_idxs(mut i: isize, mut j: isize, di: isize, dj: isize) -> (usize, usize) {
i += di;
j += dj;
if i < 0 { i = (CELLS_X as isize) + i; } else
if i >= CELLS_X as isize { i = i - CELLS_X as isize; }
if j < 0 { j = (CELLS_Y as isize) + j; } else
if j >= CELLS_Y as isize { j = j - CELLS_Y as isize; }
(i as usize, j as usize)
}
let cells_prev: Box<_> = self.cells_curr.take().unwrap();
let mut cells_curr: Box<_> = self.cells_prev.take().unwrap();
cells_curr
.par_iter_mut()
.enumerate()
.for_each(|(i, row)| {
for j in 0..(CELLS_Y as usize) {
let cell = cells_prev[i][j];
let sum = unsafe { neighbours.iter() }
.map(|(di, dj)| wrap_idxs(i as isize, j as isize, *di, *dj))
.fold(0., |sum, (x, y)| cells_prev[x][y] + sum);
let avg = sum / unsafe { neighbours.len() as f32 };
let x = match (cell, avg) {
(c, a) if c < 0. && a > -0.2 => -c + 0.025,
(c, a) if c > 0. && a < 0. => -c - 0.025,
(c, a) if c > 0. && a > 0.55 => -c - 0.025,
(c, a) if c < a => c + 0.01,
(c, a) if a < c => c - 0.01,
(c, a) => c // panic!() // (c * 6. + a) / 5.
// (c, a) => (c * 10. + a) / 10.
};
row[j] = if x > 1. { 1. } else if x < -1. { -1. } else { x };
// row[j] = x / (1. + x * x).sqrt();
}
});
self.cells_prev = Some(cells_prev);
self.cells_curr = Some(cells_curr);
self.iter += 1;
}
}
fn init_neighbours() {
let mut i = 0;
for x in (-7)..8 {
for y in (-7)..8 {
if (x <= 1 && x >= -1) && (y <= 1 && y >= -1) {
continue;
}
unsafe {
neighbours[i] = (x, y);
}
i += 1;
}
}
}
pub fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
rayon::ThreadPoolBuilder::new().num_threads(4).build_global().unwrap();
let window = video_subsystem.window("Rust CA", CELLS_X * 1, CELLS_Y * 1)
.position_centered()
.build()
.unwrap();
let canvas = window.into_canvas().build().unwrap();
let mut app = App {
canvas: canvas,
cells_prev: Some(Box::new(
[[0.; CELLS_Y as usize]; CELLS_X as usize])),
cells_curr: Some(Box::new(
[[0.; CELLS_Y as usize]; CELLS_X as usize])),
iter: 0,
};
init_neighbours();
let mut rng = rand::thread_rng();
let cells = &mut app.cells_curr.as_mut().unwrap();
for i in 0..(CELLS_X as usize) {
for j in 0..(CELLS_Y as usize) {
cells[i][j] = rng.gen_range(-1.0, 1.0);
}
}
let mut events = sdl_context.event_pump().unwrap();
loop {
for e in events.poll_iter() {
match e {
Event::Quit {..} |
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
std::process::exit(0);
},
_ => {}
}
}
app.render();
app.update();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment