use super::{errors::ValidationError, GameState, Grid, Mark};
pub(crate) fn validate_game_state(game_state: &GameState) -> Result<(), ValidationError> {
validate_number_of_marks(game_state.grid())?;
validate_starting_mark(game_state.grid(), game_state.starting_mark())?;
validate_winner(
game_state.grid(),
game_state.starting_mark(),
game_state.winner_mark(),
)?;
Ok(())
}
fn validate_number_of_marks(grid: &Grid) -> Result<(), ValidationError> {
let cross_count = grid.cross_count();
let naught_count = grid.naught_count();
if cross_count.abs_diff(naught_count) > 1 {
return Err(ValidationError::WrongNumberOfNaughtsAndCrosses(
naught_count,
cross_count,
));
}
Ok(())
}
fn validate_starting_mark(grid: &Grid, starting_mark: &Mark) -> Result<(), ValidationError> {
let cross_count = grid.cross_count();
let naught_count = grid.naught_count();
if (cross_count > naught_count && starting_mark == &Mark::Naught)
|| (cross_count < naught_count && starting_mark == &Mark::Cross)
{
return Err(ValidationError::WrongStartingMark(*starting_mark));
}
Ok(())
}
fn validate_winner(
grid: &Grid,
starting_mark: &Mark,
winner: Option<Mark>,
) -> Result<(), ValidationError> {
if let Some(winner_mark) = winner {
if winner_mark == Mark::Cross {
if starting_mark == &Mark::Cross {
if grid.cross_count() <= grid.naught_count() {
return Err(ValidationError::WrongWinnerMark(winner_mark));
}
} else if grid.cross_count() != grid.naught_count() {
return Err(ValidationError::WrongWinnerMark(winner_mark));
}
} else if winner_mark == Mark::Naught {
if starting_mark == &Mark::Naught {
if grid.naught_count() <= grid.cross_count() {
return Err(ValidationError::WrongWinnerMark(winner_mark));
}
} else if grid.naught_count() != grid.cross_count() {
return Err(ValidationError::WrongWinnerMark(winner_mark));
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::logic::Cell;
use super::*;
#[test]
fn test_validate_number_of_marks_valid() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_empty(),
Cell::new_empty(),
]));
let game_state = GameState::new(grid, None).unwrap();
assert!(validate_number_of_marks(game_state.grid()).is_ok());
}
#[test]
fn test_validate_number_of_marks_fail() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Cross),
Cell::new_empty(),
Cell::new_empty(),
Cell::new_empty(),
]));
let result = validate_number_of_marks(&grid);
assert!(result.is_err());
}
#[test]
fn test_validate_starting_mark_valid() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_empty(),
]));
let game_state = GameState::new(grid, Some(Mark::Cross)).unwrap();
assert!(validate_starting_mark(game_state.grid(), game_state.starting_mark()).is_ok());
}
#[test]
fn test_validate_starting_mark_fail() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_empty(),
]));
let result = validate_starting_mark(&grid, &Mark::Naught);
assert!(result.is_err());
}
#[test]
fn test_validate_winner_valid() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Naught),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_empty(),
]));
let game_state = GameState::new(grid, Some(Mark::Naught)).unwrap();
assert!(validate_winner(
game_state.grid(),
game_state.starting_mark(),
Some(Mark::Cross)
)
.is_ok());
}
#[test]
fn test_validate_winner_fail() {
let grid = Grid::new(Some([
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Cross),
Cell::new_marked(Mark::Naught),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_marked(Mark::Naught),
Cell::new_empty(),
Cell::new_empty(),
]));
let game_state = GameState::new(grid, Some(Mark::Naught)).unwrap();
assert!(validate_winner(
game_state.grid(),
game_state.starting_mark(),
Some(Mark::Naught)
)
.is_err());
}
}