use crate::bit_patterns::{Cell, WinPattern};
use crate::{Board, Player};
mod board_display;
impl Board {
#[allow(non_snake_case)]
fn has_player_set_cell(&self, player: Player, cell: Cell) -> bool {
self.cells & cell != 0
&& if let Player::O = player {
self.cells & cell >> 1 == 0
} else {
self.cells & cell >> 1 != 0
}
}
fn is_cell_set(&self, cell: Cell) -> bool {
self.cells & cell != 0
}
fn set_cell(&mut self, player: Player, cell: Cell) {
self.cells |= cell;
if let Player::X = player {
self.cells |= cell >> 1
}
}
fn on_user_input(&mut self) -> Cell {
loop {
println!("Enter a value between 1-9");
let mut player_input_stream = String::new();
std::io::stdin()
.read_line(&mut player_input_stream)
.unwrap();
match Cell::try_from(player_input_stream.trim()) {
Some(c) if !self.is_cell_set(c) => return c,
Some(_) => println!("Sorry, this cell has already been set!"),
None => println!("Sorry, please enter a valid number."),
}
}
}
}
impl Board {
pub(crate) fn new() -> Board {
Board { cells: 0 }
}
pub(crate) fn is_every_cell_set(&self) -> bool {
!self.cells & 0b101010101010101010 == 0
}
pub(crate) fn select_cell(&mut self, player: Player) {
if self.is_every_cell_set() {
return;
}
println!("{}: Select a Cell", player);
let cell = self.on_user_input();
self.set_cell(player, cell);
}
pub(crate) fn check_player_has_won(&self, player: Player, win_pattern: WinPattern) -> bool {
let cells: [Cell; 3] = win_pattern.into();
cells.iter().all(|c| self.has_player_set_cell(player, *c))
}
pub(crate) fn has_player_won(&self) -> bool {
[
WinPattern::TopRow,
WinPattern::CentreRow,
WinPattern::BottomRow,
WinPattern::LeftColumn,
WinPattern::CentreColumn,
WinPattern::RightColumn,
WinPattern::LeftDiagonal,
WinPattern::RightDiagonal,
]
.iter()
.any(|p| {
self.check_player_has_won(Player::O, *p) || self.check_player_has_won(Player::X, *p)
})
}
}
#[cfg(test)]
mod tests;