use crate::constants::{COLS, ROWS};
use crate::state::{BoardState, BoardType};
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum WinType {
+ Horizontal(usize),
+ Vertical(usize),
+ DiagonalUp(usize),
+ DiagonalDown(usize),
+ None,
+}
+
/// Returns a BoardState if win/draw, None if game is still going
-pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
+pub fn check_win_draw(board: &BoardType) -> Option<(BoardState, WinType)> {
let mut has_empty_slot = false;
for slot in board {
match slot.get() {
has_empty_slot = true;
break;
}
- BoardState::Cyan | BoardState::Magenta => (),
+ BoardState::Cyan
+ | BoardState::CyanWin
+ | BoardState::Magenta
+ | BoardState::MagentaWin => (),
}
}
if !has_empty_slot {
- return Some(BoardState::Empty);
+ return Some((BoardState::Empty, WinType::None));
}
let check_result = |state| -> Option<BoardState> {
match state {
BoardState::Empty => None,
- BoardState::Cyan => Some(BoardState::Cyan),
- BoardState::Magenta => Some(BoardState::Magenta),
+ BoardState::Cyan | BoardState::CyanWin => Some(BoardState::Cyan),
+ BoardState::Magenta | BoardState::MagentaWin => Some(BoardState::Magenta),
}
};
// check horizontals
for y in 0..(ROWS as usize) {
for x in 0..((COLS - 3) as usize) {
- let result = check_result(has_right_horizontal_at_idx(x + y * (COLS as usize), board));
+ let idx = x + y * (COLS as usize);
+ let result = check_result(has_right_horizontal_at_idx(idx, board));
if result.is_some() {
- return result;
+ return Some((result.unwrap(), WinType::Horizontal(idx)));
}
}
}
// check verticals
for y in 0..((ROWS - 3) as usize) {
for x in 0..(COLS as usize) {
- let result = check_result(has_down_vertical_at_idx(x + y * (COLS as usize), board));
+ let idx = x + y * (COLS as usize);
+ let result = check_result(has_down_vertical_at_idx(idx, board));
if result.is_some() {
- return result;
+ return Some((result.unwrap(), WinType::Vertical(idx)));
}
}
}
// check up diagonals
for y in 3..(ROWS as usize) {
for x in 0..((COLS - 3) as usize) {
- let result = check_result(has_right_up_diagonal_at_idx(x + y * (COLS as usize), board));
+ let idx = x + y * (COLS as usize);
+ let result = check_result(has_right_up_diagonal_at_idx(idx, board));
if result.is_some() {
- return result;
+ return Some((result.unwrap(), WinType::DiagonalUp(idx)));
}
}
}
// check down diagonals
for y in 0..((ROWS - 3) as usize) {
for x in 0..((COLS - 3) as usize) {
- let result = check_result(has_right_down_diagonal_at_idx(
- x + y * (COLS as usize),
- board,
- ));
+ let idx = x + y * (COLS as usize);
+ let result = check_result(has_right_down_diagonal_at_idx(idx, board));
if result.is_some() {
- return result;
+ return Some((result.unwrap(), WinType::DiagonalDown(idx)));
}
}
}
Empty,
Cyan,
Magenta,
+ CyanWin,
+ MagentaWin,
}
impl Default for BoardState {
match *self {
BoardState::Empty => f.write_str("open"),
BoardState::Cyan => f.write_str("cyan"),
+ BoardState::CyanWin => f.write_str("cyan win"),
BoardState::Magenta => f.write_str("magenta"),
+ BoardState::MagentaWin => f.write_str("magenta win"),
}
}
}
pub fn is_empty(&self) -> bool {
*self == BoardState::Empty
}
+
+ pub fn into_win(&self) -> Self {
+ match *self {
+ BoardState::Empty => BoardState::Empty,
+ BoardState::Cyan | BoardState::CyanWin => BoardState::CyanWin,
+ BoardState::Magenta | BoardState::MagentaWin => BoardState::MagentaWin,
+ }
+ }
+
+ pub fn from_win(&self) -> Self {
+ match *self {
+ BoardState::Empty => BoardState::Empty,
+ BoardState::Cyan | BoardState::CyanWin => BoardState::Cyan,
+ BoardState::Magenta | BoardState::MagentaWin => BoardState::MagentaWin,
+ }
+ }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
impl From<BoardState> for Turn {
fn from(board_state: BoardState) -> Self {
match board_state {
- BoardState::Empty | BoardState::Cyan => Turn::CyanPlayer,
- BoardState::Magenta => Turn::MagentaPlayer,
+ BoardState::Empty | BoardState::Cyan | BoardState::CyanWin => Turn::CyanPlayer,
+ BoardState::Magenta | BoardState::MagentaWin => Turn::MagentaPlayer,
}
}
}
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::game_logic::{check_win_draw, WinType};
+use crate::html_helper::{append_to_info_text, element_append_class, get_window_document};
use crate::state::{BoardState, GameState, SharedState, Turn};
use std::cell::Cell;
// check for win
let check_win_draw_opt = check_win_draw(&shared.board);
- if let Some(endgame_state) = check_win_draw_opt {
+ if let Some((endgame_state, win_type)) = check_win_draw_opt {
if endgame_state == BoardState::Empty {
// draw
let text_append_result = append_to_info_text(
if let Err(e) = text_append_result {
log::warn!("ERROR: text append to info_text0 failed: {}", e);
}
+
+ match win_type {
+ WinType::Horizontal(idx) => {
+ let append_result =
+ element_append_class(&document, &format!("slot{}", idx), "win");
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 1),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 2),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 3),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+
+ shared.board[idx].replace(shared.board[idx].get().into_win());
+ shared.board[idx + 1]
+ .replace(shared.board[idx + 1].get().into_win());
+ shared.board[idx + 2]
+ .replace(shared.board[idx + 2].get().into_win());
+ shared.board[idx + 3]
+ .replace(shared.board[idx + 3].get().into_win());
+ }
+ WinType::Vertical(idx) => {
+ let append_result =
+ element_append_class(&document, &format!("slot{}", idx), "win");
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 1 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 2 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 3 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+
+ shared.board[idx].replace(shared.board[idx].get().into_win());
+ shared.board[idx + 1 * (COLS as usize)].replace(
+ shared.board[idx + 1 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 2 * (COLS as usize)].replace(
+ shared.board[idx + 2 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 3 * (COLS as usize)].replace(
+ shared.board[idx + 3 * (COLS as usize)].get().into_win(),
+ );
+ }
+ WinType::DiagonalUp(idx) => {
+ let append_result =
+ element_append_class(&document, &format!("slot{}", idx), "win");
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 1 - 1 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 2 - 2 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 3 - 3 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+
+ shared.board[idx].replace(shared.board[idx].get().into_win());
+ shared.board[idx + 1 - 1 * (COLS as usize)].replace(
+ shared.board[idx + 1 - 1 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 2 - 2 * (COLS as usize)].replace(
+ shared.board[idx + 2 - 2 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 3 - 3 * (COLS as usize)].replace(
+ shared.board[idx + 3 - 3 * (COLS as usize)].get().into_win(),
+ );
+ }
+ WinType::DiagonalDown(idx) => {
+ let append_result =
+ element_append_class(&document, &format!("slot{}", idx), "win");
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 1 + 1 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 2 + 2 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+ let append_result = element_append_class(
+ &document,
+ &format!("slot{}", idx + 3 + 3 * (COLS as usize)),
+ "win",
+ );
+ if let Err(e) = append_result {
+ log::warn!("ERROR: element_append_class failed: {}", e);
+ }
+
+ shared.board[idx].replace(shared.board[idx].get().into_win());
+ shared.board[idx + 1 + 1 * (COLS as usize)].replace(
+ shared.board[idx + 1 + 1 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 2 + 2 * (COLS as usize)].replace(
+ shared.board[idx + 2 + 2 * (COLS as usize)].get().into_win(),
+ );
+ shared.board[idx + 3 + 3 * (COLS as usize)].replace(
+ shared.board[idx + 3 + 3 * (COLS as usize)].get().into_win(),
+ );
+ }
+ WinType::None => todo!(),
+ }
}
let text_append_result =