Impl use of win/draw check, fixes
Also added unit tests for win/draw checks.
This commit is contained in:
parent
9e9bb0758c
commit
b902b1c7b4
5 changed files with 396 additions and 146 deletions
|
@ -14,8 +14,8 @@ pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_empty_slot {
|
if !has_empty_slot {
|
||||||
return None;
|
return Some(BoardState::Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let check_result = |state| -> Option<BoardState> {
|
let check_result = |state| -> Option<BoardState> {
|
||||||
|
@ -130,3 +130,200 @@ fn has_right_down_diagonal_at_idx(idx: usize, board: &BoardType) -> BoardState {
|
||||||
}
|
}
|
||||||
BoardState::Empty
|
BoardState::Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::state::{new_empty_board, BoardState};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_horizontal_check() {
|
||||||
|
let board = new_empty_board();
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_horizontal_at_idx(x + y * (COLS as usize), &board),
|
||||||
|
BoardState::Empty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[50].replace(BoardState::Cyan);
|
||||||
|
board[51].replace(BoardState::Cyan);
|
||||||
|
board[52].replace(BoardState::Cyan);
|
||||||
|
board[53].replace(BoardState::Cyan);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 50 {
|
||||||
|
assert_eq!(has_right_horizontal_at_idx(idx, &board), BoardState::Cyan);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_right_horizontal_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[51].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
board[43].replace(BoardState::Magenta);
|
||||||
|
board[44].replace(BoardState::Magenta);
|
||||||
|
board[45].replace(BoardState::Magenta);
|
||||||
|
board[46].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 43 {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_horizontal_at_idx(idx, &board),
|
||||||
|
BoardState::Magenta
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_right_horizontal_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vertical_check() {
|
||||||
|
let board = new_empty_board();
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
assert_eq!(
|
||||||
|
has_down_vertical_at_idx(x + y * (COLS as usize), &board),
|
||||||
|
BoardState::Empty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[30].replace(BoardState::Cyan);
|
||||||
|
board[37].replace(BoardState::Cyan);
|
||||||
|
board[44].replace(BoardState::Cyan);
|
||||||
|
board[51].replace(BoardState::Cyan);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 30 {
|
||||||
|
assert_eq!(has_down_vertical_at_idx(idx, &board), BoardState::Cyan);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_down_vertical_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[16].replace(BoardState::Magenta);
|
||||||
|
board[23].replace(BoardState::Magenta);
|
||||||
|
board[30].replace(BoardState::Magenta);
|
||||||
|
board[37].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 16 {
|
||||||
|
assert_eq!(has_down_vertical_at_idx(idx, &board), BoardState::Magenta);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_down_vertical_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_upper_diagonal_check() {
|
||||||
|
let board = new_empty_board();
|
||||||
|
|
||||||
|
board[44].replace(BoardState::Cyan);
|
||||||
|
board[38].replace(BoardState::Cyan);
|
||||||
|
board[32].replace(BoardState::Cyan);
|
||||||
|
board[26].replace(BoardState::Cyan);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 44 {
|
||||||
|
assert_eq!(has_right_up_diagonal_at_idx(idx, &board), BoardState::Cyan);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_right_up_diagonal_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[38].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
board[28].replace(BoardState::Magenta);
|
||||||
|
board[22].replace(BoardState::Magenta);
|
||||||
|
board[16].replace(BoardState::Magenta);
|
||||||
|
board[10].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 28 {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_up_diagonal_at_idx(idx, &board),
|
||||||
|
BoardState::Magenta
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(has_right_up_diagonal_at_idx(idx, &board), BoardState::Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lower_diagonal_check() {
|
||||||
|
let board = new_empty_board();
|
||||||
|
|
||||||
|
board[17].replace(BoardState::Cyan);
|
||||||
|
board[25].replace(BoardState::Cyan);
|
||||||
|
board[33].replace(BoardState::Cyan);
|
||||||
|
board[41].replace(BoardState::Cyan);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 17 {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_down_diagonal_at_idx(idx, &board),
|
||||||
|
BoardState::Cyan
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_down_diagonal_at_idx(idx, &board),
|
||||||
|
BoardState::Empty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board[25].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
board[28].replace(BoardState::Magenta);
|
||||||
|
board[36].replace(BoardState::Magenta);
|
||||||
|
board[44].replace(BoardState::Magenta);
|
||||||
|
board[52].replace(BoardState::Magenta);
|
||||||
|
|
||||||
|
for y in 0..(ROWS as usize) {
|
||||||
|
for x in 0..(COLS as usize) {
|
||||||
|
let idx = x + y * (COLS as usize);
|
||||||
|
if idx == 28 {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_down_diagonal_at_idx(idx, &board),
|
||||||
|
BoardState::Magenta
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
has_right_down_diagonal_at_idx(idx, &board),
|
||||||
|
BoardState::Empty
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
54
front_end/src/html_helper.rs
Normal file
54
front_end/src/html_helper.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
use web_sys::{window, Document, Window};
|
||||||
|
|
||||||
|
pub fn get_window_document() -> Result<(Window, Document), String> {
|
||||||
|
let window = window().ok_or_else(|| String::from("Failed to get window"))?;
|
||||||
|
let document = window
|
||||||
|
.document()
|
||||||
|
.ok_or_else(|| String::from("Failed to get document"))?;
|
||||||
|
|
||||||
|
Ok((window, document))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_to_info_text(
|
||||||
|
document: &Document,
|
||||||
|
id: &str,
|
||||||
|
msg: &str,
|
||||||
|
limit: u32,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let info_text = document
|
||||||
|
.get_element_by_id(id)
|
||||||
|
.ok_or_else(|| format!("Failed to get info_text \"{}\"", id))?;
|
||||||
|
|
||||||
|
let height = info_text.client_height();
|
||||||
|
|
||||||
|
// create the new text to be appended in the text
|
||||||
|
let p = document
|
||||||
|
.create_element("p")
|
||||||
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
|
||||||
|
p.set_inner_html(msg);
|
||||||
|
|
||||||
|
// check if scrolled to top
|
||||||
|
let at_top: bool = info_text.scroll_top() <= height - info_text.scroll_height();
|
||||||
|
|
||||||
|
// append text to output
|
||||||
|
info_text
|
||||||
|
.append_with_node_1(&p)
|
||||||
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
|
||||||
|
while info_text.child_element_count() > limit {
|
||||||
|
info_text
|
||||||
|
.remove_child(
|
||||||
|
&info_text.first_child().ok_or_else(|| {
|
||||||
|
format!("Failed to get first_child() of info_text \"{}\"", id)
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
.map_err(|e| format!("{:?}", e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if at_top {
|
||||||
|
info_text.set_scroll_top(height - info_text.scroll_height());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
mod ai;
|
mod ai;
|
||||||
mod constants;
|
mod constants;
|
||||||
mod game_logic;
|
mod game_logic;
|
||||||
|
mod html_helper;
|
||||||
mod random_helper;
|
mod random_helper;
|
||||||
mod state;
|
mod state;
|
||||||
mod yew_components;
|
mod yew_components;
|
||||||
|
|
|
@ -9,7 +9,7 @@ pub enum GameState {
|
||||||
SinglePlayer,
|
SinglePlayer,
|
||||||
LocalMultiplayer,
|
LocalMultiplayer,
|
||||||
NetworkedMultiplayer,
|
NetworkedMultiplayer,
|
||||||
PostGameResults(Turn),
|
PostGameResults(BoardState),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GameState {
|
impl Default for GameState {
|
||||||
|
@ -108,6 +108,67 @@ impl Turn {
|
||||||
|
|
||||||
pub type BoardType = [Rc<Cell<BoardState>>; 56];
|
pub type BoardType = [Rc<Cell<BoardState>>; 56];
|
||||||
|
|
||||||
|
pub fn new_empty_board() -> BoardType {
|
||||||
|
[
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
Rc::new(Cell::new(BoardState::default())),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct SharedState {
|
pub struct SharedState {
|
||||||
pub board: BoardType,
|
pub board: BoardType,
|
||||||
|
@ -119,64 +180,7 @@ impl Default for SharedState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// cannot use [<type>; 56] because Rc does not impl Copy
|
// cannot use [<type>; 56] because Rc does not impl Copy
|
||||||
board: [
|
board: new_empty_board(),
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
Rc::new(Cell::new(BoardState::default())),
|
|
||||||
],
|
|
||||||
game_state: Rc::new(Cell::new(GameState::default())),
|
game_state: Rc::new(Cell::new(GameState::default())),
|
||||||
turn: Rc::new(Cell::new(Turn::CyanPlayer)),
|
turn: Rc::new(Cell::new(Turn::CyanPlayer)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use crate::constants::{COLS, INFO_TEXT_MAX_ITEMS, ROWS};
|
use crate::constants::{COLS, INFO_TEXT_MAX_ITEMS, ROWS};
|
||||||
|
use crate::game_logic::check_win_draw;
|
||||||
|
use crate::html_helper::{append_to_info_text, get_window_document};
|
||||||
use crate::state::{BoardState, GameState, SharedState, Turn};
|
use crate::state::{BoardState, GameState, SharedState, Turn};
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
pub struct MainMenu {}
|
pub struct MainMenu {}
|
||||||
|
@ -117,6 +121,13 @@ impl Component for Slot {
|
||||||
.context::<SharedState>(Callback::noop())
|
.context::<SharedState>(Callback::noop())
|
||||||
.expect("state to be set");
|
.expect("state to be set");
|
||||||
|
|
||||||
|
match shared.game_state.get() {
|
||||||
|
GameState::MainMenu => return false,
|
||||||
|
GameState::SinglePlayer
|
||||||
|
| GameState::LocalMultiplayer
|
||||||
|
| GameState::NetworkedMultiplayer => (),
|
||||||
|
GameState::PostGameResults(_) => return false,
|
||||||
|
}
|
||||||
if shared.game_state.get() == GameState::MainMenu {
|
if shared.game_state.get() == GameState::MainMenu {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -228,8 +239,8 @@ impl Component for Wrapper {
|
||||||
.link()
|
.link()
|
||||||
.context::<SharedState>(Callback::noop())
|
.context::<SharedState>(Callback::noop())
|
||||||
.expect("state to be set");
|
.expect("state to be set");
|
||||||
let window = web_sys::window().expect("no window exists");
|
let (window, document) =
|
||||||
let document = window.document().expect("window should have a document");
|
get_window_document().expect("Should be able to get Window and Document");
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
WrapperMsg::Pressed(idx) => {
|
WrapperMsg::Pressed(idx) => {
|
||||||
|
@ -268,99 +279,82 @@ impl Component for Wrapper {
|
||||||
placed = true;
|
placed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG
|
// check for win
|
||||||
//log::info!("{} is {:?}", idx, shared.board[idx as usize].get());
|
let check_win_draw_opt = check_win_draw(&shared.board);
|
||||||
|
if let Some(endgame_state) = check_win_draw_opt {
|
||||||
|
if endgame_state == BoardState::Empty {
|
||||||
|
// draw
|
||||||
|
let text_append_result = append_to_info_text(
|
||||||
|
&document,
|
||||||
|
"info_text0",
|
||||||
|
"Game ended in a draw",
|
||||||
|
INFO_TEXT_MAX_ITEMS,
|
||||||
|
);
|
||||||
|
if let Err(e) = text_append_result {
|
||||||
|
log::warn!("ERROR: text append to info_text0 failed: {}", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// a player won
|
||||||
|
let turn = Turn::from(endgame_state);
|
||||||
|
let text_string =
|
||||||
|
format!("<b class=\"{}\">{} has won</b>", turn.get_color(), turn);
|
||||||
|
let text_append_result = append_to_info_text(
|
||||||
|
&document,
|
||||||
|
"info_text0",
|
||||||
|
&text_string,
|
||||||
|
INFO_TEXT_MAX_ITEMS,
|
||||||
|
);
|
||||||
|
if let Err(e) = text_append_result {
|
||||||
|
log::warn!("ERROR: text append to info_text0 failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DEBUG
|
let text_append_result =
|
||||||
//log::info!("{}", &output_str);
|
append_to_info_text(&document, "info_text1", "<b>Game Over</b>", 1);
|
||||||
|
if let Err(e) = text_append_result {
|
||||||
|
log::warn!("ERROR: text append to info_text1 failed: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared
|
||||||
|
.game_state
|
||||||
|
.replace(GameState::PostGameResults(endgame_state));
|
||||||
|
} else {
|
||||||
|
// game is still ongoing
|
||||||
|
|
||||||
// info text below the grid
|
// info text below the grid
|
||||||
if let Some(info_text) = document.get_element_by_id("info_text0") {
|
{
|
||||||
let height = info_text.client_height();
|
|
||||||
|
|
||||||
// create the new text to be appended in the output
|
|
||||||
let p = document
|
|
||||||
.create_element("p")
|
|
||||||
.expect("document should be able to create <p>");
|
|
||||||
let output_str = match placed {
|
let output_str = match placed {
|
||||||
true => format!("{} placed into slot {}", current_player, bottom_idx),
|
true => format!("{} placed into slot {}", current_player, bottom_idx),
|
||||||
false => "Invalid place to insert".into(),
|
false => "Invalid place to insert".into(),
|
||||||
};
|
};
|
||||||
p.set_text_content(Some(&output_str));
|
|
||||||
|
|
||||||
// DEBUG
|
let text_append_result = append_to_info_text(
|
||||||
//log::info!(
|
&document,
|
||||||
// "pre: scroll top is {}, scroll height is {}",
|
"info_text0",
|
||||||
// info_text.scroll_top(),
|
&output_str,
|
||||||
// info_text.scroll_height()
|
INFO_TEXT_MAX_ITEMS,
|
||||||
//);
|
);
|
||||||
|
if let Err(e) = text_append_result {
|
||||||
// check if scrolled to top
|
log::warn!("ERROR: text append to info_text0 failed: {}", e);
|
||||||
let at_top: bool = info_text.scroll_top() <= height - info_text.scroll_height();
|
|
||||||
|
|
||||||
// append text to output
|
|
||||||
info_text
|
|
||||||
.append_with_node_1(&p)
|
|
||||||
.expect("should be able to append to info_text");
|
|
||||||
while info_text.child_element_count() > INFO_TEXT_MAX_ITEMS {
|
|
||||||
info_text
|
|
||||||
.remove_child(&info_text.first_child().unwrap())
|
|
||||||
.expect("should be able to limit items in info_text");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
//log::info!("at_top is {}", if at_top { "true" } else { "false" });
|
|
||||||
|
|
||||||
// scroll to top only if at top
|
|
||||||
if at_top {
|
|
||||||
info_text.set_scroll_top(height - info_text.scroll_height());
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
//log::info!(
|
|
||||||
// "post: scroll top is {}, scroll height is {}",
|
|
||||||
// info_text.scroll_top(),
|
|
||||||
// info_text.scroll_height()
|
|
||||||
//);
|
|
||||||
} else {
|
|
||||||
log::warn!("Failed to get bottom \"info_text\"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// info text right of the grid
|
// info text right of the grid
|
||||||
if let Some(info_text) = document.get_element_by_id("info_text1") {
|
{
|
||||||
let height = info_text.client_height();
|
|
||||||
|
|
||||||
// create the new text to be appended in the output
|
|
||||||
let p = document
|
|
||||||
.create_element("p")
|
|
||||||
.expect("document should be able to create <p>");
|
|
||||||
let turn = shared.turn.get();
|
let turn = shared.turn.get();
|
||||||
p.set_inner_html(&format!(
|
let output_str = format!(
|
||||||
"<b class=\"{}\">It is {}'s turn</b>",
|
"<b class=\"{}\">It is {}'s turn</b>",
|
||||||
turn.get_color(),
|
turn.get_color(),
|
||||||
turn
|
turn
|
||||||
));
|
);
|
||||||
|
|
||||||
// check if scrolled to top
|
let text_append_result =
|
||||||
let at_top: bool = info_text.scroll_top() <= height - info_text.scroll_height();
|
append_to_info_text(&document, "info_text1", &output_str, 1);
|
||||||
|
if let Err(e) = text_append_result {
|
||||||
// append text to output
|
log::warn!("ERROR: text append to info_text1 failed: {}", e);
|
||||||
info_text
|
|
||||||
.append_with_node_1(&p)
|
|
||||||
.expect("should be able to append to info_text");
|
|
||||||
while info_text.child_element_count() > 1 {
|
|
||||||
info_text
|
|
||||||
.remove_child(&info_text.first_child().unwrap())
|
|
||||||
.expect("should be able to limit items in info_text");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// scroll to top only if at top
|
|
||||||
if at_top {
|
|
||||||
info_text.set_scroll_top(height - info_text.scroll_height());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::warn!("Failed to get side \"info_text\"");
|
|
||||||
}
|
}
|
||||||
|
} // else: game is still ongoing after logic check
|
||||||
} // WrapperMsg::Pressed(idx) =>
|
} // WrapperMsg::Pressed(idx) =>
|
||||||
} // match (msg)
|
} // match (msg)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue