|
@@ -1,20 +1,18 @@
|
|
|
extern crate piston_window;
|
|
|
extern crate image as im;
|
|
|
-extern crate vecmath;
|
|
|
use std::collections::HashMap;
|
|
|
-
|
|
|
use piston_window::*;
|
|
|
-// use vecmath::*;
|
|
|
use nalgebra::*;
|
|
|
+use rand::Rng;
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
struct World {
|
|
|
- cells: HashMap<Vector2<u32>, Cell>,
|
|
|
- dimensions: Vector2<u32>
|
|
|
+ cells: HashMap<Vector2<i32>, Cell>,
|
|
|
+ dimensions: Vector2<i32>
|
|
|
}
|
|
|
|
|
|
impl World {
|
|
|
- fn init(dim: Vector2<u32>) -> World {
|
|
|
+ fn init(dim: Vector2<i32>) -> World {
|
|
|
// dbg!("init world", dim);
|
|
|
World {
|
|
|
cells: HashMap::new(),
|
|
@@ -22,74 +20,56 @@ impl World {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn get_neighbours(&self, pos: u32) {
|
|
|
- let up = pos - self.dimensions[0];
|
|
|
- let down = pos + self.dimensions[0];
|
|
|
-
|
|
|
- }
|
|
|
+}
|
|
|
|
|
|
- fn grow(&self) -> World {
|
|
|
+#[derive(Debug, Clone, Default)]
|
|
|
+struct Cell {
|
|
|
+ birth: i32,
|
|
|
+ maxage: i32,
|
|
|
+ dead: bool,
|
|
|
+}
|
|
|
|
|
|
- let mut newcells: HashMap<Vector2<u32>, Cell> = HashMap::new();
|
|
|
-
|
|
|
+impl Cell {
|
|
|
+ fn decomposed(&self, step: i32) -> bool {
|
|
|
+ step - self.birth > 100
|
|
|
+ }
|
|
|
|
|
|
- for (pos, cell) in &self.cells {
|
|
|
- // dbg!(&pos);
|
|
|
- let min = Vector2::new(0, 0);
|
|
|
- let max = self.dimensions - Vector2::new(1, 1);
|
|
|
+ fn dead(&self, step: i32) -> bool {
|
|
|
+ step - self.birth > 50
|
|
|
+ }
|
|
|
+
|
|
|
+ fn age(&self, step: i32) -> i32 {
|
|
|
+ step - self.birth
|
|
|
+ }
|
|
|
|
|
|
- let up = clamp(Vector2::new(pos.x, pos.y + 1), min, max);
|
|
|
- let down = clamp(Vector2::new(pos.x, pos.y - 1), min, max);
|
|
|
|
|
|
- // dbg!(&up);
|
|
|
- newcells.insert(up, Cell{birth: 111, maxage: 110});
|
|
|
- // newcells.insert(down, Cell{birth: 111, maxage: 110});
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- // dbg!(self.cells.len());
|
|
|
- World {
|
|
|
- cells: newcells,
|
|
|
- dimensions: self.dimensions
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
-#[derive(Debug, Clone)]
|
|
|
-struct Cell {
|
|
|
- birth: u32,
|
|
|
- maxage: u32
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
- let (width, height) = (300 as u32, 300 as u32);
|
|
|
+ let (width, height) = (400, 400);
|
|
|
|
|
|
|
|
|
let mut world = World::init(Vector2::new(width, height));
|
|
|
|
|
|
- world.cells.insert(Vector2::new(100, 100), Cell{birth: 0, maxage: 110});
|
|
|
- world.cells.insert(Vector2::new(200, 120), Cell{birth: 1, maxage: 110});
|
|
|
|
|
|
- // dbg!(&world);
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
|
|
|
- // world = world.grow();
|
|
|
- // world = world.grow();
|
|
|
- // // dbg!(&world);
|
|
|
- // world = world.grow();
|
|
|
- // // dbg!(&world);
|
|
|
+
|
|
|
+ world.cells.insert(Vector2::new(rng.gen_range(0, width), rng.gen_range(0, height)), Cell{birth: 0, maxage: 110, ..Default::default()});
|
|
|
+ world.cells.insert(Vector2::new(rng.gen_range(0, width), rng.gen_range(0, height)), Cell{birth: 0, maxage: 110, ..Default::default()});
|
|
|
|
|
|
let opengl = OpenGL::V3_2;
|
|
|
let mut window: PistonWindow =
|
|
|
- WindowSettings::new("piston: paint", (width, height))
|
|
|
+ WindowSettings::new("piston: paint", (width as u32, height as u32))
|
|
|
.exit_on_esc(true)
|
|
|
.graphics_api(opengl)
|
|
|
.build()
|
|
|
.unwrap();
|
|
|
|
|
|
- let mut canvas = im::ImageBuffer::new(width, height);
|
|
|
+ let mut canvas = im::ImageBuffer::new(width as u32, height as u32);
|
|
|
let mut texture_context = TextureContext {
|
|
|
factory: window.factory.clone(),
|
|
|
encoder: window.factory.create_command_buffer().into()
|
|
@@ -103,23 +83,64 @@ fn main() {
|
|
|
let mut step = 0;
|
|
|
|
|
|
|
|
|
+ let min = Vector2::new(0, 0);
|
|
|
+ let max = world.dimensions - Vector2::new(1, 1);
|
|
|
+
|
|
|
while let Some(e) = window.next() {
|
|
|
-
|
|
|
- // canvas.put_pixel(step, step, im::Rgba([0, 0, 0, 255]));
|
|
|
|
|
|
- let w = world.grow();
|
|
|
- world = world.grow();
|
|
|
|
|
|
- for (pos, cell) in w.cells {
|
|
|
- canvas.put_pixel(pos[0], pos[1], im::Rgba([0, 0, 0, 255]));
|
|
|
+ for (pos, cell) in world.clone().cells {
|
|
|
+
|
|
|
+ // set dead
|
|
|
+ if cell.dead(step) {
|
|
|
+ let dead_cell = world.cells.get_mut(&pos).unwrap();
|
|
|
+ dead_cell.dead = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // decomposed
|
|
|
+ if cell.decomposed(step) {
|
|
|
+ world.cells.remove(&pos);
|
|
|
+ canvas.put_pixel(pos.x as u32, pos.y as u32, im::Rgba([255, 255, 255, 255]));
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if cell.dead {
|
|
|
+ canvas.put_pixel(pos.x as u32, pos.y as u32, im::Rgba([255, 255, 0, 255]));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ let neighbors: Vec<Vector2<i32>> = vec![
|
|
|
+ Vector2::new(0, 1),
|
|
|
+ Vector2::new(0, -1),
|
|
|
+ Vector2::new(1, 0),
|
|
|
+ Vector2::new(-1, 0),
|
|
|
+ Vector2::new(-1, 1),
|
|
|
+ Vector2::new(-1, -1),
|
|
|
+ Vector2::new(1, 1),
|
|
|
+ Vector2::new(1, -1),
|
|
|
+ ]
|
|
|
+ .iter()
|
|
|
+ .map(move |a| pos+a)
|
|
|
+ .map(|x| clamp(x, min, max))
|
|
|
+ .filter(|x| rng.gen_bool(0.1))
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ canvas.put_pixel(pos.x as u32, pos.y as u32, im::Rgba([0, 0, 0, 255]));
|
|
|
+
|
|
|
+ for n in neighbors {
|
|
|
+ world.cells.entry(n).or_insert(Cell{birth: step, maxage: 110, ..Default::default()});
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- step += 1;
|
|
|
|
|
|
+ step += 1;
|
|
|
texture.update(&mut texture_context, &canvas).unwrap();
|
|
|
window.draw_2d(&e, |c, g, device| {
|
|
|
texture_context.encoder.flush(device);
|
|
|
-
|
|
|
clear([1.0; 4], g);
|
|
|
image(&texture, c.transform, g);
|
|
|
});
|