optimizations: move all things to Grid (1 Vec internal) and life uses nalive() (8 ifs instead of 2 loops)

This commit is contained in:
Dan Ballard 2021-01-05 20:46:48 -08:00
parent 6381d02fb9
commit 02a3f3aad1
3 changed files with 100 additions and 49 deletions

View File

@ -11,6 +11,30 @@ pub mod life;
pub const BLACK: Color = Color::RGB(0, 0, 0);
pub const WHITE: Color = Color::RGB(255, 255, 255);
pub struct Grid<T: Clone> {
size: usize,
flat_grid: Vec<T>,
}
impl<T> Grid<T>
where T: Clone
{
pub fn new(default: T, size: usize) -> Grid<T> {
Grid::<T> {size: size, flat_grid: vec![default; size*size]}
}
pub fn get(&self, y: usize, x: usize) -> &T {
&self.flat_grid[ y*self.size + x ]
}
pub fn set(&mut self, y: usize, x: usize, val: T) {
self.flat_grid[ y*self.size + x ] = val;
}
pub fn size(&self) -> usize {
self.size
}
}
#[derive(Clone)]
@ -19,7 +43,7 @@ pub struct Cell {
}
pub trait Engine {
fn evolve(&mut self) -> Vec<Vec<Cell>>;
fn evolve(&mut self) -> Grid<Cell>;
}
pub struct Renderer {
@ -32,14 +56,14 @@ impl Renderer {
Renderer { px_size: px_size, canvas: canvas }
}
pub fn render(&mut self, grid: &Vec<Vec<Cell>>) {
pub fn render(&mut self, grid: Grid<Cell>) {
self.canvas.set_draw_color(BLACK);
self.canvas.clear();
for y in 0..grid.len() {
for x in 0..grid[y].len() {
for y in 0..grid.size() {
for x in 0..grid.size() {
//if grid[y][x].alive {
self.canvas.set_draw_color(grid[y][x].color);
self.canvas.set_draw_color(grid.get(y, x).color);
self.canvas.fill_rect(Rect::new(x as i32 * self.px_size, y as i32 * self.px_size, self.px_size as u32, self.px_size as u32));
//}
}

View File

@ -1,70 +1,96 @@
use std::cmp;
use super::{Cell, Engine, WHITE, BLACK};
use super::{Cell, Engine, Grid, WHITE, BLACK};
pub struct LifeEngine {
grid: Vec<Vec<bool>>,
grid: Grid<bool>,
}
pub fn new(size: usize) -> LifeEngine {
let mut life = LifeEngine{grid: vec![vec![false; size]; size]};
let mut life = LifeEngine{grid: Grid::new(false, size)};
// r pemento
let centery = size/2;
let centerx = size/2;
life.grid[centery][centerx] = true;
life.grid[centery+1][centerx] = true;
life.grid[centery-1][centerx] = true;
life.grid.set(centery, centerx,true);
life.grid.set(centery+1, centerx, true);
life.grid.set(centery-1, centerx, true);
life.grid[centery-1][centerx-1] = true;
life.grid[centery][centerx+1] = true;
life.grid.set(centery-1, centerx-1, true);
life.grid.set(centery, centerx+1, true);
life
}
impl LifeEngine {
fn nalive(&self, y: usize, x: usize) -> u8 {
let mut nalive = 0;
if y > 0 {
if x > 0 {
if *self.grid.get(y-1, x-1) {
nalive += 1;
}
}
if *self.grid.get(y-1, x) {
nalive += 1;
}
if x < self.grid.size()-1 {
if *self.grid.get(y-1, x+1) {
nalive += 1;
}
}
}
if x > 0 {
if *self.grid.get(y, x-1) {
nalive += 1;
}
}
if x < self.grid.size()-1 {
if *self.grid.get(y, x+1) {
nalive += 1;
}
}
if y < self.grid.size()-1 {
if x > 0 {
if *self.grid.get(y+1, x-1) {
nalive += 1;
}
}
if *self.grid.get(y+1, x) {
nalive += 1;
}
if x < self.grid.size()-1 {
if *self.grid.get(y+1, x+1) {
nalive += 1;
}
}
}
nalive
}
}
impl Engine for LifeEngine {
fn evolve(&mut self) -> Vec<Vec<Cell>> {
let mut new_render_grid = vec![vec![Cell{color: BLACK}; self.grid.len()]; self.grid.len()];
let mut new_life_grid = vec![vec![false; self.grid.len()]; self.grid.len()];
fn evolve(&mut self) -> super::Grid<Cell> {
let mut new_render_grid = super::Grid::new(Cell{color: BLACK}, self.grid.size());
let mut new_life_grid = Grid::new(false, self.grid.size());
for y in 0..self.grid.len() {
for x in 0..self.grid[y].len() {
let mut nalive = 0;
for y in 0..self.grid.size() {
for x in 0..self.grid.size() {
let nalive = self.nalive(y, x);
let mut ylow = 0;
if y > 1 {
ylow = y-1;
}
let yhigh = cmp::min(self.grid.len()-1, y+1);
let mut xlow = 0;
if x > 1 {
xlow = x-1;
}
let xhigh = cmp::min(self.grid.len()-1, x+1);
for i in ylow..yhigh+1 {
for j in xlow..xhigh+1 {
if i == y && j == x {
continue;
}
if self.grid[i][j] {
nalive += 1;
}
}
}
if self.grid[y][x] {
if *self.grid.get(y, x) {
if nalive == 2 || nalive == 3 {
new_render_grid[y][x] = Cell{color: WHITE};
new_life_grid[y][x] = true;
new_render_grid.set(y, x, Cell{color: WHITE});
new_life_grid.set(y, x, true);
}
} else if nalive == 3 {
new_render_grid[y][x] = Cell{color: WHITE};
new_life_grid[y][x] = true;
new_render_grid.set(y, x, Cell{color: WHITE});
new_life_grid.set(y, x, true);
}
}
}

View File

@ -5,6 +5,7 @@ use std::{thread, time};
use std::time::{SystemTime};
use microworlds::Engine;
use microworlds::Grid;
pub const SCREEN_SIZE: u32 = 800;
pub const PX_SIZE: u32 = 2;
@ -16,7 +17,7 @@ fn main() {
let window = video_subsystem.window("Microworlds", SCREEN_SIZE, SCREEN_SIZE).build().unwrap();
println!("Window: {}x{} at {} px per cell", SCREEN_SIZE, SCREEN_SIZE, PX_SIZE);
let size: usize = (SCREEN_SIZE/PX_SIZE) as usize;
let mut grid = vec![vec![microworlds::Cell{color: microworlds::BLACK}; size]; size];
let mut grid = Grid::new(microworlds::Cell{color: microworlds::BLACK}, size);
println!("cell grid: {}x{} ({} cells) - {} steps per sec", size, size, (size*size), STEPS_PER_SEC);
@ -44,7 +45,7 @@ fn main() {
}
let start_rend = SystemTime::now();
renderer.render(&grid);
renderer.render(grid);
let render_time = start_rend.elapsed().unwrap();
let start_evo = SystemTime::now();
grid = engine.evolve();