From 6d2eb8ab0a62bb0ffa676920c36a6e9e38ccb0e1 Mon Sep 17 00:00:00 2001 From: andy Date: Sat, 10 Jul 2021 23:54:05 +0100 Subject: [PATCH] added selected highlighting, king checking --- src/board/mod.rs | 45 ++++++++++++++++++++++++++++++++---- src/comp/mod.rs | 38 +++++++++++------------------- src/comp/tests.rs | 33 ++++++++++++++++++++------ src/game/mod.rs | 32 +++++++++++++++++++++++-- src/paint.rs | 47 ++++++++++++++++++++++++++++++++++++- www/index.html | 10 ++++---- www/index.js | 59 +++++++++++++++++++++++++---------------------- 7 files changed, 195 insertions(+), 69 deletions(-) diff --git a/src/board/mod.rs b/src/board/mod.rs index 62c9d71..0ff34cd 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -581,6 +581,7 @@ impl Board { } } + /// Get cell index of jumpee square given from and to locations pub fn jumpee_idx(&self, from: BrdIdx, to: BrdIdx) -> usize { let (row_diff, col_diff) = Board::idx_diffs(from, to); self.cell_idx( @@ -628,13 +629,20 @@ impl Board { let mut white: isize = 0; for (_, square) in PieceIterator::new(self) { - if let Some(x) = square.occupant { - match x.team { + if let Some(piece) = square.occupant { + + // kings are move valuable than men + let increment = match piece.strength { + Man => 1, + King => 2, + }; + + match piece.team { Black => { - black += 1; + black += increment; }, White => { - white += 1; + white += increment; }, } } @@ -648,6 +656,7 @@ impl Board { self.cell(idx).state } + /// Get new board derived from current with given move applied pub fn apply_move(&self, from: BrdIdx, to: BrdIdx) -> Board { let mut new = self.clone(); @@ -666,9 +675,12 @@ impl Board { Square::empty() // empty piece ); + Board::check_kinged(&mut new, to); + new } + /// Get new board derived from current with given jump applied pub fn apply_jump(&self, from: BrdIdx, to: BrdIdx) -> Board { let mut new = self.clone(); @@ -693,9 +705,18 @@ impl Board { Square::empty() // empty piece ); + Board::check_kinged(&mut new, to); new } + + /// Get row index for current team, top row for black, bottom row for white + pub fn king_row_idx(&self) -> usize { + match self.current_turn { + White => self.height - 1, + Black => 0, + } + } } ///////////////////////// @@ -725,6 +746,22 @@ impl Board { return from.team.opponent() == jumpee.team } + /// Check and apply king strength + fn check_kinged(new_board: &mut Board, idx: BrdIdx) { + if new_board.king_row_idx() == idx.row { + let cell_idx = new_board.cell_idx(idx); + let cell = new_board.cell(cell_idx); + match cell.occupant { + Some(piece) => { + new_board.set_cell(cell_idx, Square::pc(piece.team, King)); + }, + None => { + panic!("No piece found when checking king, idx: {}", idx); + }, + } + } + } + /// Initialise a game board without game pieces #[wasm_bindgen(constructor)] pub fn new(width: usize, height: usize, current_turn: Team) -> Board { diff --git a/src/comp/mod.rs b/src/comp/mod.rs index 7fd81c4..861b2e7 100644 --- a/src/comp/mod.rs +++ b/src/comp/mod.rs @@ -37,7 +37,6 @@ impl Move { /// Root-level structure for managing the game as a collection of board states #[derive(Debug)] pub struct Computer { - pub tree: Arena, pub root_node_id: NodeId, pub search_depth: usize, pub team: Team, @@ -48,19 +47,13 @@ impl Computer { let mut tree = Arena::new(); let root_node_id = tree.new_node(initial_board); Computer { - tree, root_node_id, search_depth, team } } - pub fn update_board(&mut self, new_board: Board) { - let mut tree = Arena::new(); - tree.new_node(new_board); - self.tree = tree; - } - + /// Get vector of available moves for a given board pub fn available_turns(&self, board: &Board) -> Vec { // allocate capacity for 2 moves per piece, likely too much but will be shrunk @@ -94,7 +87,7 @@ impl Computer { panic!("Unable to unwrap adjacent indices, from: {}, brd: {}", from_brd_idx, board); } - // iterate over adjacent indices + // iterate over jumpable indices if let Some(jump) = jump_op { for i in jump { let to_brd_idx = board.board_index(i); @@ -116,29 +109,26 @@ impl Computer { moves } - // pub fn gen_tree(&mut self, tree: &mut Arena, board: Board) { + pub fn gen_tree(&mut self, tree: &mut Arena, board: Board) { - // let boards = self.get_move_boards(&board); + // possible boards from given + let boards = self.get_move_boards(&board); - // let root_id = vec!(tree.new_node(board)); - // let ids = self.insert_boards(boards); + // root node of tree + let root = tree.new_node(board); - // for d in 0..self.search_depth { + // insert possible boards + let ids = self.insert_boards(tree, boards); + // append ids to root node + ids.iter().for_each( |id| root.append(*id, tree) ); - // for root in root_id.iter(){ - // for id in ids.into_iter() { - // root.append(id, tree); - // } - // } - // } + } - // } - - pub fn insert_boards(&mut self, boards: Vec) -> Vec { + pub fn insert_boards(&mut self, tree: &mut Arena, boards: Vec) -> Vec { boards .into_iter().map( - |b| self.tree.new_node(b) + |b| tree.new_node(b) ).collect() } diff --git a/src/comp/tests.rs b/src/comp/tests.rs index 244cb89..73c0eec 100644 --- a/src/comp/tests.rs +++ b/src/comp/tests.rs @@ -3,19 +3,20 @@ use wasm_bindgen_test::*; use crate::board::Square; use crate::board::enums::Strength::*; +use crate::log; use Team::*; wasm_bindgen_test_configure!(run_in_browser); -#[wasm_bindgen_test] -fn initial_tree_size() { - let brd = Board::new(3, 2, White); - let comp = Computer::new(brd, 3, White); +// #[wasm_bindgen_test] +// fn initial_tree_size() { +// let brd = Board::new(3, 2, White); +// let comp = Computer::new(brd, 3, White); - assert!(!comp.tree.is_empty()); - assert_eq!(comp.tree.count(), 1); -} +// assert!(!comp.tree.is_empty()); +// assert_eq!(comp.tree.count(), 1); +// } #[wasm_bindgen_test] fn available_moves() { @@ -84,3 +85,21 @@ fn available_moves_std_brd() { assert_eq!(moves.len(), 7); assert!(moves.into_iter().all(|m| m.mv_type == MoveType::Move)); } + +#[wasm_bindgen_test] +fn tree_insert() { + let brd = Board::init_game(Board::new(8, 8, White), 3); + let brd2 = brd.clone(); + let mut comp = Computer::new(brd, 3, White); + + // log!("{}", brd2); + + let moves = comp.available_turns(&brd2); + log!("{}", moves.len()); + + let mut tree = Arena::new(); + comp.gen_tree(&mut tree, brd2); + + log!("{}", tree.count()); +} + diff --git a/src/game/mod.rs b/src/game/mod.rs index 026e620..3124c6a 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -8,11 +8,11 @@ use wasm_bindgen::prelude::*; use crate::log; use crate::board::{Square, BrdIdx}; -use crate::board::enums::{Moveable, Team}; +use crate::board::enums::{SquareState, Moveable, Team}; use crate::paint::Painter; // use Team::*; -// use SquareState::*; +use SquareState::*; use std::fmt::{Display}; @@ -23,6 +23,7 @@ use std::fmt::{Display}; #[derive(Debug)] pub struct Game { current: Board, + selected_piece: Option, previous_boards: Vec, painter: Option } @@ -56,10 +57,35 @@ impl Game { self.current.current_turn } + /// Get square on current board for given index pub fn current_cell_state(&self, idx: &BrdIdx) -> Square { self.current.cell(self.current.cell_idx(*idx)) } + /// Set given index as selected piece + /// TODO: Check whether valid square? + pub fn set_selected(&mut self, idx: &BrdIdx) { + + if self.current.cell(self.current.cell_idx(*idx)).state != Occupied { + panic!("Tried to select an unoccupied or empty square"); + } + + self.selected_piece = Some(*idx); + match &mut self.painter { + Some(p) => p.set_selected(&Some(*idx)), + None => {}, + } + } + + /// Clear currently selected piece + pub fn clear_selected(&mut self) { + self.selected_piece = None; + match &mut self.painter { + Some(p) => p.set_selected(&None), + None => {}, + } + } + /// Attempt to make a move given a source and destination index pub fn make_move(&mut self, from: BrdIdx, to: BrdIdx) -> Moveable { let able = self.current.can_move(from, to); @@ -114,6 +140,7 @@ impl Game { current: Board::init_game( Board::new(width, height, first_turn), piece_rows, ), + selected_piece: None, previous_boards: Vec::with_capacity(10), painter: None, } @@ -124,6 +151,7 @@ impl Game { current: Board::init_game( Board::new(width, height, first_turn), piece_rows, ), + selected_piece: None, previous_boards: Vec::with_capacity(10), painter: Some( Painter::new(canvas_width, canvas_height, canvas_id) diff --git a/src/paint.rs b/src/paint.rs index e548b74..f46d212 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -10,7 +10,7 @@ use web_sys::CanvasRenderingContext2d; use std::f64; use crate::log; -use crate::board::{Board}; +use crate::board::{Board, BrdIdx}; use crate::board::iter::PieceIterator; use crate::board::enums::Team::*; @@ -32,11 +32,16 @@ const DRAW_OUTLINE: bool = true; const WHITE_PIECE: &str = "#dbdbdb"; /// Default hex colour value for black pieces const BLACK_PIECE: &str = "#ed0000"; +/// Default hex colour value for selected piece +const SELECTED_PIECE: &str = "#fffd78"; /// Default hex colour value for white piece outline const WHITE_PIECE_OUTLINE: &str = "#9c9c9c"; /// Default hex colour value for black piece outline const BLACK_PIECE_OUTLINE: &str = "#a60000"; +/// Default hex colour value for selected piece outline +// const SELECTED_PIECE_OUTLINE: &str = "#dedc73"; +const SELECTED_PIECE_OUTLINE: &str = "#d1cf45"; /// Default hex colour value for black piece outline const KING_OUTLINE: &str = "#ffea00"; /// Whether to outline pieces @@ -53,15 +58,18 @@ const PIECE_MARGIN: f64 = 10.0; pub struct Painter { canvas: HtmlCanvasElement, context: CanvasRenderingContext2d, + selected_idx: Option, white_square: JsValue, black_square: JsValue, white_piece: JsValue, black_piece: JsValue, + selected_piece: JsValue, white_piece_line: JsValue, black_piece_line: JsValue, + selected_piece_line: JsValue, king_line: JsValue, piece_lines: bool, @@ -76,6 +84,11 @@ pub struct Painter { } impl Painter { + /// Set selected piece by board index + pub fn set_selected(&mut self, idx: &Option) { + self.selected_idx = *idx; + } + /// Get a canvas by element ID fn get_canvas(canvas_id: &str) -> HtmlCanvasElement { // JS WINDOW @@ -142,15 +155,18 @@ impl Painter { canvas, context, width, height, + selected_idx: None, white_square: JsValue::from_str(WHITE_SQUARE), black_square: JsValue::from_str(BLACK_SQUARE), white_piece: JsValue::from_str(WHITE_PIECE), black_piece: JsValue::from_str(BLACK_PIECE), + selected_piece: JsValue::from_str(SELECTED_PIECE), white_piece_line: JsValue::from_str(WHITE_PIECE_OUTLINE), black_piece_line: JsValue::from_str(BLACK_PIECE_OUTLINE), + selected_piece_line: JsValue::from_str(SELECTED_PIECE_OUTLINE), king_line: JsValue::from_str(KING_OUTLINE), piece_lines: DRAW_PIECE_OUTLINES, piece_line_width: PIECE_OUTLINE_WIDTH, @@ -172,15 +188,18 @@ impl Painter { canvas, context, width, height, + selected_idx: None, white_square: JsValue::from_str(WHITE_SQUARE), black_square: JsValue::from_str(BLACK_SQUARE), white_piece: JsValue::from_str(WHITE_PIECE), black_piece: JsValue::from_str(BLACK_PIECE), + selected_piece: JsValue::from_str(SELECTED_PIECE), white_piece_line: JsValue::from_str(WHITE_PIECE_OUTLINE), black_piece_line: JsValue::from_str(BLACK_PIECE_OUTLINE), + selected_piece_line: JsValue::from_str(SELECTED_PIECE_OUTLINE), king_line: JsValue::from_str(KING_OUTLINE), piece_lines: DRAW_PIECE_OUTLINES, piece_line_width: PIECE_OUTLINE_WIDTH, @@ -336,5 +355,31 @@ impl Painter { None => panic!("No piece found when attempting to draw, idx: {}, square: {:?}", idx, square), } } + + if let Some(selected_idx) = self.selected_idx { + self.context.set_fill_style(&self.selected_piece); + self.context.set_stroke_style(&self.selected_piece_line); + + let center_x: f64 = (selected_idx.col as f64 * cell_width as f64) + (cell_width as f64) / 2.0; + let center_y: f64 = (selected_idx.row as f64 * cell_height as f64) + (cell_height as f64) / 2.0; + + self.context.begin_path(); + match self.context.arc( + center_x, + center_y, + (cell_width as f64 / 2.0) - PIECE_MARGIN, // radius + 0.0, // start angle + f64::consts::PI * 2.0) // end angle + { + Ok(res) => res, + Err(err) => log!("Failed to paint selected piece, idx: {}, {:?}", selected_idx, err), + }; + self.context.fill(); + + if self.piece_lines { + self.context.set_line_width(self.piece_line_width); + self.context.stroke() + } + } } } \ No newline at end of file diff --git a/www/index.html b/www/index.html index b725555..6ce688b 100644 --- a/www/index.html +++ b/www/index.html @@ -41,16 +41,18 @@
- Docs - + Docs +
-
+

-
+
+
+