EN605.607.81.SP22_ASDM_Project/front_end/src/game_logic.rs
Stephen Seo b902b1c7b4 Impl use of win/draw check, fixes
Also added unit tests for win/draw checks.
2022-03-09 17:29:53 +09:00

330 lines
10 KiB
Rust

use crate::constants::{COLS, ROWS};
use crate::state::{BoardState, BoardType};
/// Returns a BoardState if win/draw, None if game is still going
pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
let mut has_empty_slot = false;
for slot in board {
match slot.get() {
BoardState::Empty => {
has_empty_slot = true;
break;
}
BoardState::Cyan | BoardState::Magenta => (),
}
}
if !has_empty_slot {
return Some(BoardState::Empty);
}
let check_result = |state| -> Option<BoardState> {
match state {
BoardState::Empty => None,
BoardState::Cyan => Some(BoardState::Cyan),
BoardState::Magenta => 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));
if result.is_some() {
return result;
}
}
}
// 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));
if result.is_some() {
return result;
}
}
}
// 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));
if result.is_some() {
return result;
}
}
}
// 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,
));
if result.is_some() {
return result;
}
}
}
None
}
fn has_right_horizontal_at_idx(idx: usize, board: &BoardType) -> BoardState {
let state_at_idx = board[idx].get();
if idx % (COLS as usize) < (COLS as usize) - 3 {
for x in 0..=3 {
if board[idx + x].get() != state_at_idx {
break;
} else if x == 3 {
return state_at_idx;
}
}
}
BoardState::Empty
}
fn has_down_vertical_at_idx(idx: usize, board: &BoardType) -> BoardState {
let state_at_idx = board[idx].get();
if idx / (COLS as usize) < (ROWS as usize) - 3 {
for y in 0..=3 {
if board[idx + y * (COLS as usize)].get() != state_at_idx {
break;
} else if y == 3 {
return state_at_idx;
}
}
}
BoardState::Empty
}
fn has_right_up_diagonal_at_idx(idx: usize, board: &BoardType) -> BoardState {
let state_at_idx = board[idx].get();
if idx % (COLS as usize) < (COLS as usize) - 3 && idx / (COLS as usize) > 2 {
for i in 0..=3 {
if board[idx + i - i * (COLS as usize)].get() != state_at_idx {
break;
} else if i == 3 {
return state_at_idx;
}
}
}
BoardState::Empty
}
fn has_right_down_diagonal_at_idx(idx: usize, board: &BoardType) -> BoardState {
let state_at_idx = board[idx].get();
if idx % (COLS as usize) < (COLS as usize) - 3 && idx / (COLS as usize) < (ROWS as usize) - 3 {
for i in 0..=3 {
if board[idx + i + i * (COLS as usize)].get() != state_at_idx {
break;
} else if i == 3 {
return state_at_idx;
}
}
}
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
);
}
}
}
}
}