1mod utils;
2
3use wasm_bindgen::prelude::*;
4use std::cmp::{max};
5
6#[cfg(feature = "wee_alloc")]
7#[global_allocator]
8static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
9
10#[wasm_bindgen]
11#[repr(u8)]
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum Cell {
14 None = 0,
15 Black = 1,
16 White = 2,
17}
18
19#[wasm_bindgen]
20#[repr(u8)]
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Direction {
23 Horizontal = 0,
24 Vertical = 1,
25 Diagonal = 2,
26}
27
28
29#[wasm_bindgen]
30pub struct Universe {
31 width: u32,
32 height: u32,
33 turn: u32,
34 cells: Vec<Cell>,
35}
36
37#[wasm_bindgen]
38impl Universe {
39
40 fn next_turn(&mut self){
41 self.turn = self.turn.clone() + 1;
42 }
43
44 pub fn toggle(&mut self, row: u32, col: u32) {
45
46 let turn = if self.turn % 2 == 0 { Cell::Black } else { Cell::White };
47
48 self.set_cell(row, col, turn);
49
50 self.next_turn();
51
52 }
53
54 fn get_index(&self, row: u32, column: u32) -> usize {
55 (row * self.width + column) as usize
56 }
57
58 fn direction_count(&self, color: Cell, direction: Direction ,row: u32, column: u32) -> u32 {
59
60 if row <=14 && column <= 14 && color != Cell::None{
61 let mut count = 1;
62
63 let cells = self.get_cells();
64
65 if cells[self.get_index(row, column)] == color {
66 match direction {
67 Direction::Horizontal => count += self.direction_count(color,direction,row,column+1),
68 Direction::Vertical => count += self.direction_count(color,direction,row+1,column),
69 Direction::Diagonal => count += max(self.direction_count(color,direction,row+1,column+1),self.direction_count(color,direction,row+1,column-1)),
70 }
71 count
72 }else{
73 0
74 }
75 }else{
76 0
77 }
78 }
79
80 pub fn is_win(&mut self) -> Cell{
81
82 for row in 0..self.height{
83 for col in 0..self.width {
84
85 let idx = self.get_index(row, col);
86 let cell = self.cells[idx];
87
88 if self.direction_count(cell, Direction::Horizontal, row, col) == 5 ||
89 self.direction_count(cell, Direction::Vertical, row, col) == 5 ||
90 self.direction_count(cell, Direction::Diagonal, row, col) == 5
91 {
92 return cell;
93 }
94 }
95 }
96
97 Cell::None
98 }
99
100 pub fn new() -> Universe {
101 let width = 15;
102 let height = 15;
103 let turn = 0;
104
105 let cells = (0..width * height)
106 .map(|_i| {
107 Cell::None
108 })
109 .collect();
110
111 Universe {
112 width,
113 height,
114 turn,
115 cells,
116 }
117 }
118
119 fn get_cells(&self) -> &[Cell] {
120 &self.cells
121 }
122
123 pub fn set_cell(&mut self, row: u32, column: u32, cell: Cell) {
124
125 if row <=14 && column <= 14 {
126 let index = self.get_index(row, column);
127 self.cells[index] = cell;
128 }
129
130 }
131 pub fn width(&self) -> u32 {
132 self.width
133 }
134
135 pub fn height(&self) -> u32 {
136 self.height
137 }
138
139 pub fn cells(&self) -> *const Cell {
140 self.cells.as_ptr()
141 }
142
143 pub fn is_non(&self, row: u32, col: u32) -> bool {
144 let index = self.get_index(row, col);
145 self.cells[index] == Cell::None
146 }
147
148}
149
150#[cfg(test)]
151mod tests {
152
153 use super::*;
154
155 #[test]
156 fn universe_get_index() {
157
158 let sut = Universe::new();
159
160 assert_eq!(0,sut.get_index(0,0));
161 assert_eq!(35,sut.get_index(2,5));
162 assert_eq!(209,sut.get_index(13,14));
163
164 }
165
166 #[test]
167 fn universe_get_cell(){
168
169 let sut = Universe::new();
170
171 let cells = sut.get_cells();
172
173 let index = sut.get_index(10,10);
174
175 assert_eq!(Cell::None, cells[index]);
176
177 }
178
179 #[test]
180 fn univsese_set_cell(){
181
182 let mut sut = Universe::new();
183
184 sut.set_cell(10,10,Cell::White);
185
186 let cells = sut.get_cells();
187
188 assert_eq!(Cell::White, cells[sut.get_index(10,10)]);
189
190 }
191
192 #[test]
193 fn universe_direction_count_horizontal(){
194
195 let mut sut = Universe::new();
196
197 sut.set_cell(10,5,Cell::Black);
198 sut.set_cell(10,6,Cell::Black);
199 sut.set_cell(10,7,Cell::Black);
200
201 assert_eq!(0,sut.direction_count(Cell::White, Direction::Horizontal , 10, 5));
202 assert_eq!(3,sut.direction_count(Cell::Black, Direction::Horizontal , 10, 5));
203
204 }
205
206 #[test]
207 fn universe_direction_count_out_of_bound(){
208
209 let mut sut = Universe::new();
210
211 sut.set_cell(14,14,Cell::Black);
212
213 assert_eq!(1,sut.direction_count(Cell::Black, Direction::Horizontal , 14, 14));
214 }
215
216
217 #[test]
218 fn universe_direction_count_vertical(){
219
220 let mut sut = Universe::new();
221
222 sut.set_cell(9,5,Cell::Black);
223 sut.set_cell(10,5,Cell::Black);
224 sut.set_cell(11,5,Cell::Black);
225 sut.set_cell(12,5,Cell::Black);
226 sut.set_cell(13,5,Cell::Black);
227
228
229 assert_eq!(5,sut.direction_count(Cell::Black, Direction::Vertical , 9, 5));
230
231 }
232
233 #[test]
234 fn universe_direction_count_diagonal(){
235
236 let mut sut = Universe::new();
237
238 sut.set_cell(5,5,Cell::Black);
239 sut.set_cell(6,6,Cell::Black);
240 sut.set_cell(7,7,Cell::Black);
241 sut.set_cell(8,8,Cell::Black);
242 sut.set_cell(9,9,Cell::Black);
243
244 assert_eq!(5,sut.direction_count(Cell::Black, Direction::Diagonal , 5, 5));
245
246 }
247
248 #[test]
249 fn universe_direction_count_not_none(){
250
251 let sut = Universe::new();
252
253 assert_eq!(0,sut.direction_count(Cell::None, Direction::Diagonal , 5, 5));
254
255 }
256
257 #[test]
258 fn universe_not_win(){
259
260 let mut sut = Universe::new();
261
262 assert_eq!(Cell::None, sut.is_win());
263 }
264
265 #[test]
266 fn universe_black_win(){
267
268 let mut sut = Universe::new();
269
270 sut.set_cell(5,5,Cell::Black);
271 sut.set_cell(6,6,Cell::Black);
272 sut.set_cell(7,7,Cell::Black);
273 sut.set_cell(8,8,Cell::Black);
274 sut.set_cell(9,9,Cell::Black);
275
276 assert_eq!(Cell::Black, sut.is_win());
277
278 }
279
280 #[test]
281 fn universe_white_win(){
282
283 let mut sut = Universe::new();
284
285 sut.set_cell(5,5,Cell::White);
286 sut.set_cell(5,6,Cell::White);
287 sut.set_cell(5,7,Cell::White);
288 sut.set_cell(5,8,Cell::White);
289 sut.set_cell(5,9,Cell::White);
290
291 assert_eq!(Cell::White, sut.is_win());
292
293 }
294
295 #[test]
296 fn universe_toggle_cell(){
297
298 let mut sut = Universe::new();
299
300 sut.toggle(4, 4);
301 sut.toggle(8, 5);
302 sut.toggle(1, 7);
303 sut.toggle(4, 2);
304 sut.toggle(10, 4);
305
306
307 let cells = sut.get_cells();
308
309 assert_eq!(Cell::Black, cells[sut.get_index(4, 4)]);
310 assert_eq!(Cell::White, cells[sut.get_index(8, 5)]);
311 assert_eq!(Cell::Black, cells[sut.get_index(1, 7)]);
312 assert_eq!(Cell::White, cells[sut.get_index(4, 2)]);
313 assert_eq!(Cell::Black, cells[sut.get_index(10, 4)]);
314
315 }
316
317 #[test]
318 fn universe_not_none_cell(){
319
320 let sut = Universe::new();
321
322 assert_eq!(true,sut.is_non(10,10));
323
324 }
325
326}