add back functionality
This commit is contained in:
parent
80db0a872d
commit
fc8c2b8178
33
src/agent.rs
33
src/agent.rs
@ -3,11 +3,18 @@ use rand::prelude::*;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AgentMove {
|
||||
CoordPair(CoordPair),
|
||||
Back,
|
||||
Skip,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// implements `Send` so we can use it in a multithreaded `EloArena`
|
||||
pub trait Agent: Send {
|
||||
/// Returns the move of an [`Agent`]
|
||||
fn next_move(&mut self, board: &Board) -> Option<CoordPair>;
|
||||
fn next_move(&mut self, board: &Board) -> AgentMove;
|
||||
/// Returns the name of the [`Agent`]
|
||||
fn name(&self) -> &'static str;
|
||||
/// Returns the color the [`Agent`] is playing
|
||||
@ -28,16 +35,23 @@ impl ManualAgent {
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Agent for ManualAgent {
|
||||
fn next_move(&mut self, board: &Board) -> Option<CoordPair> {
|
||||
fn next_move(&mut self, board: &Board) -> AgentMove {
|
||||
let stdin = io::stdin();
|
||||
let mut input = String::new();
|
||||
println!("Your turn! ('Skip' to skip)");
|
||||
println!("Your turn! ('Skip' to skip 'back' to go back a move)");
|
||||
loop {
|
||||
input.clear();
|
||||
stdin.lock().read_line(&mut input).ok()?;
|
||||
if stdin.lock().read_line(&mut input).is_err() {
|
||||
return AgentMove::Skip;
|
||||
};
|
||||
|
||||
if input.to_lowercase().trim() == "skip" {
|
||||
// skips move
|
||||
return None;
|
||||
return AgentMove::Skip;
|
||||
}
|
||||
if input.to_lowercase().trim() == "back" {
|
||||
// skips move
|
||||
return AgentMove::Back;
|
||||
}
|
||||
|
||||
let got = input
|
||||
@ -53,7 +67,7 @@ impl Agent for ManualAgent {
|
||||
println!("Invalid move! Try again.");
|
||||
continue;
|
||||
}
|
||||
return Some(got.into());
|
||||
return AgentMove::CoordPair(got.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,8 +88,11 @@ pub struct RandomAgent {
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl Agent for RandomAgent {
|
||||
fn next_move(&mut self, board: &Board) -> Option<CoordPair> {
|
||||
board.possible_moves(self.color).choose(&mut rand::rng())
|
||||
fn next_move(&mut self, board: &Board) -> AgentMove {
|
||||
match board.possible_moves(self.color).choose(&mut rand::rng()) {
|
||||
Some(x) => AgentMove::CoordPair(x),
|
||||
None => AgentMove::Skip,
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
agent::Agent,
|
||||
agent::{Agent, AgentMove},
|
||||
logic::{FutureMoveConfig, FutureMoves},
|
||||
repr::{Board, CoordPair, Piece},
|
||||
repr::{Board, Piece},
|
||||
};
|
||||
|
||||
pub struct ComplexAgent {
|
||||
@ -20,13 +20,18 @@ impl ComplexAgent {
|
||||
}
|
||||
|
||||
impl Agent for ComplexAgent {
|
||||
fn next_move(&mut self, board: &Board) -> Option<CoordPair> {
|
||||
fn next_move(&mut self, board: &Board) -> AgentMove {
|
||||
self.future_moves.update_from_board(board);
|
||||
self.future_moves.generate();
|
||||
|
||||
self.future_moves
|
||||
match self
|
||||
.future_moves
|
||||
.best_move()
|
||||
.expect("FutureMoves has no move?")
|
||||
{
|
||||
Some(x) => AgentMove::CoordPair(x),
|
||||
None => AgentMove::Skip,
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
agent::Agent,
|
||||
agent::{Agent, AgentMove},
|
||||
repr::{Board, CoordPair, Piece, Winner},
|
||||
};
|
||||
|
||||
@ -70,41 +70,48 @@ impl GameInner {
|
||||
// when it comes to human input
|
||||
loop {
|
||||
let player_move = self.players[player_i].next_move(&self.board);
|
||||
self.move_log.push((player_move, player_color));
|
||||
|
||||
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);
|
||||
match player_move {
|
||||
AgentMove::CoordPair(coord) => {
|
||||
self.move_log.push((Some(coord), player_color));
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Invalid move by Player {}: {}. Move: {} State: {:?}",
|
||||
player_i, err, coord, self
|
||||
);
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Invalid move by Player {}: {}. Move: {} State: {:?}",
|
||||
player_i, err, coord, self
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.do_print {
|
||||
println!("Player {} did not make a move!", player_i);
|
||||
AgentMove::Back => {
|
||||
self.back();
|
||||
}
|
||||
|
||||
// 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() {
|
||||
AgentMove::Skip => {
|
||||
self.move_log.push((None, player_color));
|
||||
if self.do_print {
|
||||
println!(
|
||||
"Player {} has possible moves, but skipped (invalid)",
|
||||
player_i
|
||||
);
|
||||
println!("Player {} did not make a move!", player_i);
|
||||
}
|
||||
continue;
|
||||
|
||||
// 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
|
||||
}
|
||||
return; // No valid move available
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,4 +153,19 @@ impl GameInner {
|
||||
self.game_loop();
|
||||
self.board.game_winner()
|
||||
}
|
||||
|
||||
pub fn back(&mut self) {
|
||||
if self.move_log.is_empty() {
|
||||
println!("This is the initial board state!");
|
||||
return;
|
||||
}
|
||||
self.move_log.pop();
|
||||
self.board = self.first_board;
|
||||
for &(l, p) in &self.move_log {
|
||||
if let Some(loc) = l {
|
||||
self.board.place(loc, p).expect("unable to go backwards");
|
||||
}
|
||||
}
|
||||
println!("{}", self);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user