mirror of
https://github.com/Noratrieb/minmax.git
synced 2026-01-14 23:35:04 +01:00
board works
This commit is contained in:
parent
b4badd4290
commit
6c3bf8dddb
1 changed files with 100 additions and 7 deletions
|
|
@ -4,10 +4,14 @@ use crate::{Player, State};
|
||||||
|
|
||||||
type Position = Option<Player>;
|
type Position = Option<Player>;
|
||||||
|
|
||||||
const BOARD_WIDTH: usize = 7;
|
const WIDTH: usize = 7;
|
||||||
const BOARD_HEIGHT: usize = 4;
|
const HEIGTH: usize = 4;
|
||||||
const BOARD_POSITIONS: usize = BOARD_WIDTH * BOARD_HEIGHT;
|
const BOARD_POSITIONS: usize = WIDTH * HEIGTH;
|
||||||
|
|
||||||
|
/// 0 1 2 3 4 5 6
|
||||||
|
/// 7 8 9 10 11 12 13
|
||||||
|
/// 14 15 16 17 18 19 20
|
||||||
|
/// 21 22 23 24 25 26 27
|
||||||
pub struct Board {
|
pub struct Board {
|
||||||
positions: [Position; BOARD_POSITIONS],
|
positions: [Position; BOARD_POSITIONS],
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +24,14 @@ impl Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn result(&self) -> State {
|
pub fn result(&self) -> State {
|
||||||
self.check_board()
|
match self.check_board() {
|
||||||
|
State::Winner(winner) => State::Winner(winner),
|
||||||
|
State::InProgress if self.positions.iter().all(|position| position.is_some()) => {
|
||||||
|
State::Draw
|
||||||
|
}
|
||||||
|
State::InProgress => State::InProgress,
|
||||||
|
State::Draw => unreachable!("check_board cannot tell a draw"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_board(&self) -> State {
|
fn check_board(&self) -> State {
|
||||||
|
|
@ -30,15 +41,15 @@ impl Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_columns(&self) -> State {
|
fn check_columns(&self) -> State {
|
||||||
for i in 0..BOARD_WIDTH {
|
for i in 0..WIDTH {
|
||||||
self.check_four(i, i + BOARD_WIDTH, i + 2 * BOARD_WIDTH, i + 3 * BOARD_WIDTH)?;
|
self.check_four(i, i + WIDTH, i + 2 * WIDTH, i + 3 * WIDTH)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
State::InProgress
|
State::InProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_rows(&self) -> State {
|
fn check_rows(&self) -> State {
|
||||||
for row_start in 0..BOARD_HEIGHT {
|
for row_start in 0..HEIGTH {
|
||||||
for offset in 0..4 {
|
for offset in 0..4 {
|
||||||
let start = row_start + offset;
|
let start = row_start + offset;
|
||||||
self.check_four(start, start + 1, start + 2, start + 3)?;
|
self.check_four(start, start + 1, start + 2, start + 3)?;
|
||||||
|
|
@ -49,6 +60,17 @@ impl Board {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_diagonals(&self) -> State {
|
fn check_diagonals(&self) -> State {
|
||||||
|
// */*
|
||||||
|
for start in 3..WIDTH {
|
||||||
|
const DIFF: usize = WIDTH - 1;
|
||||||
|
self.check_four(start, start + DIFF, start + 2 * DIFF, start + 3 * DIFF)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *\*
|
||||||
|
for start in 0..4 {
|
||||||
|
const DIFF: usize = WIDTH + 1;
|
||||||
|
self.check_four(start, start + DIFF, start + 2 * DIFF, start + 3 * DIFF)?;
|
||||||
|
}
|
||||||
State::InProgress
|
State::InProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,3 +95,74 @@ impl Index<usize> for Board {
|
||||||
&self.positions[index]
|
&self.positions[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{Player, State};
|
||||||
|
|
||||||
|
use super::Board;
|
||||||
|
|
||||||
|
fn parse_board(board: &str) -> Board {
|
||||||
|
let positions = board
|
||||||
|
.chars()
|
||||||
|
.filter(|char| !char.is_whitespace())
|
||||||
|
.map(|char| match char {
|
||||||
|
'X' => Some(Player::X),
|
||||||
|
'O' => Some(Player::O),
|
||||||
|
'_' => None,
|
||||||
|
char => panic!("Invalid char in board: `{char}`"),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.expect(&format!(
|
||||||
|
"not enough positions provided: {}",
|
||||||
|
board.chars().filter(|c| !c.is_whitespace()).count()
|
||||||
|
));
|
||||||
|
|
||||||
|
Board { positions }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test(board: &str, state: State) {
|
||||||
|
let board = parse_board(board);
|
||||||
|
assert_eq!(board.result(), state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn draw() {
|
||||||
|
test(
|
||||||
|
"
|
||||||
|
XOOOXOX
|
||||||
|
XOOOXOX
|
||||||
|
OXXXOXO
|
||||||
|
XOOOXXX
|
||||||
|
",
|
||||||
|
State::Draw,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_winner() {
|
||||||
|
test(
|
||||||
|
"
|
||||||
|
XOOOXOX
|
||||||
|
XOOOXOX
|
||||||
|
OXXXOXO
|
||||||
|
XOOOXOX
|
||||||
|
",
|
||||||
|
State::Winner(Player::O),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_rows() {
|
||||||
|
test(
|
||||||
|
"
|
||||||
|
XXX_OOO
|
||||||
|
_XXX___
|
||||||
|
X_OOO__
|
||||||
|
OOO____
|
||||||
|
",
|
||||||
|
State::InProgress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue