use crate::{ agent::Agent, board::{Board, Winner}, piece::Piece, }; pub struct Game { players: [Box; 2], board: Board, } impl std::fmt::Display for Game { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!( f, "Players: {} ({}) and {} ({})", self.players[0].name(), self.players[0].color().symbol(), self.players[1].name(), self.players[1].color().symbol() )?; write!(f, "{}", self.board)?; Ok(()) } } #[allow(dead_code)] impl Game { pub fn new(player1: Box, player2: Box) -> Self { let player1_color = player1.color(); let player2_color = player2.color(); assert_ne!( player1_color, player2_color, "Both players cannot have the same color {}", player1_color.text() ); assert_eq!(player1_color, Piece::Black, "player 1 must playing black"); assert_eq!(player2_color, Piece::White, "player 2 must play white"); Self { players: [player1, player2], board: Board::new().starting_pos(), } } // Handle when a move is made pub fn step(&mut self, player_i: usize) { let player_color = self.players[player_i].color(); // TODO! move this to `ManualAgent` as it's only really useful // when it comes to human input loop { let player_move = self.players[player_i].next_move(&self.board); if let Some((i, j)) = player_move { match self.board.place(i, j, player_color) { // Check if its a valid move Ok(_) => { println!("Player {} placed at ({}, {})", player_i, i, j); break; } // Lets the player try again if the move is invalid // Now we dont need to restart the game if we mess up Err(err) => { panic!( "Invalid move by Player {}: {}. Try again. Move: ({}, {})", player_i, err, i, j ); } } } else { println!("Player {} did not make a move!", player_i); // players are able to skip a move if they have no valid moves to make if self.board.possible_moves(player_color).any(|_| true) { println!( "Player {} has possible moves, but skipped (invalid)", player_i ); continue; } return; // No valid move available } } } // TODO! make this loop good pub fn game_loop(&mut self) { let mut current_player: usize = 0; loop { // alternate which player plays current_player %= self.players.len(); println!("{}", self); match self.board.game_winner(self.players[current_player].color()) { Winner::Player(piece) => { println!("{} Wins!", piece.text()); break; } Winner::Tie => { println!("Game Tied!"); break; } Winner::None => {} } self.step(current_player); current_player += 1; } } }