Guest User

Untitled

a guest
May 30th, 2020
15
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. mod utils;
  2.  
  3. // extern crate js_sys;
  4. // extern crate web_sys;
  5.  
  6. use wasm_bindgen::prelude::*;
  7. use std::fmt;
  8. use wasm_bindgen::__rt::core::fmt::Formatter;
  9. use web_sys;
  10. use web_sys::console;
  11.  
  12. macro_rules! log {
  13. ($( $t:tt)* ) => {
  14. web_sys::console::log_1(&format!($($t)*).into());
  15. };
  16. }
  17.  
  18. pub struct Timer<'a> {
  19. name: &'a str,
  20. }
  21.  
  22. impl <'a> Timer<'a> {
  23.  
  24. pub fn new(name: &'a str) -> Timer<'a> {
  25. console::time_with_label(name);
  26. Timer { name }
  27. }
  28.  
  29. }
  30.  
  31. impl <'a> Drop for Timer<'a> {
  32. fn drop(&mut self) {
  33. console::time_end_with_label(self.name);
  34. }
  35. }
  36.  
  37. fn now() -> f64 {
  38. web_sys::window()
  39. .expect("should have a Window")
  40. .performance()
  41. .expect("should have a Performance")
  42. .now()
  43. }
  44.  
  45. // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
  46. // allocator.
  47. #[cfg(feature = "wee_alloc")]
  48. #[global_allocator]
  49. static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
  50.  
  51. #[wasm_bindgen]
  52. #[repr(u8)]
  53. #[derive(Clone, Copy, Debug, PartialEq, Eq)]
  54. pub enum Cell {
  55. Dead = 0,
  56. Alive = 1,
  57. }
  58.  
  59. pub enum BufActive {
  60. One,
  61. Two
  62. }
  63.  
  64. pub struct DoubleBuffer {
  65. cells_buf_one: Vec<Cell>,
  66. cells_buf_two: Vec<Cell>,
  67. active_buf: BufActive
  68. }
  69.  
  70. pub struct Dimension {
  71. width: u32,
  72. height: u32
  73. }
  74.  
  75. #[wasm_bindgen]
  76. pub struct Universe {
  77. dimension : Dimension,
  78. buffer: DoubleBuffer
  79. }
  80.  
  81. impl DoubleBuffer {
  82. pub fn new(cells: Vec<Cell>) -> Self {
  83. DoubleBuffer {
  84. cells_buf_one : Clone::clone(&cells),
  85. cells_buf_two : cells,
  86. active_buf : BufActive::One
  87. }
  88. }
  89.  
  90. pub fn switch_active_buffer(&mut self) {
  91. self.active_buf = match &self.active_buf {
  92. One => BufActive::Two,
  93. Two => BufActive::One
  94. }
  95. }
  96.  
  97. pub fn get_write_buf_mut(&mut self) -> & mut Vec<Cell> {
  98. match &self.active_buf {
  99. One => &mut self.cells_buf_one,
  100. Two => &mut self.cells_buf_two
  101. }
  102. }
  103.  
  104. pub fn get_read_buf(& self) -> & Vec<Cell> {
  105. match &self.active_buf {
  106. One => & self.cells_buf_one,
  107. Two => & self.cells_buf_two
  108. }
  109. }
  110.  
  111. pub fn get_buf_mut(&mut self) -> (& Vec<Cell>, &mut Vec<Cell>) {
  112. match &self.active_buf {
  113. One => (& self.cells_buf_two, &mut self.cells_buf_one),
  114. Two => (& self.cells_buf_one, &mut self.cells_buf_two)
  115. }
  116. }
  117.  
  118. pub fn init(&mut self, cells: Vec<Cell>) {
  119. self.cells_buf_one = Clone::clone(&cells);
  120. self.cells_buf_two = cells;
  121. }
  122. }
  123.  
  124. impl Dimension {
  125. fn get_index(&self, row: u32, column: u32) -> usize {
  126. (row * self.width + column) as usize
  127. }
  128. }
  129.  
  130. impl Cell {
  131.  
  132. fn toggle(&mut self) {
  133. *self = match self {
  134. Cell::Dead => Cell::Alive,
  135. Cell::Alive => Cell::Dead
  136. }
  137. }
  138.  
  139. }
  140.  
  141. /// Public methods, exported to JavaScript.
  142. #[wasm_bindgen]
  143. impl Universe {
  144.  
  145. pub fn toggle_cell(&mut self, row: u32, column: u32) {
  146. let idx = self.dimension.get_index(row, column);
  147. let writeBuf = self.buffer.get_write_buf_mut();
  148. writeBuf[idx].toggle();
  149. }
  150.  
  151. pub fn width(&self) -> u32 {
  152. self.dimension.width
  153. }
  154.  
  155. pub fn height(&self) -> u32 {
  156. self.dimension.height
  157. }
  158.  
  159. pub fn cells(&self) -> *const Cell {
  160. self.buffer.get_read_buf().as_ptr()
  161. }
  162.  
  163. pub fn set_height(&mut self, height: u32) {
  164. self.dimension.height = height;
  165. self.initCells();
  166. }
  167.  
  168. pub fn set_width(&mut self, width: u32) {
  169. self.dimension.width = width;
  170. self.initCells();
  171. }
  172.  
  173. fn initCells(&mut self) {
  174. self.buffer.init(
  175. (0..self.dimension.width * self.dimension.height)
  176. .map(|_i| Cell::Dead)
  177. .collect());
  178. }
  179.  
  180. pub fn new() -> Universe {
  181.  
  182. utils::set_panic_hook();
  183.  
  184. // panic!("Attention , you life is broken beyond repair!");
  185. let width = 256;
  186. let height = 128;
  187.  
  188. let cells = (0..width * height).map(|i| {
  189. if js_sys::Math::random() < 0.3 || i%2 == 0 {
  190. Cell::Alive
  191. } else {
  192. Cell::Dead
  193. }
  194. }).collect();
  195.  
  196. Universe {
  197. dimension: Dimension { height, width },
  198. buffer: DoubleBuffer::new(cells)
  199. }
  200. }
  201.  
  202. pub fn init_random(&mut self) {
  203. let cells = (0..self.dimension.width * self.dimension.height).map(|i| {
  204. if js_sys::Math::random() < 0.5 {
  205. Cell::Alive
  206. } else {
  207. Cell::Dead
  208. }
  209. }).collect();
  210.  
  211. self.buffer.init(cells);
  212. }
  213.  
  214. pub fn init_clear(&mut self) {
  215. let cells = (0..self.dimension.width * self.dimension.height).map(|i| { Cell::Dead }).collect();
  216. self.buffer.init(cells);
  217. }
  218.  
  219. pub fn render(&self) -> String {
  220. self.to_string()
  221. }
  222.  
  223.  
  224. fn live_neighbor_count(dim: &Dimension, buf: &Vec<Cell>, row: u32, column: u32) -> u8 {
  225.  
  226. // less efficient algorithm
  227. // let mut count = 0;
  228. //
  229. // for delta_row in [self.height -1, 0, 1].iter().cloned() {
  230. // for delta_col in [self.width -1, 0, 1].iter().cloned() {
  231. //
  232. // if delta_row == 0 && delta_col == 0 {
  233. // continue;
  234. // }
  235. //
  236. // let neighbor_row = (row + delta_row) % self.height;
  237. // let neighbor_col = (column + delta_col) % self.width;
  238. // let idx = self.dimension.get_index(neighbor_row, neighbor_col);
  239. // count += self.cells[idx] as u8;
  240. // }
  241. // }
  242. // count
  243.  
  244. let mut count = 0;
  245.  
  246. let north = if row == 0 {
  247. dim.height - 1
  248. } else {
  249. row - 1
  250. };
  251.  
  252. let south = if row == dim.height - 1 {
  253. 0
  254. } else {
  255. row + 1
  256. };
  257.  
  258. let west = if column == 0 {
  259. dim.width - 1
  260. } else {
  261. column - 1
  262. };
  263.  
  264. let east = if column == dim.width - 1 {
  265. 0
  266. } else {
  267. column + 1
  268. };
  269.  
  270. let nw = dim.get_index(north, west);
  271. count += buf[nw] as u8;
  272.  
  273. let n = dim.get_index(north, column);
  274. count += buf[n] as u8;
  275.  
  276. let ne = dim.get_index(north, east);
  277. count += buf[ne] as u8;
  278.  
  279. let w = dim.get_index(row, west);
  280. count += buf[w] as u8;
  281.  
  282. let e = dim.get_index(row, east);
  283. count += buf[e] as u8;
  284.  
  285. let sw = dim.get_index(south, west);
  286. count += buf[sw] as u8;
  287.  
  288. let s = dim.get_index(south, column);
  289. count += buf[s] as u8;
  290.  
  291. let se = dim.get_index(south, east);
  292. count += buf[se] as u8;
  293.  
  294. count
  295.  
  296. }
  297.  
  298.  
  299. pub fn tick(&mut self) {
  300. let _timer = Timer::new("Universe::tick");
  301.  
  302.  
  303. let (readBuf,writeBuf) = self.buffer.get_buf_mut();
  304.  
  305. {
  306. let _timer = Timer::new("new generation");
  307. for row in 0..self.dimension.height {
  308. for col in 0..self.dimension.width {
  309. let idx = self.dimension.get_index(row, col);
  310. let cell = readBuf[idx];
  311. let live_neighbors = Universe::live_neighbor_count(&self.dimension, readBuf, row, col);
  312. //
  313. // log!("cell[{}, {}] is initially {:?} and has {} live neighbors",
  314. // row, col, cell, live_neighbors);
  315.  
  316. let next_cell = match (cell, live_neighbors) {
  317. (Cell::Alive, x) if x < 2 => Cell::Dead,
  318. (Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
  319. (Cell::Alive, x) => Cell::Dead,
  320. (Cell::Dead, 3) => Cell::Alive,
  321. (otherwise,_) => otherwise,
  322. };
  323.  
  324. writeBuf[idx] = next_cell;
  325. }
  326. }
  327. }
  328.  
  329. let _timer = Timer::new("free old cells");
  330.  
  331. self.buffer.switch_active_buffer();
  332. }
  333.  
  334.  
  335. }
  336.  
  337.  
  338. impl Universe {
  339.  
  340. /// Get the dead and alive values of the entire universe.
  341. pub fn get_cells(& self) -> &[Cell] {
  342. self.buffer.get_read_buf()
  343. }
  344.  
  345. /// Set cells to be alive in a universe by passing the row and column
  346. /// of each cell as an array
  347. pub fn set_cells(&mut self, cells: &[(u32,u32)]) {
  348.  
  349. let writebuf = self.buffer.get_write_buf_mut();
  350.  
  351. for (row, col) in cells.iter().cloned() {
  352. let idx = self.dimension.get_index(row, col);
  353. writebuf[idx] = Cell::Alive;
  354. }
  355.  
  356. self.buffer.switch_active_buffer();
  357. }
  358.  
  359. }
  360.  
  361. impl fmt::Display for Universe {
  362. fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
  363.  
  364. let readBuf = self.buffer.get_read_buf();
  365. for line in readBuf.as_slice().chunks(self.dimension.width as usize) {
  366. for &cell in line {
  367. let symbol = if cell == Cell::Dead { '◻' } else { '◼' };
  368. write!(f, "{}", symbol)?;
  369. }
  370. write!(f, "\n")?;
  371. }
  372.  
  373. Ok(())
  374. }
  375.  
  376.  
  377. }
RAW Paste Data