split off game_inner
This commit is contained in:
parent
ed1c785cb3
commit
f6c2ef753d
101
src/game.rs
101
src/game.rs
@ -1,115 +1,22 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
agent::Agent,
|
agent::Agent,
|
||||||
|
game_inner::GameInner,
|
||||||
repr::{Board, Piece, Winner},
|
repr::{Board, Piece, Winner},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
players: [Box<dyn Agent>; 2],
|
inner: GameInner,
|
||||||
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)]
|
#[allow(dead_code)]
|
||||||
impl Game {
|
impl Game {
|
||||||
pub fn new(player1: Box<dyn Agent>, player2: Box<dyn Agent>) -> Self {
|
pub fn new(player1: Box<dyn Agent>, player2: Box<dyn Agent>) -> 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 {
|
Self {
|
||||||
players: [player1, player2],
|
inner: GameInner::new(player1, player2, true),
|
||||||
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(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) {
|
pub fn game_loop(&mut self) {
|
||||||
let mut current_player: usize = 0;
|
self.inner.game_loop();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
128
src/game_inner.rs
Normal file
128
src/game_inner.rs
Normal file
@ -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<dyn Agent>; 2],
|
||||||
|
board: Board,
|
||||||
|
do_print: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameInner {
|
||||||
|
pub fn new(player1: Box<dyn Agent>, player2: Box<dyn Agent>, 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
mod agent;
|
mod agent;
|
||||||
mod complexagent;
|
mod complexagent;
|
||||||
mod game;
|
mod game;
|
||||||
|
mod game_inner;
|
||||||
pub mod logic;
|
pub mod logic;
|
||||||
pub mod repr;
|
pub mod repr;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use repr::Piece;
|
|||||||
mod agent;
|
mod agent;
|
||||||
mod complexagent;
|
mod complexagent;
|
||||||
mod game;
|
mod game;
|
||||||
|
mod game_inner;
|
||||||
mod logic;
|
mod logic;
|
||||||
pub mod repr;
|
pub mod repr;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user