rust-gomoku 0.0.2

A console and web-based Gomoku written in Rust and WebAssembly
Documentation
mod utils;

use wasm_bindgen::prelude::*;
use std::cmp::{max};

#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
    None = 0,
    Black = 1,
    White = 2,
}

#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Horizontal = 0,
    Vertical = 1,
    Diagonal = 2,
}


#[wasm_bindgen]
pub struct Universe {
    width: u32,
    height: u32,
    turn: u32,
    cells: Vec<Cell>,
}

#[wasm_bindgen]
impl Universe {

    fn next_turn(&mut self){
        self.turn = self.turn.clone() + 1;
    }

    pub fn toggle(&mut self, row: u32, col: u32) {
        
        let turn = if self.turn % 2 == 0 { Cell::Black } else { Cell::White };

        self.set_cell(row, col, turn);
        
        self.next_turn();

    }

    fn get_index(&self, row: u32, column: u32) -> usize {
        (row * self.width + column) as usize
    }

    fn direction_count(&self, color: Cell, direction: Direction ,row: u32, column: u32) -> u32 {
        
        if row <=14 && column <= 14 && color != Cell::None{
            let mut count = 1;

            let cells = self.get_cells();

            if cells[self.get_index(row, column)] == color {
                match direction {
                    Direction::Horizontal => count += self.direction_count(color,direction,row,column+1),
                    Direction::Vertical => count += self.direction_count(color,direction,row+1,column),
                    Direction::Diagonal => count += max(self.direction_count(color,direction,row+1,column+1),self.direction_count(color,direction,row+1,column-1)),
                }
                count
            }else{
                0
            }
        }else{
            0
        }
    }

    pub fn is_win(&mut self) -> Cell{
        
        for row in 0..self.height{
            for col in 0..self.width {
                
                let idx = self.get_index(row, col);
                let cell = self.cells[idx];

                if self.direction_count(cell, Direction::Horizontal, row, col) == 5 || 
                   self.direction_count(cell, Direction::Vertical, row, col) == 5 || 
                   self.direction_count(cell, Direction::Diagonal, row, col) == 5 
                {
                    return cell;
                }
            }
        }

        Cell::None
    }

    pub fn new() -> Universe {
        let width = 15;
        let height = 15;
        let turn = 0;

        let cells = (0..width * height)
            .map(|_i| {
                Cell::None
            })
            .collect();

        Universe {
            width,
            height,
            turn,
            cells,
        }
    }

    fn get_cells(&self) -> &[Cell] {
        &self.cells
    }

    pub fn set_cell(&mut self, row: u32, column: u32, cell: Cell) {
        
        if row <=14 && column <= 14 {
            let index = self.get_index(row, column);
            self.cells[index] = cell;
        }
        
    }
    pub fn width(&self) -> u32 {
        self.width
    }

    pub fn height(&self) -> u32 {
        self.height
    }

    pub fn cells(&self) -> *const Cell {
        self.cells.as_ptr()
    }

    pub fn is_non(&self, row: u32, col: u32) -> bool {
        let index = self.get_index(row, col);
        self.cells[index] == Cell::None
    }

}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn universe_get_index() {
        
        let sut = Universe::new();
        
        assert_eq!(0,sut.get_index(0,0));
        assert_eq!(35,sut.get_index(2,5));
        assert_eq!(209,sut.get_index(13,14));

    }

    #[test]
    fn universe_get_cell(){

        let sut = Universe::new();

        let cells = sut.get_cells();

        let index = sut.get_index(10,10);

        assert_eq!(Cell::None, cells[index]);

    }

    #[test]
    fn univsese_set_cell(){

        let mut sut = Universe::new();

        sut.set_cell(10,10,Cell::White);

        let cells = sut.get_cells();

        assert_eq!(Cell::White, cells[sut.get_index(10,10)]);

    }

    #[test]
    fn universe_direction_count_horizontal(){

        let mut sut = Universe::new();

        sut.set_cell(10,5,Cell::Black);
        sut.set_cell(10,6,Cell::Black);
        sut.set_cell(10,7,Cell::Black);

        assert_eq!(0,sut.direction_count(Cell::White, Direction::Horizontal , 10, 5));
        assert_eq!(3,sut.direction_count(Cell::Black, Direction::Horizontal , 10, 5));
        
    }

    #[test]
    fn universe_direction_count_out_of_bound(){

        let mut sut = Universe::new();

        sut.set_cell(14,14,Cell::Black);
        
        assert_eq!(1,sut.direction_count(Cell::Black, Direction::Horizontal , 14, 14));
    }


    #[test]
    fn universe_direction_count_vertical(){

        let mut sut = Universe::new();

        sut.set_cell(9,5,Cell::Black);
        sut.set_cell(10,5,Cell::Black);
        sut.set_cell(11,5,Cell::Black);
        sut.set_cell(12,5,Cell::Black);
        sut.set_cell(13,5,Cell::Black);
        

        assert_eq!(5,sut.direction_count(Cell::Black, Direction::Vertical , 9, 5));

    }

    #[test]
    fn universe_direction_count_diagonal(){

        let mut sut = Universe::new();

        sut.set_cell(5,5,Cell::Black);
        sut.set_cell(6,6,Cell::Black);
        sut.set_cell(7,7,Cell::Black);
        sut.set_cell(8,8,Cell::Black);
        sut.set_cell(9,9,Cell::Black);

        assert_eq!(5,sut.direction_count(Cell::Black, Direction::Diagonal , 5, 5));

    }

    #[test]
    fn universe_direction_count_not_none(){

        let sut = Universe::new();

        assert_eq!(0,sut.direction_count(Cell::None, Direction::Diagonal , 5, 5));

    }

    #[test]
    fn universe_not_win(){

        let mut sut = Universe::new();

        assert_eq!(Cell::None, sut.is_win());
    }

    #[test]
    fn universe_black_win(){

        let mut sut = Universe::new();

        sut.set_cell(5,5,Cell::Black);
        sut.set_cell(6,6,Cell::Black);
        sut.set_cell(7,7,Cell::Black);
        sut.set_cell(8,8,Cell::Black);
        sut.set_cell(9,9,Cell::Black);
        
        assert_eq!(Cell::Black, sut.is_win());
        
    }

    #[test]
    fn universe_white_win(){

        let mut sut = Universe::new();

        sut.set_cell(5,5,Cell::White);
        sut.set_cell(5,6,Cell::White);
        sut.set_cell(5,7,Cell::White);
        sut.set_cell(5,8,Cell::White);
        sut.set_cell(5,9,Cell::White);
        
        assert_eq!(Cell::White, sut.is_win());

    }    

    #[test]
    fn universe_toggle_cell(){

        let mut sut = Universe::new();

        sut.toggle(4, 4);
        sut.toggle(8, 5);
        sut.toggle(1, 7);
        sut.toggle(4, 2);
        sut.toggle(10, 4);
        
        
        let cells = sut.get_cells();

        assert_eq!(Cell::Black, cells[sut.get_index(4, 4)]);
        assert_eq!(Cell::White, cells[sut.get_index(8, 5)]);
        assert_eq!(Cell::Black, cells[sut.get_index(1, 7)]);
        assert_eq!(Cell::White, cells[sut.get_index(4, 2)]);
        assert_eq!(Cell::Black, cells[sut.get_index(10, 4)]);
        
    }

    #[test]
    fn universe_not_none_cell(){

        let sut = Universe::new();

        assert_eq!(true,sut.is_non(10,10));

    }

}