moving working and testing, dev/prod webpack
This commit is contained in:
parent
17ed845125
commit
8dbc2eb586
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@ -18,12 +18,12 @@ jobs:
|
|||||||
- name: Install wasm-pack
|
- name: Install wasm-pack
|
||||||
uses: jetli/wasm-pack-action@v0.3.0
|
uses: jetli/wasm-pack-action@v0.3.0
|
||||||
|
|
||||||
- name: Build Rust for WASM
|
|
||||||
run: wasm-pack build
|
|
||||||
|
|
||||||
- name: Test WASM in-browser
|
- name: Test WASM in-browser
|
||||||
run: wasm-pack test --firefox --chrome --headless
|
run: wasm-pack test --firefox --chrome --headless
|
||||||
|
|
||||||
|
- name: Build Rust for WASM
|
||||||
|
run: wasm-pack build
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::board::{Board, Square};
|
use crate::board::{Board, Piece, Square};
|
||||||
|
use crate::board::enums::*;
|
||||||
|
|
||||||
pub struct RowIndexIterator<'a> {
|
pub struct RowIndexIterator<'a> {
|
||||||
board: &'a Board,
|
board: &'a Board,
|
||||||
@ -67,17 +68,51 @@ impl<'a> Iterator for RowSquareIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PieceIterator<'a> {
|
||||||
|
board: &'a Board,
|
||||||
|
index_cursor: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PieceIterator<'a> {
|
||||||
|
pub fn new(board: &'a Board) -> Self {
|
||||||
|
Self {
|
||||||
|
board,
|
||||||
|
index_cursor: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for PieceIterator<'a> {
|
||||||
|
type Item = (usize, Square);
|
||||||
|
|
||||||
|
/// Get next item from the iterator
|
||||||
|
fn next(&mut self) -> Option<(usize, Square)> {
|
||||||
|
|
||||||
|
while self.index_cursor < self.board.num_cells() - 1 {
|
||||||
|
self.index_cursor += 1;
|
||||||
|
match self.board.cell(self.index_cursor).state {
|
||||||
|
SquareState::Empty | SquareState::Unplayable => continue,
|
||||||
|
SquareState::Occupied => return Some((self.index_cursor, self.board.cell(self.index_cursor))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::board::enums::SquareState;
|
use crate::board::enums::SquareState;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
|
use crate::log;
|
||||||
|
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn index_iterator() {
|
fn index_iterator() {
|
||||||
let board = Board::new(2, 2);
|
let board = Board::new(2, 2, Team::Black);
|
||||||
let iter = RowIndexIterator::new(&board);
|
let iter = RowIndexIterator::new(&board);
|
||||||
let collected: Vec<Vec<usize>> = iter.collect();
|
let collected: Vec<Vec<usize>> = iter.collect();
|
||||||
assert_eq!(vec![
|
assert_eq!(vec![
|
||||||
@ -88,7 +123,7 @@ mod tests {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn square_iterator() {
|
fn square_iterator() {
|
||||||
let board = Board::new(2, 2);
|
let board = Board::new(2, 2, Team::Black);
|
||||||
let iter = RowSquareIterator::new(&board);
|
let iter = RowSquareIterator::new(&board);
|
||||||
let collected: Vec<Vec<Square>> = iter.collect();
|
let collected: Vec<Vec<Square>> = iter.collect();
|
||||||
assert_eq!(vec![
|
assert_eq!(vec![
|
||||||
@ -103,4 +138,57 @@ mod tests {
|
|||||||
], collected);
|
], collected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn piece_iterator_one_piece() {
|
||||||
|
let idx = 2;
|
||||||
|
|
||||||
|
let mut board = Board::new(4, 4, Team::Black);
|
||||||
|
board.set_cell(idx, Square::new(
|
||||||
|
SquareState::Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(Team::White, Strength::Man)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
let iter = PieceIterator::new(&board);
|
||||||
|
let collected: Vec<(usize, Square)> = iter.collect();
|
||||||
|
|
||||||
|
assert_eq!(collected.len(), 1);
|
||||||
|
assert_eq!(collected[0], (idx, board.cell(idx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn piece_iterator_multiple_pieces() {
|
||||||
|
|
||||||
|
let mut board = Board::new(4, 4, Team::Black);
|
||||||
|
board.set_cell(2, Square::new(
|
||||||
|
SquareState::Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(Team::White, Strength::Man)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
board.set_cell(4, Square::new(
|
||||||
|
SquareState::Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(Team::Black, Strength::Man)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
board.set_cell(5, Square::new(
|
||||||
|
SquareState::Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(Team::White, Strength::King)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
let iter = PieceIterator::new(&board);
|
||||||
|
let collected: Vec<(usize, Square)> = iter.collect();
|
||||||
|
|
||||||
|
assert_eq!(collected.len(), 3);
|
||||||
|
assert_eq!(collected[0], (2, board.cell(2)));
|
||||||
|
assert_eq!(collected[1], (4, board.cell(4)));
|
||||||
|
assert_eq!(collected[2], (5, board.cell(5)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
244
src/board/mod.rs
244
src/board/mod.rs
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
pub mod enums;
|
pub mod enums;
|
||||||
use enums::*;
|
use enums::*;
|
||||||
|
use enums::Team::*;
|
||||||
|
use enums::Strength::*;
|
||||||
|
use enums::SquareState::*;
|
||||||
|
|
||||||
pub mod iter;
|
pub mod iter;
|
||||||
use iter::*;
|
use iter::*;
|
||||||
@ -19,7 +22,7 @@ pub const STD_WIDTH: usize = 8;
|
|||||||
/// Standard height of a checkers board is 8 squares
|
/// Standard height of a checkers board is 8 squares
|
||||||
pub const STD_HEIGHT: usize = 8;
|
pub const STD_HEIGHT: usize = 8;
|
||||||
|
|
||||||
/// Model a game piece by its team and strength (normal or kinged)
|
/// Game piece given by its team and strength (normal or kinged)
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct Piece {
|
pub struct Piece {
|
||||||
@ -27,7 +30,9 @@ pub struct Piece {
|
|||||||
strength: Strength
|
strength: Strength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
impl Piece {
|
impl Piece {
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new(team: Team, strength: Strength) -> Piece {
|
pub fn new(team: Team, strength: Strength) -> Piece {
|
||||||
Piece {
|
Piece {
|
||||||
team, strength
|
team, strength
|
||||||
@ -35,7 +40,7 @@ impl Piece {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Model the standard diagonal movements by north west/east etc
|
/// Standard diagonal movements given by north west/east etc
|
||||||
///
|
///
|
||||||
/// Used as an absolute measure, i.e. not relative to the team making a move
|
/// Used as an absolute measure, i.e. not relative to the team making a move
|
||||||
///
|
///
|
||||||
@ -64,7 +69,7 @@ impl<T: Clone + Copy> Direction<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Model board squares by a state and a possible occupying game piece
|
/// Board squares given by a state and a possible occupying game piece
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct Square {
|
pub struct Square {
|
||||||
@ -74,16 +79,32 @@ pub struct Square {
|
|||||||
state: SquareState
|
state: SquareState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
impl Square {
|
impl Square {
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new(state: SquareState, occupant: Option<Piece>) -> Square{
|
pub fn new(state: SquareState, occupant: Option<Piece>) -> Square{
|
||||||
Square {
|
Square {
|
||||||
occupant,
|
occupant,
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pc(team: Team, strength: Strength) -> Square {
|
||||||
|
Square {
|
||||||
|
occupant: Some(Piece::new(team, strength)),
|
||||||
|
state: Occupied,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Model a rank 2 tensor index to identify a board square by row and column
|
pub fn empty() -> Square {
|
||||||
|
Square {
|
||||||
|
occupant: None,
|
||||||
|
state: Empty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rank 2 tensor index to identify a board square by row and column
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct BrdIdx {
|
pub struct BrdIdx {
|
||||||
@ -110,9 +131,9 @@ impl Display for BrdIdx {
|
|||||||
// BOARD
|
// BOARD
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
/// Models a single state for a checkers board
|
/// Single state of a checkers board
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
/// 1D backing array of board squares for the 2D game board
|
/// 1D backing array of board squares for the 2D game board
|
||||||
cells: Vec<Square>,
|
cells: Vec<Square>,
|
||||||
@ -122,6 +143,10 @@ pub struct Board {
|
|||||||
current_turn: Team
|
current_turn: Team
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// PRIV FUNCS
|
||||||
|
///////////////////
|
||||||
|
|
||||||
impl Board {
|
impl Board {
|
||||||
/// Get a mutable reference to a board square by 1D array index
|
/// Get a mutable reference to a board square by 1D array index
|
||||||
pub fn cell_mut(&mut self, idx: usize) -> &mut Square {
|
pub fn cell_mut(&mut self, idx: usize) -> &mut Square {
|
||||||
@ -136,7 +161,7 @@ impl Board {
|
|||||||
/// Some(Vec<usize>): A variable length vector of 1D indices for diagonally adjacent squares.
|
/// Some(Vec<usize>): A variable length vector of 1D indices for diagonally adjacent squares.
|
||||||
/// Vector may be between 1 and 4 items long depending on the location of the given square
|
/// Vector may be between 1 and 4 items long depending on the location of the given square
|
||||||
pub fn diagonal_indices(&self, idx: BrdIdx) -> Option<Vec<usize>> {
|
pub fn diagonal_indices(&self, idx: BrdIdx) -> Option<Vec<usize>> {
|
||||||
if self.cell_state(self.cell_idx(idx)) == SquareState::Unplayable {
|
if self.cell_state(self.cell_idx(idx)) == Unplayable {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +211,7 @@ impl Board {
|
|||||||
///
|
///
|
||||||
/// Some(Direction<Square>): A [`Direction`] structure for the diagonally adjacent squares.
|
/// Some(Direction<Square>): A [`Direction`] structure for the diagonally adjacent squares.
|
||||||
pub fn adjacent_dir(&self, idx: BrdIdx) -> Option<Direction<Square>> {
|
pub fn adjacent_dir(&self, idx: BrdIdx) -> Option<Direction<Square>> {
|
||||||
if self.cell_state(self.cell_idx(idx)) == SquareState::Unplayable {
|
if self.cell_state(self.cell_idx(idx)) == Unplayable {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +247,8 @@ impl Board {
|
|||||||
pub fn filter_indices(&self, idx: BrdIdx, player: Team, indices: Vec<usize>) -> Vec<usize> {
|
pub fn filter_indices(&self, idx: BrdIdx, player: Team, indices: Vec<usize>) -> Vec<usize> {
|
||||||
indices.into_iter().filter(|i| {
|
indices.into_iter().filter(|i| {
|
||||||
match player {
|
match player {
|
||||||
Team::Black => self.board_index(*i).row < idx.row,
|
Black => self.board_index(*i).row < idx.row,
|
||||||
Team::White => self.board_index(*i).row > idx.row,
|
White => self.board_index(*i).row > idx.row,
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
@ -243,7 +268,7 @@ impl Board {
|
|||||||
/// Some(Vec<usize>): A variable length vector of 1D indices for diagonally jumpable squares.
|
/// Some(Vec<usize>): A variable length vector of 1D indices for diagonally jumpable squares.
|
||||||
/// Vector may be between 1 and 4 items long depending on the location of the given square
|
/// Vector may be between 1 and 4 items long depending on the location of the given square
|
||||||
pub fn jumpable_indices(&self, idx: BrdIdx) -> Option<Vec<usize>> {
|
pub fn jumpable_indices(&self, idx: BrdIdx) -> Option<Vec<usize>> {
|
||||||
if self.cell_state(self.cell_idx(idx)) == SquareState::Unplayable {
|
if self.cell_state(self.cell_idx(idx)) == Unplayable {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +318,7 @@ impl Board {
|
|||||||
///
|
///
|
||||||
/// Some(Direction<Square>): A [`Direction`] structure for the diagonally jumpable squares.
|
/// Some(Direction<Square>): A [`Direction`] structure for the diagonally jumpable squares.
|
||||||
pub fn jumpable_dir(&self, idx: BrdIdx) -> Option<Direction<Square>> {
|
pub fn jumpable_dir(&self, idx: BrdIdx) -> Option<Direction<Square>> {
|
||||||
if self.cell_state(self.cell_idx(idx)) == SquareState::Unplayable {
|
if self.cell_state(self.cell_idx(idx)) == Unplayable {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,7 +356,17 @@ impl Board {
|
|||||||
None => None
|
None => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// cast the signed
|
||||||
|
pub fn idx_diffs(from: BrdIdx, to: BrdIdx) -> (isize, isize) {
|
||||||
|
// cast to signed ints so that -1 will work for black moves
|
||||||
|
(to.row as isize - from.row as isize, to.col as isize - from.col as isize)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// BOUND FUNCS
|
||||||
|
///////////////////
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl Board {
|
impl Board {
|
||||||
@ -340,6 +375,15 @@ impl Board {
|
|||||||
self.cells[idx]
|
self.cells[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a copy of a board square by 1D array index
|
||||||
|
pub fn set_cell(&mut self, idx: usize, square: Square) {
|
||||||
|
// TODO: handle this error better?
|
||||||
|
if idx >= self.num_cells() {
|
||||||
|
panic!("Given index is too large, idx: {}, square: {:?}", idx, square);
|
||||||
|
}
|
||||||
|
self.cells[idx] = square;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a copy of a board square by 2D [`BrdIdx`] index
|
/// Get a copy of a board square by 2D [`BrdIdx`] index
|
||||||
pub fn grid_cell(&self, idx: BrdIdx) -> Square {
|
pub fn grid_cell(&self, idx: BrdIdx) -> Square {
|
||||||
self.cell(self.cell_idx(idx))
|
self.cell(self.cell_idx(idx))
|
||||||
@ -362,6 +406,7 @@ impl Board {
|
|||||||
BrdIdx::from(row, col)
|
BrdIdx::from(row, col)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether a move given by source and destination indices is legal
|
||||||
pub fn can_move(&self, from: BrdIdx, to: BrdIdx) -> Moveable {
|
pub fn can_move(&self, from: BrdIdx, to: BrdIdx) -> Moveable {
|
||||||
|
|
||||||
if from.row > self.height - 1 || from.col > self.width - 1 {
|
if from.row > self.height - 1 || from.col > self.width - 1 {
|
||||||
@ -376,9 +421,9 @@ impl Board {
|
|||||||
|
|
||||||
// check source square is occupied
|
// check source square is occupied
|
||||||
match from_square.state {
|
match from_square.state {
|
||||||
SquareState::Empty => return Moveable::UnoccupiedSrc,
|
Empty => return Moveable::UnoccupiedSrc,
|
||||||
SquareState::Unplayable => return Moveable::Unplayable,
|
Unplayable => return Moveable::Unplayable,
|
||||||
SquareState::Occupied => {
|
Occupied => {
|
||||||
|
|
||||||
// if its not the current teams piece then error
|
// if its not the current teams piece then error
|
||||||
match from_square.occupant {
|
match from_square.occupant {
|
||||||
@ -391,29 +436,50 @@ impl Board {
|
|||||||
return Moveable::WrongTeamSrc;
|
return Moveable::WrongTeamSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cast to signed ints so that -1 will work for black moves
|
|
||||||
let row_diff: i32 = to.row as i32 - from.row as i32;
|
|
||||||
let col_diff: i32 = to.col as i32 - from.col as i32;
|
|
||||||
|
|
||||||
// depending on whether the piece is a king or not, the piece can make different moves
|
// depending on whether the piece is a king or not, the piece can make different moves
|
||||||
|
// below validate_*_move() functions just check whether the trajectory is valid i.e a single ajacacent diagonal move for moves and 2 squares for a jump
|
||||||
|
// this includes validating the jumpee when jumping
|
||||||
|
//
|
||||||
|
// we use the Allowed type to indicate that the trajectory check passed
|
||||||
|
// but we catch it instead of returning to allow further checks on
|
||||||
|
// the destination square
|
||||||
// TODO: refactor to a IsMove()/IsJump() to check whether the move has a legal trajectory
|
// TODO: refactor to a IsMove()/IsJump() to check whether the move has a legal trajectory
|
||||||
match from_square_occupant.strength {
|
match from_square_occupant.strength {
|
||||||
Strength::Man => self.validate_man_move(from, to, row_diff, col_diff, from_square_occupant),
|
Man => {
|
||||||
Strength::King => self.validate_king_move(from, to, row_diff, col_diff, from_square_occupant),
|
let strength_check = self.validate_man_move(from, to, from_square_occupant);
|
||||||
|
if strength_check != Moveable::Allowed {
|
||||||
|
return strength_check;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
King => {
|
||||||
|
let strength_check = self.validate_king_move(from, to, from_square_occupant);
|
||||||
|
if strength_check != Moveable::Allowed {
|
||||||
|
return strength_check;
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let to_square = self.cell(self.cell_idx(to));
|
||||||
|
match to_square.state {
|
||||||
|
Empty => {
|
||||||
|
return Moveable::Allowed;
|
||||||
|
},
|
||||||
|
Unplayable => return Moveable::Unplayable,
|
||||||
|
Occupied => return Moveable::OccupiedDest,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Moveable::Allowed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_man_move(&self, from: BrdIdx, to: BrdIdx, row_diff: i32, col_diff: i32, from_square_occupant: Piece) -> Moveable {
|
pub fn validate_man_move(&self, from: BrdIdx, to: BrdIdx, from_square_occupant: Piece) -> Moveable {
|
||||||
|
let (row_diff, col_diff) = Board::idx_diffs(from, to);
|
||||||
|
|
||||||
// men can only move forwards, below is row difference for each team
|
// men can only move forwards, below is row difference for each team
|
||||||
let idx_scale: i32 = match self.current_turn {
|
let idx_scale: isize = match self.current_turn {
|
||||||
Team::Black => -1,
|
Black => -1,
|
||||||
Team::White => 1,
|
White => 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// legal standard move
|
// legal standard move
|
||||||
@ -433,14 +499,14 @@ impl Board {
|
|||||||
if col_diff.abs() == 2 {
|
if col_diff.abs() == 2 {
|
||||||
|
|
||||||
// piece to be jumped over
|
// piece to be jumped over
|
||||||
let jumpee = self.get_jumpee(from, row_diff, col_diff);
|
let jumpee = self.cell(self.jumpee_idx(from, to));
|
||||||
match jumpee.state {
|
match jumpee.state {
|
||||||
SquareState::Empty => Moveable::NoJumpablePiece,
|
Empty => Moveable::NoJumpablePiece,
|
||||||
SquareState::Unplayable => panic!("Found an unplayable piece to try to jump over, from: {}, to: {}, jumpee: {:?}", from, to, jumpee),
|
Unplayable => panic!("Found an unplayable piece to try to jump over, from: {}, to: {}, jumpee: {:?}", from, to, jumpee),
|
||||||
SquareState::Occupied => {
|
Occupied => {
|
||||||
|
|
||||||
// check whether jumpee is an opponent's piece
|
// check whether jumpee is an opponent's piece
|
||||||
return Board::validate_jumpee(jumpee, from, to, from_square_occupant);
|
return Board::validate_jumpee(jumpee, from_square_occupant);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,7 +521,9 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_king_move(&self, from: BrdIdx, to: BrdIdx, row_diff: i32, col_diff: i32, from_square_occupant: Piece) -> Moveable {
|
pub fn validate_king_move(&self, from: BrdIdx, to: BrdIdx, from_square_occupant: Piece) -> Moveable {
|
||||||
|
let (row_diff, col_diff) = Board::idx_diffs(from, to);
|
||||||
|
|
||||||
// legal standard move
|
// legal standard move
|
||||||
if row_diff.abs() == 1 {
|
if row_diff.abs() == 1 {
|
||||||
// destination is directly to the left or right
|
// destination is directly to the left or right
|
||||||
@ -473,14 +541,14 @@ impl Board {
|
|||||||
if col_diff.abs() == 2 {
|
if col_diff.abs() == 2 {
|
||||||
|
|
||||||
// piece to be jumped over
|
// piece to be jumped over
|
||||||
let jumpee = self.get_jumpee(from, row_diff, col_diff);
|
let jumpee = self.cell(self.jumpee_idx(from, to));
|
||||||
match jumpee.state {
|
match jumpee.state {
|
||||||
SquareState::Empty => Moveable::NoJumpablePiece,
|
Empty => Moveable::NoJumpablePiece,
|
||||||
SquareState::Unplayable => panic!("Found an unplayable piece to try to jump over, from: {}, to: {}, jumpee: {:?}", from, to, jumpee),
|
Unplayable => panic!("Found an unplayable piece to try to jump over, from: {}, to: {}, jumpee: {:?}", from, to, jumpee),
|
||||||
SquareState::Occupied => {
|
Occupied => {
|
||||||
|
|
||||||
// check whether jumpee is an opponent's piece
|
// check whether jumpee is an opponent's piece
|
||||||
return Board::validate_jumpee(jumpee, from, to, from_square_occupant);
|
return Board::validate_jumpee(jumpee, from_square_occupant);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -495,20 +563,20 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_jumpee(&self, from: BrdIdx, row_diff: i32, col_diff: i32) -> Square {
|
pub fn jumpee_idx(&self, from: BrdIdx, to: BrdIdx) -> usize {
|
||||||
self.cell(
|
let (row_diff, col_diff) = Board::idx_diffs(from, to);
|
||||||
self.cell_idx(
|
self.cell_idx(
|
||||||
BrdIdx::from(
|
BrdIdx::from(
|
||||||
((from.row as i32) + row_diff / 2) as usize,
|
((from.row as isize) + row_diff / 2) as usize,
|
||||||
((from.col as i32) + col_diff / 2) as usize)
|
((from.col as isize) + col_diff / 2) as usize)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_jumpee(jumpee: Square, from: BrdIdx, to: BrdIdx, from_occ: Piece) -> Moveable {
|
/// Unwrap the jumpee piece from the square and [`Board::check_jumpee_team`] with [`Moveable`] response
|
||||||
|
pub fn validate_jumpee(jumpee: Square, from_occ: Piece) -> Moveable {
|
||||||
// check whether jumpee is an opponent's piece
|
// check whether jumpee is an opponent's piece
|
||||||
match jumpee.occupant {
|
match jumpee.occupant {
|
||||||
None => panic!("No occupant found when checking the jumpee, from: {}, to: {}, jumpee: {:?}", from, to, jumpee),
|
None => panic!("No occupant found when checking the from: {:?} , jumpee: {:?}", from_occ, jumpee),
|
||||||
Some(jumpee_occupant_uw) => {
|
Some(jumpee_occupant_uw) => {
|
||||||
if Board::check_jumpee_team(from_occ, jumpee_occupant_uw) {
|
if Board::check_jumpee_team(from_occ, jumpee_occupant_uw) {
|
||||||
return Moveable::Allowed;
|
return Moveable::Allowed;
|
||||||
@ -520,13 +588,14 @@ impl Board {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the source piece and the jumpee are of opposing teams
|
||||||
pub fn check_jumpee_team(from: Piece, jumpee: Piece) -> bool {
|
pub fn check_jumpee_team(from: Piece, jumpee: Piece) -> bool {
|
||||||
return from.team.opponent() == jumpee.team
|
return from.team.opponent() == jumpee.team
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iniitalise a game board without game pieces
|
/// Initialise a game board without game pieces
|
||||||
pub fn new(width: usize, height: usize) -> Board {
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new(width: usize, height: usize, current_turn: Team) -> Board {
|
||||||
let total_cells = width * height;
|
let total_cells = width * height;
|
||||||
|
|
||||||
let mut cells: Vec<Square> = Vec::with_capacity(total_cells);
|
let mut cells: Vec<Square> = Vec::with_capacity(total_cells);
|
||||||
@ -535,10 +604,10 @@ impl Board {
|
|||||||
for i in 0..height {
|
for i in 0..height {
|
||||||
for _ in 0..width {
|
for _ in 0..width {
|
||||||
if playable {
|
if playable {
|
||||||
cells.push(Square::new(SquareState::Empty, None));
|
cells.push(Square::new(Empty, None));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cells.push(Square::new(SquareState::Unplayable, None));
|
cells.push(Square::new(Unplayable, None));
|
||||||
}
|
}
|
||||||
playable = !playable;
|
playable = !playable;
|
||||||
}
|
}
|
||||||
@ -550,33 +619,27 @@ impl Board {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
||||||
current_turn: Team::Black
|
current_turn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the given board to a starting layout with 3 rows of opposing pieces
|
/// Reset the given board to a starting layout with 3 rows of opposing pieces
|
||||||
pub fn init_game(board: Board) -> Board {
|
pub fn init_game(board: Board, piece_rows: usize) -> Board {
|
||||||
let mut new_board = board.clone();
|
let mut new_board = board.clone();
|
||||||
for (idx, row) in RowSquareIterator::new(&board).enumerate() {
|
for (idx, row) in RowSquareIterator::new(&board).enumerate() {
|
||||||
for (jdx, square) in row.iter().enumerate() {
|
for (jdx, square) in row.iter().enumerate() {
|
||||||
|
|
||||||
if square.state == SquareState::Empty || square.state == SquareState::Occupied {
|
if square.state == Empty || square.state == Occupied {
|
||||||
if idx < 3 {
|
if idx < piece_rows {
|
||||||
let cell_idx = new_board.cell_index(idx, jdx);
|
let cell_idx = new_board.cell_index(idx, jdx);
|
||||||
new_board.cells[cell_idx] = Square::new(
|
new_board.cells[cell_idx] = Square::pc(White, Man);
|
||||||
SquareState::Occupied,
|
} else if idx >= board.height - piece_rows {
|
||||||
Some(Piece::new(Team::White, Strength::Man))
|
|
||||||
);
|
|
||||||
} else if idx >= board.height - 3 {
|
|
||||||
let cell_idx = new_board.cell_index(idx, jdx);
|
let cell_idx = new_board.cell_index(idx, jdx);
|
||||||
new_board.cells[cell_idx] = Square::new(
|
new_board.cells[cell_idx] = Square::pc(Black, Man);
|
||||||
SquareState::Occupied,
|
|
||||||
Some(Piece::new(Team::Black, Strength::Man))
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
let cell_idx = new_board.cell_index(idx, jdx);
|
let cell_idx = new_board.cell_index(idx, jdx);
|
||||||
new_board.cells[cell_idx] = Square::new(
|
new_board.cells[cell_idx] = Square::new(
|
||||||
SquareState::Empty,
|
Empty,
|
||||||
None
|
None
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -592,6 +655,10 @@ impl Board {
|
|||||||
self.current_turn
|
self.current_turn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_turn(&mut self, new_team: Team) {
|
||||||
|
self.current_turn = new_team;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a pointer to the backing array of board squares, [`Board::cells`]
|
/// Get a pointer to the backing array of board squares, [`Board::cells`]
|
||||||
pub fn cells(&self) -> *const Square {
|
pub fn cells(&self) -> *const Square {
|
||||||
self.cells.as_ptr()
|
self.cells.as_ptr()
|
||||||
@ -602,6 +669,49 @@ impl Board {
|
|||||||
self.cells.len()
|
self.cells.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the number of remaining pieces
|
||||||
|
pub fn num_pieces(&self) -> usize {
|
||||||
|
let pieces: Vec<_> = PieceIterator::new(self).collect();
|
||||||
|
pieces.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the number of remaining pieces for a player
|
||||||
|
pub fn num_player(&self, team: Team) -> usize {
|
||||||
|
let mut total = 0;
|
||||||
|
for (_, square) in PieceIterator::new(self) {
|
||||||
|
match square.occupant {
|
||||||
|
None => {},
|
||||||
|
Some(x) => {
|
||||||
|
if x.team == team {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the score value, Black - White pieces
|
||||||
|
pub fn score(&self) -> isize {
|
||||||
|
let mut black: isize = 0;
|
||||||
|
let mut white: isize = 0;
|
||||||
|
|
||||||
|
for (_, square) in PieceIterator::new(self) {
|
||||||
|
if let Some(x) = square.occupant {
|
||||||
|
match x.team {
|
||||||
|
Black => {
|
||||||
|
black += 1;
|
||||||
|
},
|
||||||
|
White => {
|
||||||
|
white += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
black - white
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the state of a board square by 1D array index
|
/// Get the state of a board square by 1D array index
|
||||||
pub fn cell_state(&self, idx: usize) -> SquareState {
|
pub fn cell_state(&self, idx: usize) -> SquareState {
|
||||||
self.cell(idx).state
|
self.cell(idx).state
|
||||||
@ -617,9 +727,9 @@ impl Display for Board {
|
|||||||
let idx = self.cell_index(i, j);
|
let idx = self.cell_index(i, j);
|
||||||
|
|
||||||
match self.cell_state(idx) {
|
match self.cell_state(idx) {
|
||||||
SquareState::Empty => { write!(string, "{}", SquareState::Empty); },
|
Empty => { write!(string, "_ "); },
|
||||||
SquareState::Occupied => { write!(string, "{}", self.cell(idx).occupant.unwrap().team); },
|
Occupied => { write!(string, "{} ", self.cell(idx).occupant.unwrap().team); },
|
||||||
SquareState::Unplayable => { write!(string, "{}", SquareState::Unplayable); },
|
Unplayable => { write!(string, ". "); },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string.push('\n');
|
string.push('\n');
|
||||||
|
@ -7,47 +7,73 @@ wasm_bindgen_test_configure!(run_in_browser);
|
|||||||
|
|
||||||
// #[wasm_bindgen_test]
|
// #[wasm_bindgen_test]
|
||||||
// fn init_game() {
|
// fn init_game() {
|
||||||
// let board = Board::init_game(Board::new(8, 8));
|
// let board = Board::init_game(Board::new(8, 8, Black), 3);
|
||||||
// log!("{}", board);
|
// log!("{}", board);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn create() {
|
fn create() {
|
||||||
let board = Board::new(STD_WIDTH, STD_HEIGHT);
|
let board = Board::new(STD_WIDTH, STD_HEIGHT, Black);
|
||||||
assert!(true);
|
assert!(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn std_num_cells() {
|
fn std_num_cells() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(64, board.num_cells());
|
assert_eq!(64, board.num_cells());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn idx_diffs() {
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(2, 2);
|
||||||
|
assert_eq!(Board::idx_diffs(from, to), (1, 1));
|
||||||
|
|
||||||
|
let from = BrdIdx::from(2, 2);
|
||||||
|
let to = BrdIdx::from(1, 1);
|
||||||
|
assert_eq!(Board::idx_diffs(from, to), (-1, -1));
|
||||||
|
|
||||||
|
let from = BrdIdx::from(5, 0);
|
||||||
|
let to = BrdIdx::from(0, 10);
|
||||||
|
assert_eq!(Board::idx_diffs(from, to), (-5, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn set_cell() {
|
||||||
|
let idx = 1;
|
||||||
|
|
||||||
|
let mut board = Board::new(8, 8, Black);
|
||||||
|
let square = Square::new(Occupied, Some(Piece::new(White, Man)));
|
||||||
|
|
||||||
|
board.set_cell(idx, square);
|
||||||
|
assert_eq!(square, board.cell(idx));
|
||||||
|
}
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
// INDEXING
|
// INDEXING
|
||||||
//////////////
|
//////////////
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn cell_index_top_left() {
|
fn cell_index_top_left() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(0, board.cell_index(0, 0));
|
assert_eq!(0, board.cell_index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn cell_index_central() {
|
fn cell_index_central() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(9, board.cell_index(1, 1));
|
assert_eq!(9, board.cell_index(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn cell_index_central_2() {
|
fn cell_index_central_2() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(17, board.cell_index(2, 1));
|
assert_eq!(17, board.cell_index(2, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn board_index() {
|
fn board_index() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
|
|
||||||
// first row
|
// first row
|
||||||
assert_eq!(BrdIdx::from(0, 5), board.board_index(5));
|
assert_eq!(BrdIdx::from(0, 5), board.board_index(5));
|
||||||
@ -63,14 +89,14 @@ fn board_index() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn first_square_unplayable() {
|
fn first_square_unplayable() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(SquareState::Unplayable, board.cell_state(board.cell_index(0, 0)));
|
assert_eq!(Unplayable, board.cell_state(board.cell_index(0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn first_square_row_5_unplayable() {
|
fn first_square_row_5_unplayable() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(SquareState::Empty, board.cell_state(board.cell_index(5, 0)));
|
assert_eq!(Empty, board.cell_state(board.cell_index(5, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -79,7 +105,7 @@ fn first_square_row_5_unplayable() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_unplayable() {
|
fn moveable_indices_unplayable() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(None, board.diagonal_indices(BrdIdx::from(7, 7)));
|
assert_eq!(None, board.diagonal_indices(BrdIdx::from(7, 7)));
|
||||||
assert_eq!(None, board.diagonal_indices(BrdIdx::from(0, 0)));
|
assert_eq!(None, board.diagonal_indices(BrdIdx::from(0, 0)));
|
||||||
assert_eq!(None, board.diagonal_indices(BrdIdx::from(1, 1)));
|
assert_eq!(None, board.diagonal_indices(BrdIdx::from(1, 1)));
|
||||||
@ -87,43 +113,43 @@ fn moveable_indices_unplayable() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_central() {
|
fn moveable_indices_central() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![1, 3, 17, 19]), board.diagonal_indices(BrdIdx::from(1, 2)));
|
assert_eq!(Some(vec![1, 3, 17, 19]), board.diagonal_indices(BrdIdx::from(1, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_top_row() {
|
fn moveable_indices_top_row() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![8, 10]), board.diagonal_indices(BrdIdx::from(0, 1)));
|
assert_eq!(Some(vec![8, 10]), board.diagonal_indices(BrdIdx::from(0, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_left_column() {
|
fn moveable_indices_left_column() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![1, 17]), board.diagonal_indices(BrdIdx::from(1, 0)));
|
assert_eq!(Some(vec![1, 17]), board.diagonal_indices(BrdIdx::from(1, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_bottom_row() {
|
fn moveable_indices_bottom_row() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![49, 51]), board.diagonal_indices(BrdIdx::from(7, 2)));
|
assert_eq!(Some(vec![49, 51]), board.diagonal_indices(BrdIdx::from(7, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_right_column() {
|
fn moveable_indices_right_column() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![14, 30]), board.diagonal_indices(BrdIdx::from(2, 7)));
|
assert_eq!(Some(vec![14, 30]), board.diagonal_indices(BrdIdx::from(2, 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_top_right() {
|
fn moveable_indices_top_right() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![14]), board.diagonal_indices(BrdIdx::from(0, 7)));
|
assert_eq!(Some(vec![14]), board.diagonal_indices(BrdIdx::from(0, 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn moveable_indices_bottom_left() {
|
fn moveable_indices_bottom_left() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![49]), board.diagonal_indices(BrdIdx::from(7, 0)));
|
assert_eq!(Some(vec![49]), board.diagonal_indices(BrdIdx::from(7, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +159,7 @@ fn moveable_indices_bottom_left() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_unplayable() {
|
fn jumpable_indices_unplayable() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(None, board.jumpable_indices(BrdIdx::from(7, 7)));
|
assert_eq!(None, board.jumpable_indices(BrdIdx::from(7, 7)));
|
||||||
assert_eq!(None, board.jumpable_indices(BrdIdx::from(0, 0)));
|
assert_eq!(None, board.jumpable_indices(BrdIdx::from(0, 0)));
|
||||||
assert_eq!(None, board.jumpable_indices(BrdIdx::from(1, 1)));
|
assert_eq!(None, board.jumpable_indices(BrdIdx::from(1, 1)));
|
||||||
@ -141,70 +167,320 @@ fn jumpable_indices_unplayable() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices() {
|
fn jumpable_indices() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![24, 28]), board.jumpable_indices(BrdIdx::from(1, 2)));
|
assert_eq!(Some(vec![24, 28]), board.jumpable_indices(BrdIdx::from(1, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_central() {
|
fn jumpable_indices_central() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![10, 14, 42, 46]), board.jumpable_indices(BrdIdx::from(3, 4)));
|
assert_eq!(Some(vec![10, 14, 42, 46]), board.jumpable_indices(BrdIdx::from(3, 4)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_top_row() {
|
fn jumpable_indices_top_row() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![19]), board.jumpable_indices(BrdIdx::from(0, 1)));
|
assert_eq!(Some(vec![19]), board.jumpable_indices(BrdIdx::from(0, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_left_column() {
|
fn jumpable_indices_left_column() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![26]), board.jumpable_indices(BrdIdx::from(1, 0)));
|
assert_eq!(Some(vec![26]), board.jumpable_indices(BrdIdx::from(1, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_bottom_row() {
|
fn jumpable_indices_bottom_row() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![40, 44]), board.jumpable_indices(BrdIdx::from(7, 2)));
|
assert_eq!(Some(vec![40, 44]), board.jumpable_indices(BrdIdx::from(7, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_right_column() {
|
fn jumpable_indices_right_column() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![5, 37]), board.jumpable_indices(BrdIdx::from(2, 7)));
|
assert_eq!(Some(vec![5, 37]), board.jumpable_indices(BrdIdx::from(2, 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_top_right() {
|
fn jumpable_indices_top_right() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![21]), board.jumpable_indices(BrdIdx::from(0, 7)));
|
assert_eq!(Some(vec![21]), board.jumpable_indices(BrdIdx::from(0, 7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn jumpable_indices_bottom_left() {
|
fn jumpable_indices_bottom_left() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![42]), board.jumpable_indices(BrdIdx::from(7, 0)));
|
assert_eq!(Some(vec![42]), board.jumpable_indices(BrdIdx::from(7, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn black_diagonal_indices() {
|
fn black_diagonal_indices() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![1, 3]), board.player_diagonal_indices(BrdIdx::from(1, 2), Team::Black));
|
assert_eq!(Some(vec![1, 3]), board.player_diagonal_indices(BrdIdx::from(1, 2), Black));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn white_diagonal_indices() {
|
fn white_diagonal_indices() {
|
||||||
let board = Board::new(8, 8);
|
let board = Board::new(8, 8, Black);
|
||||||
assert_eq!(Some(vec![17, 19]), board.player_diagonal_indices(BrdIdx::from(1, 2), Team::White));
|
assert_eq!(Some(vec![17, 19]), board.player_diagonal_indices(BrdIdx::from(1, 2), White));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// JUMPEE
|
// JUMPEE
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
// #[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
// fn check_jumpee() {
|
fn check_jumpee_opposing_teams() {
|
||||||
// let from =
|
let from = Piece::new(Black, Man);
|
||||||
// assert_eq!(Board::check_jumpee_team(from: Piece, jumpee: Piece));
|
let jumpee = Piece::new(White, Man);
|
||||||
// }
|
assert_eq!(Board::check_jumpee_team(from, jumpee), true);
|
||||||
|
|
||||||
|
let from = Piece::new(White, Man);
|
||||||
|
let jumpee = Piece::new(Black, Man);
|
||||||
|
assert_eq!(Board::check_jumpee_team(from, jumpee), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn check_jumpee_same_teams() {
|
||||||
|
let from = Piece::new(Black, Man);
|
||||||
|
let jumpee = Piece::new(Black, Man);
|
||||||
|
assert_eq!(Board::check_jumpee_team(from, jumpee), false);
|
||||||
|
|
||||||
|
let from = Piece::new(White, Man);
|
||||||
|
let jumpee = Piece::new(White, Man);
|
||||||
|
assert_eq!(Board::check_jumpee_team(from, jumpee), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn check_validate_jumpee_opposing_teams() {
|
||||||
|
let jumpee_square = Square::new(
|
||||||
|
Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(White, Man)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let from_piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Board::validate_jumpee(jumpee_square, from_piece), Moveable::Allowed);
|
||||||
|
|
||||||
|
let jumpee_square = Square::new(
|
||||||
|
Occupied,
|
||||||
|
Some(
|
||||||
|
Piece::new(Black, Man)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let from_piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Board::validate_jumpee(jumpee_square, from_piece), Moveable::Allowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn check_validate_jumpee_same_teams() {
|
||||||
|
let jumpee_square = Square::pc(White, Man);
|
||||||
|
let from_piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Board::validate_jumpee(jumpee_square, from_piece), Moveable::JumpingSameTeam);
|
||||||
|
|
||||||
|
let jumpee_square = Square::pc(Black, Man);
|
||||||
|
let from_piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Board::validate_jumpee(jumpee_square, from_piece), Moveable::JumpingSameTeam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// SCORE
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn score() {
|
||||||
|
//////////////////////////////////
|
||||||
|
let board = Board::new(8, 8, Black);
|
||||||
|
assert_eq!(0, board.score());
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
let mut board = Board::new(8, 8, Black);
|
||||||
|
let square = Square::pc(Black, Man);
|
||||||
|
board.set_cell(1, square);
|
||||||
|
assert_eq!(1, board.score());
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
let square = Square::pc(White, Man);
|
||||||
|
board.set_cell(5, square);
|
||||||
|
let square = Square::pc(Black, Man);
|
||||||
|
board.set_cell(7, square);
|
||||||
|
let square = Square::pc(Black, Man);
|
||||||
|
board.set_cell(8, square);
|
||||||
|
assert_eq!(2, board.score());
|
||||||
|
//////////////////////////////////
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// MOVE VALIDATION
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn validate_man_move_team_directions() {
|
||||||
|
// WHITE NEEDS INCREASING IDX
|
||||||
|
|
||||||
|
// allowed, white moves down board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(2, 2);
|
||||||
|
let piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::Allowed, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// unallowed, white moves up board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let from = BrdIdx::from(2, 2);
|
||||||
|
let to = BrdIdx::from(1, 1);
|
||||||
|
let piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// allowed, black moves up board
|
||||||
|
let board = Board::new(8, 8, Black);
|
||||||
|
let from = BrdIdx::from(2, 2);
|
||||||
|
let to = BrdIdx::from(1, 1);
|
||||||
|
let piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::Allowed, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// unallowed, black moves down board
|
||||||
|
let board = Board::new(8, 8, Black);
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(2, 2);
|
||||||
|
let piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn validate_man_move_weird_trajectories() {
|
||||||
|
// WHITE NEEDS INCREASING IDX
|
||||||
|
|
||||||
|
// allowed, white moves down board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(3, 2);
|
||||||
|
let piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// unallowed, white moves up board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let from = BrdIdx::from(2, 3);
|
||||||
|
let to = BrdIdx::from(1, 1);
|
||||||
|
let piece = Piece::new(White, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// allowed, black moves up board
|
||||||
|
let board = Board::new(8, 8, Black);
|
||||||
|
let from = BrdIdx::from(5, 2);
|
||||||
|
let to = BrdIdx::from(1, 1);
|
||||||
|
let piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
|
||||||
|
// unallowed, black moves down board
|
||||||
|
let board = Board::new(8, 8, Black);
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(2, 4);
|
||||||
|
let piece = Piece::new(Black, Man);
|
||||||
|
|
||||||
|
assert_eq!(Moveable::IllegalTrajectory, board.validate_man_move(from, to, piece));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn can_move() {
|
||||||
|
// WHITE NEEDS INCREASING IDX
|
||||||
|
|
||||||
|
// allowed, white moves down board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let mut board = Board::init_game(board, 3);
|
||||||
|
|
||||||
|
// log!("{}", board);
|
||||||
|
|
||||||
|
// white can move down
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(3, 0);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::Allowed);
|
||||||
|
|
||||||
|
// going straight down
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(3, 1);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::IllegalTrajectory);
|
||||||
|
|
||||||
|
// going directly right
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(2, 2);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::IllegalTrajectory);
|
||||||
|
|
||||||
|
// jumping an empty square
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::NoJumpablePiece);
|
||||||
|
|
||||||
|
// empty cell
|
||||||
|
let from = BrdIdx::from(3, 0);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::UnoccupiedSrc);
|
||||||
|
|
||||||
|
// out of board
|
||||||
|
let from = BrdIdx::from(50, 50);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::OutOfBounds);
|
||||||
|
let from = BrdIdx::from(5, 5);
|
||||||
|
let to = BrdIdx::from(50, 50);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::OutOfBounds);
|
||||||
|
|
||||||
|
// unplayable
|
||||||
|
let from = BrdIdx::from(0, 0);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::Unplayable);
|
||||||
|
let from = BrdIdx::from(1, 1);
|
||||||
|
let to = BrdIdx::from(0, 0);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::Unplayable);
|
||||||
|
|
||||||
|
board.set_turn(Black);
|
||||||
|
|
||||||
|
// wrong teams piece
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::WrongTeamSrc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn can_move_jump() {
|
||||||
|
// WHITE NEEDS INCREASING IDX
|
||||||
|
|
||||||
|
// allowed, white moves down board
|
||||||
|
let board = Board::new(8, 8, White);
|
||||||
|
let mut board = Board::init_game(board, 3);
|
||||||
|
|
||||||
|
board.set_cell(board.cell_index(3, 2), Square::pc(Black, Man));
|
||||||
|
|
||||||
|
// log!("{}", board);
|
||||||
|
// log!("{:?}", board.cell(board.cell_index(3, 2)));
|
||||||
|
|
||||||
|
// white can move down
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::Allowed);
|
||||||
|
|
||||||
|
board.set_cell(board.cell_index(3, 2), Square::pc(White, Man));
|
||||||
|
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(4, 3);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::JumpingSameTeam);
|
||||||
|
|
||||||
|
// moving in to full cell
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(3, 2);
|
||||||
|
assert_eq!(board.can_move(from, to), Moveable::OccupiedDest);
|
||||||
|
|
||||||
|
}
|
13
src/game.rs
13
src/game.rs
@ -1,13 +0,0 @@
|
|||||||
use crate::board::Board;
|
|
||||||
use indextree::Arena;
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
|
||||||
use wasm_bindgen::prelude::*;
|
|
||||||
|
|
||||||
/// Root-level structure for managing the game as a collection of board states
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct Game {
|
|
||||||
current: Board,
|
|
||||||
previous_boards: Vec<Board>,
|
|
||||||
tree: Arena<Board>
|
|
||||||
}
|
|
142
src/game/mod.rs
Normal file
142
src/game/mod.rs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
use crate::board::Board;
|
||||||
|
use indextree::Arena;
|
||||||
|
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
use crate::log;
|
||||||
|
|
||||||
|
use crate::board::{Square, BrdIdx};
|
||||||
|
use crate::board::enums::{SquareState, Moveable, Team};
|
||||||
|
|
||||||
|
use Team::*;
|
||||||
|
use SquareState::*;
|
||||||
|
|
||||||
|
use std::fmt::{Display, Write};
|
||||||
|
|
||||||
|
#[cfg(test)] pub mod tests;
|
||||||
|
|
||||||
|
/// Root-level structure for managing the game as a collection of board states
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Game {
|
||||||
|
current: Board,
|
||||||
|
previous_boards: Vec<Board>,
|
||||||
|
// tree: Arena<Board>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
/// Get a read-only copy of a previous turn's board
|
||||||
|
pub fn previous_board(&self, turn: usize) -> &Board {
|
||||||
|
&self.previous_boards[turn]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set current board to given
|
||||||
|
pub fn current_board(&self) -> &Board {
|
||||||
|
&self.current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Game {
|
||||||
|
/// Attempt to make a move given a source and destination index
|
||||||
|
pub fn make_move(&mut self, from: BrdIdx, to: BrdIdx) {
|
||||||
|
let able = self.current.can_move(from, to);
|
||||||
|
|
||||||
|
if let Moveable::Allowed = able {
|
||||||
|
let (_, col_diff) = Board::idx_diffs(from, to);
|
||||||
|
// MOVE
|
||||||
|
if col_diff.abs() == 1 {
|
||||||
|
self.execute_move(from, to);
|
||||||
|
}
|
||||||
|
// JUMP
|
||||||
|
else {
|
||||||
|
self.execute_jump(from, to);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log!("Unable to make move, {:?}", able);
|
||||||
|
}
|
||||||
|
|
||||||
|
// board has been changed, update player turn
|
||||||
|
self.current.set_turn(self.current.current_turn().opponent());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update board state with given move and push new board into current state
|
||||||
|
pub fn execute_move(&mut self, from: BrdIdx, to: BrdIdx) {
|
||||||
|
let mut new_board = self.current.clone();
|
||||||
|
|
||||||
|
let from_idx = self.current.cell_idx(from);
|
||||||
|
let to_idx = self.current.cell_idx(to);
|
||||||
|
|
||||||
|
// make move update
|
||||||
|
new_board.set_cell(
|
||||||
|
to_idx, // destination square
|
||||||
|
self.current.cell(from_idx) // source piece
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove old piece
|
||||||
|
new_board.set_cell(
|
||||||
|
from_idx, // destination square
|
||||||
|
Square::empty() // empty piece
|
||||||
|
);
|
||||||
|
|
||||||
|
// set new board to current and push current to stack
|
||||||
|
self.push_new_board(new_board);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update board state with given jump move and push new board into current state
|
||||||
|
pub fn execute_jump(&mut self, from: BrdIdx, to: BrdIdx) {
|
||||||
|
let mut new_board = self.current.clone();
|
||||||
|
|
||||||
|
let from_idx = self.current.cell_idx(from);
|
||||||
|
let to_idx = self.current.cell_idx(from);
|
||||||
|
|
||||||
|
// make move update
|
||||||
|
new_board.set_cell(
|
||||||
|
to_idx, // destination square
|
||||||
|
self.current.cell(from_idx) // source piece
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove old piece
|
||||||
|
new_board.set_cell(
|
||||||
|
from_idx, // destination square
|
||||||
|
Square::empty() // empty piece
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove jumpee
|
||||||
|
new_board.set_cell(
|
||||||
|
self.current.jumpee_idx(from, to), // destination square
|
||||||
|
Square::empty() // empty piece
|
||||||
|
);
|
||||||
|
|
||||||
|
// set new board to current and push current to stack
|
||||||
|
self.push_new_board(new_board);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push current board into the previous turns and set given board to current
|
||||||
|
pub fn push_new_board(&mut self, board: Board) {
|
||||||
|
self.previous_boards.push(self.current.clone());
|
||||||
|
self.set_current(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set current board to given
|
||||||
|
pub fn set_current(&mut self, board: Board) {
|
||||||
|
self.current = board;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn new(width: usize, height: usize, piece_rows: usize, first_turn: Team) -> Game {
|
||||||
|
Game {
|
||||||
|
current: Board::init_game(
|
||||||
|
Board::new(width, height, first_turn), piece_rows,
|
||||||
|
),
|
||||||
|
previous_boards: Vec::with_capacity(10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Game {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result{
|
||||||
|
write!(f, "{}", self.current)
|
||||||
|
}
|
||||||
|
}
|
59
src/game/tests.rs
Normal file
59
src/game/tests.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use super::*;
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
use crate::log;
|
||||||
|
|
||||||
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
|
use crate::board::{Piece};
|
||||||
|
use crate::board::enums::Strength::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn make_move() {
|
||||||
|
let mut game = Game::new(8, 8, 3, Black);
|
||||||
|
log!("{}", game);
|
||||||
|
// log!("{:?}", game);
|
||||||
|
|
||||||
|
let from = BrdIdx::from(5, 2);
|
||||||
|
let to = BrdIdx::from(4, 1);
|
||||||
|
|
||||||
|
game.make_move(from, to);
|
||||||
|
let board = game.current_board();
|
||||||
|
|
||||||
|
assert_eq!(board.cell(board.cell_index(4, 1)), Square::pc(Black, Man));
|
||||||
|
|
||||||
|
log!("{}", game);
|
||||||
|
|
||||||
|
let from = BrdIdx::from(2, 1);
|
||||||
|
let to = BrdIdx::from(3, 2);
|
||||||
|
|
||||||
|
game.make_move(from, to);
|
||||||
|
let board = game.current_board();
|
||||||
|
|
||||||
|
assert_eq!(board.cell(board.cell_index(3, 2)), Square::pc(White, Man));
|
||||||
|
|
||||||
|
log!("{}", game);
|
||||||
|
// log!("{}", game.previous_board(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn make_jump() {
|
||||||
|
let mut game = Game::new(8, 8, 3, Black);
|
||||||
|
// log!("{}", game);
|
||||||
|
// log!("{:?}", game);
|
||||||
|
|
||||||
|
let square = Square::pc(White, Man);
|
||||||
|
game.current.set_cell(
|
||||||
|
game.current.cell_idx(BrdIdx::from(4, 1)),
|
||||||
|
square
|
||||||
|
);
|
||||||
|
|
||||||
|
let from = BrdIdx::from(5, 2);
|
||||||
|
let to = BrdIdx::from(3, 0);
|
||||||
|
|
||||||
|
game.make_move(from, to);
|
||||||
|
|
||||||
|
// log!("{}", game);
|
||||||
|
// log!("{}", game.previous_board(0));
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
|||||||
pub mod board;
|
pub mod board;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
|
pub mod player;
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
8
src/player.rs
Normal file
8
src/player.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
extern crate wasm_bindgen;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Player {
|
||||||
|
score: usize,
|
||||||
|
}
|
3
www/package-lock.json
generated
3
www/package-lock.json
generated
@ -14,7 +14,8 @@
|
|||||||
"copy-webpack-plugin": "^9.0.0",
|
"copy-webpack-plugin": "^9.0.0",
|
||||||
"webpack": "^5.40.0",
|
"webpack": "^5.40.0",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.7.2",
|
||||||
"webpack-dev-server": "^3.11.2"
|
"webpack-dev-server": "^3.11.2",
|
||||||
|
"webpack-merge": "^5.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"../pkg": {
|
"../pkg": {
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
"description": "Rust wasm-based checkers game",
|
"description": "Rust wasm-based checkers game",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.prod.js --env production",
|
||||||
"start": "webpack serve --config webpack.config.js --progress"
|
"devbuild": "webpack --config webpack.dev.js",
|
||||||
|
"start": "webpack serve --config webpack.dev.js --progress"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -29,6 +30,7 @@
|
|||||||
"copy-webpack-plugin": "^9.0.0",
|
"copy-webpack-plugin": "^9.0.0",
|
||||||
"webpack": "^5.40.0",
|
"webpack": "^5.40.0",
|
||||||
"webpack-cli": "^4.7.2",
|
"webpack-cli": "^4.7.2",
|
||||||
"webpack-dev-server": "^3.11.2"
|
"webpack-dev-server": "^3.11.2",
|
||||||
|
"webpack-merge": "^5.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ module.exports = {
|
|||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
filename: "bootstrap.js",
|
filename: "bootstrap.js",
|
||||||
},
|
},
|
||||||
mode: "development",
|
|
||||||
experiments: {
|
experiments: {
|
||||||
asyncWebAssembly: true
|
asyncWebAssembly: true
|
||||||
},
|
},
|
8
www/webpack.dev.js
Normal file
8
www/webpack.dev.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: 'inline-source-map',
|
||||||
|
watch: true
|
||||||
|
});
|
7
www/webpack.prod.js
Normal file
7
www/webpack.prod.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const { merge } = require('webpack-merge');
|
||||||
|
const common = require('./webpack.common.js');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'production',
|
||||||
|
devtool: 'source-map'
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user