From f6c2ef753de0ac8353fb251b7fac96cf5a81b920 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Sun, 2 Mar 2025 21:38:04 -0500 Subject: [PATCH] split off game_inner --- src/game.rs | 101 ++---------------------------------- src/game_inner.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 1 + 4 files changed, 134 insertions(+), 97 deletions(-) create mode 100644 src/game_inner.rs diff --git a/src/game.rs b/src/game.rs index 29ca1f1..44bd168 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,115 +1,22 @@ use crate::{ agent::Agent, + game_inner::GameInner, repr::{Board, Piece, Winner}, }; 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(()) - } + inner: GameInner, } #[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(), + inner: GameInner::new(player1, player2, true), } } - // 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(coord) = player_move { - match self.board.place(coord, player_color) { - // Check if its a valid move - Ok(_) => { - println!("Player {} placed at {}", player_i, coord); - 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, coord - ); - } - } - } 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() { - Winner::Player(piece) => { - println!("{} Wins!", piece.text()); - break; - } - Winner::Tie => { - println!("Game Tied!"); - break; - } - Winner::None => {} - } - - self.step(current_player); - current_player += 1; - } + self.inner.game_loop(); } } diff --git a/src/game_inner.rs b/src/game_inner.rs new file mode 100644 index 0000000..04fcb12 --- /dev/null +++ b/src/game_inner.rs @@ -0,0 +1,128 @@ +use crate::{ + agent::Agent, + repr::{Board, Piece, Winner}, +}; + +impl std::fmt::Display for GameInner { + 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(()) + } +} + +pub struct GameInner { + players: [Box; 2], + board: Board, + do_print: bool, +} + +impl GameInner { + pub fn new(player1: Box, player2: Box, do_print: bool) -> 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(), + do_print, + } + } + + // 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(coord) = player_move { + match self.board.place(coord, player_color) { + // Check if its a valid move + Ok(_) => { + if self.do_print { + println!("Player {} placed at {}", player_i, coord); + } + break; + } + + Err(err) => { + panic!( + "Invalid move by Player {}: {}. Move: {}", + player_i, err, coord + ); + } + } + } 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).next().is_some() { + if self.do_print { + 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(); + + if self.do_print { + println!("{}", self); + } + + match self.board.game_winner() { + Winner::Player(piece) => { + if self.do_print { + println!("{} Wins!", piece.text()); + } + break; + } + Winner::Tie => { + if self.do_print { + println!("Game Tied!"); + } + break; + } + Winner::None => {} + } + + self.step(current_player); + current_player += 1; + } + } + + pub fn loop_until_result(&mut self) -> Winner { + self.game_loop(); + self.board.game_winner() + } +} diff --git a/src/lib.rs b/src/lib.rs index 4dffdd7..544b748 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod agent; mod complexagent; mod game; +mod game_inner; pub mod logic; pub mod repr; diff --git a/src/main.rs b/src/main.rs index 0bd349a..4c9825e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ use repr::Piece; mod agent; mod complexagent; mod game; +mod game_inner; mod logic; pub mod repr;