fix: have no start item selection, only choose who starts (bot game type)

This commit is contained in:
landrigun 2022-11-15 10:14:22 +00:00
parent 5f5f34a52f
commit 7d1162f117

View File

@ -46,6 +46,7 @@ trait Displayer {
} }
/// Represents the **Tic-Tac-Toe** board game /// Represents the **Tic-Tac-Toe** board game
#[derive(Copy, Clone)]
struct Board { struct Board {
// board array is reprensented as follow: // board array is reprensented as follow:
// [ 0, 1, 2 ] // [ 0, 1, 2 ]
@ -224,6 +225,20 @@ impl Player {
fn new(item: Item, is_bot: bool) -> Self { fn new(item: Item, is_bot: bool) -> Self {
Player { item, is_bot } Player { item, is_bot }
} }
fn as_bot() -> Self {
Player {
item: Item::Empty,
is_bot: true,
}
}
fn as_human() -> Self {
Player {
item: Item::Empty,
is_bot: false,
}
}
} }
impl Default for Player { impl Default for Player {
@ -239,10 +254,7 @@ impl Player {
/// init players with the game type /// init players with the game type
fn from_game_type(game_type: GameType) -> Vec<Player> { fn from_game_type(game_type: GameType) -> Vec<Player> {
match game_type { match game_type {
GameType::TwoPlayers => vec![ GameType::TwoPlayers => vec![Player::new(Item::X, false), Player::new(Item::O, false)],
Player::new(Item::Empty, false),
Player::new(Item::Empty, false),
],
GameType::Bot => vec![ GameType::Bot => vec![
Player::new(Item::Empty, false), Player::new(Item::Empty, false),
Player::new(Item::Empty, true), Player::new(Item::Empty, true),
@ -255,7 +267,7 @@ impl Player {
/// Two `GameType` availables: /// Two `GameType` availables:
/// * TwoPlayers: no bot /// * TwoPlayers: no bot
/// * Bot: player against the bot /// * Bot: player against the bot
#[derive(Copy, Clone)] #[derive(Copy, Clone, PartialEq)]
enum GameType { enum GameType {
TwoPlayers, TwoPlayers,
Bot, Bot,
@ -306,15 +318,15 @@ impl TicTacToe {
self.game_type = game_type; self.game_type = game_type;
} }
fn set_players_item(&mut self, first_item: Item) -> Result<(), String> { fn set_players_item(&mut self) -> Result<(), String> {
if self.players.len() != 2 { if self.players.len() != 2 {
return Err( return Err(
"unable to initialize players item, 2 players must be initialized".to_string(), "unable to initialize players item, 2 players must be initialized".to_string(),
); );
} }
self.players[0].item = first_item; self.players[0].item = Item::X;
self.players[1].item = first_item.next(); self.players[1].item = Item::O;
Ok(()) Ok(())
} }
@ -334,8 +346,17 @@ impl TicTacToe {
Ok(self.players[0]) Ok(self.players[0])
} }
/// set the item for the first player (the one that starts) /// if `GameType` is againt bot, you can select who starts
fn select_first_player_item(&mut self) { fn select_first_player(&mut self) {
if self.players.len() != 2 {
fatal("unable to initialize the game, 2 players must be set".to_string());
}
// the first player always starts whith 'X'
if self.game_type == GameType::TwoPlayers {
return;
}
let mut attempt = 0; let mut attempt = 0;
loop { loop {
if attempt == 2 { if attempt == 2 {
@ -343,19 +364,29 @@ impl TicTacToe {
std::process::exit(1); std::process::exit(1);
} }
let input = TicTacToe::get_user_input("first player, choose your item: ('X' or 'O')"); let input = TicTacToe::get_user_input("who starts: ('B': bot, 'H': you as human)");
let item_start = Item::try_from(input); let is_bot = self.players[0].is_bot;
match item_start {
Ok(item) => { match &input[..] {
match self.set_players_item(item) { "B" | "b" => {
Ok(()) => break, if !is_bot {
Err(e) => fatal(e), self.players.swap(0, 1)
} }
break;
} }
Err(e) => error(e.to_string()), "H" | "h" => {
if is_bot {
self.players.swap(0, 1)
} }
}
_ => {
error("bad input, please retry!".to_string());
attempt += 1; attempt += 1;
continue;
}
}
self.set_players_item();
break;
} }
} }
@ -410,9 +441,22 @@ impl TicTacToe {
Ok(available_indexes[0] + 1) Ok(available_indexes[0] + 1)
} }
/// minimax algorithm used by the bot player to find the best move (minimizing the loses)
fn minimax(&self, board: Option<Board>, player: Player, depth: usize) -> usize {
let mut board = match board {
Some(b) => b,
None => self.board.clone(),
};
let availables_indexes = board.get_available_indexes();
for index in availables_indexes {
board.set_item(player.item, index);
}
0
}
fn run(&mut self) { fn run(&mut self) {
self.select_game_type(); self.select_game_type();
self.select_first_player_item(); self.select_first_player();
loop { loop {
if self.board.is_full() { if self.board.is_full() {