Generate a grid with cellular automata
[kaka/rust-sdl-test.git] / src / core / level.rs
1 use common::Point2D;
2 use core::render::Renderer;
3 use rand::Rng;
4 use sprites::SpriteManager;
5
6 ////////// LEVEL ///////////////////////////////////////////////////////////////
7
8 #[derive(Default)]
9 pub struct Level {
10     pub gravity: Point2D<f64>,
11     pub ground: f64,            // just to have something
12     pub grid: Grid,
13     iterations: u8,
14 }
15
16 impl Level {
17     pub fn new(gravity: Point2D<f64>, ground: f64) -> Self {
18         Level { gravity, ground, grid: Grid::generate(10), iterations: 10 }
19     }
20
21     pub fn regenerate(&mut self) {
22         self.grid = Grid::generate(self.iterations);
23     }
24
25     pub fn increase_iteration(&mut self) {
26         self.iterations += 1;
27         self.regenerate();
28         println!("iterate {} time(s)", self.iterations);
29     }
30
31     pub fn decrease_iteration(&mut self) {
32         self.iterations -= 1;
33         self.regenerate();
34         println!("iterate {} time(s)", self.iterations);
35     }
36
37     pub fn render(&mut self, renderer: &mut Renderer, _sprites: &SpriteManager) {
38         let w = renderer.viewport().0 as i32;
39
40         renderer.canvas().set_draw_color((64, 64, 64));
41         let size = self.grid.cell_size;
42         for x in 0..self.grid.width {
43             for y in 0..self.grid.height {
44                 if self.grid.cells[x][y] {
45                     renderer.canvas().fill_rect(sdl2::rect::Rect::new(x as i32 * size as i32, y as i32 * size as i32, size as u32, size as u32)).unwrap();
46                 }
47             }
48         }
49
50         for i in 1..11 {
51             let y = (i * i - 1) as i32 + self.ground as i32;
52             renderer.canvas().set_draw_color((255 - i * 20, 255 - i * 20, 0));
53             renderer.canvas().draw_line((0, y), (w, y)).unwrap();
54         }
55     }
56 }
57
58 ////////// GRID ////////////////////////////////////////////////////////////////
59
60 #[derive(Default)]
61 pub struct Grid {
62     pub width: usize,
63     pub height: usize,
64     pub cell_size: usize,
65     pub cells: Vec<Vec<bool>>,
66 }
67
68 impl Grid {
69     fn generate(iterations: u8) -> Grid {
70         let cell_size = 10;
71         let (width, height) = (1280 / cell_size, 600 / cell_size);
72         let mut cells = vec!(vec!(true; height); width);
73
74         let mut rng = rand::thread_rng();
75
76         // randomize
77         for x in 1..(width - 1) {
78             for y in 1..(height - 1) {
79                 cells[x][y] = rng.gen_range(0, 100) > 55;
80             }
81         }
82
83         // smooth
84         // let mut count = 0;
85         // loop {
86         //     count += 1;
87         //     println!("iteration {}", count);
88         for _i in 0..iterations {
89             let mut next = vec!(vec!(true; height); width);
90             for x in 1..(width - 1) {
91                 for y in 1..(height - 1) {
92                     match Grid::neighbours(&cells, x, y) {
93                         n if n < 4 => next[x][y] = false,
94                         n if n > 4 => next[x][y] = true,
95                         _ => next[x][y] = cells[x][y]
96                     };
97                 }
98             }
99             if cells == next {
100                 break;
101             } else {
102                 cells = next;
103             }
104         }
105
106         Grid {
107             width,
108             height,
109             cell_size,
110             cells
111         }
112     }
113
114     fn neighbours(grid: &Vec<Vec<bool>>, px: usize, py: usize) -> u8 {
115         let mut count = 0;
116         for x in (px - 1)..=(px + 1) {
117             for y in (py - 1)..=(py + 1) {
118                 if !(x == px && y == py) && grid[x][y] {
119                     count += 1;
120                 }
121             }
122         }
123         count
124     }
125 }