2024-03-05 10:18:34 -08:00
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
2024-03-04 17:46:05 -08:00
|
|
|
use anyhow::{bail, Result};
|
|
|
|
use termion::color::{self};
|
2024-02-26 08:54:35 -08:00
|
|
|
|
2024-03-03 21:48:33 -08:00
|
|
|
mod agents;
|
2024-02-26 08:54:35 -08:00
|
|
|
mod board;
|
|
|
|
mod util;
|
|
|
|
use board::Board;
|
|
|
|
use util::{Player, Symb};
|
|
|
|
|
|
|
|
fn play(
|
2024-03-04 17:46:05 -08:00
|
|
|
maxi: &mut dyn agents::MaximizerAgent,
|
2024-03-04 18:46:16 -08:00
|
|
|
maxi_player: Player,
|
2024-03-04 17:46:05 -08:00
|
|
|
mini: &mut dyn agents::MinimizerAgent,
|
2024-03-04 18:46:16 -08:00
|
|
|
mini_player: Player,
|
2024-02-26 08:54:35 -08:00
|
|
|
) -> Result<Board> {
|
2024-03-04 17:46:05 -08:00
|
|
|
let mut board = Board::new();
|
|
|
|
let mut is_first_turn = true;
|
|
|
|
let mut is_maxi_turn = true;
|
2024-03-04 15:49:40 -08:00
|
|
|
|
2024-03-04 17:46:05 -08:00
|
|
|
while !board.is_done() {
|
|
|
|
// Print board
|
|
|
|
println!(
|
|
|
|
"\r{}{}{}{}",
|
|
|
|
" ".repeat(6),
|
|
|
|
if is_first_turn { '╓' } else { '║' },
|
2024-03-05 10:18:34 -08:00
|
|
|
board.prettyprint()?,
|
2024-03-04 17:46:05 -08:00
|
|
|
if is_first_turn { '╖' } else { '║' },
|
|
|
|
);
|
|
|
|
is_first_turn = false;
|
2024-02-26 08:54:35 -08:00
|
|
|
|
2024-03-04 17:46:05 -08:00
|
|
|
// Take action
|
|
|
|
let action = if is_maxi_turn {
|
|
|
|
maxi.step_max(&board)?
|
2024-02-26 08:54:35 -08:00
|
|
|
} else {
|
2024-03-04 17:46:05 -08:00
|
|
|
mini.step_min(&board)?
|
2024-02-26 08:54:35 -08:00
|
|
|
};
|
|
|
|
|
2024-03-04 17:46:05 -08:00
|
|
|
if !board.play(
|
|
|
|
action,
|
|
|
|
if is_maxi_turn {
|
2024-03-04 18:46:16 -08:00
|
|
|
maxi_player
|
2024-03-04 15:49:40 -08:00
|
|
|
} else {
|
2024-03-04 18:46:16 -08:00
|
|
|
mini_player
|
2024-03-04 15:49:40 -08:00
|
|
|
},
|
2024-03-04 17:46:05 -08:00
|
|
|
) {
|
|
|
|
bail!("agent made invalid move")
|
2024-02-26 08:54:35 -08:00
|
|
|
}
|
2024-03-04 18:46:16 -08:00
|
|
|
|
|
|
|
is_maxi_turn = !is_maxi_turn;
|
2024-02-26 08:54:35 -08:00
|
|
|
}
|
|
|
|
|
2024-03-05 10:18:34 -08:00
|
|
|
println!("\r{}║{}║", " ".repeat(6), board.prettyprint()?);
|
2024-03-04 17:46:05 -08:00
|
|
|
println!("\r{}╙{}╜", " ".repeat(6), " ".repeat(board.size()));
|
|
|
|
Ok(board)
|
2024-02-26 08:54:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> Result<()> {
|
2024-03-04 18:46:16 -08:00
|
|
|
rayon::ThreadPoolBuilder::new()
|
|
|
|
.num_threads(4)
|
|
|
|
.build_global()
|
|
|
|
.unwrap();
|
|
|
|
|
2024-03-04 17:46:05 -08:00
|
|
|
let mut maxi = agents::PlayerAgent::new(Player::Human);
|
2024-03-05 10:18:34 -08:00
|
|
|
let mut mini = agents::Diffuse {};
|
2024-02-26 08:54:35 -08:00
|
|
|
|
2024-03-04 18:46:16 -08:00
|
|
|
let a = play(&mut maxi, Player::Human, &mut mini, Player::Computer)?;
|
2024-02-26 08:54:35 -08:00
|
|
|
if a.is_done() {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Your score:{} {:.2}\n\n",
|
|
|
|
color::Fg(Player::Human.color()),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
a.evaluate().unwrap()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Quitting{}\r\n",
|
|
|
|
color::Fg(color::Red),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
2024-03-05 10:18:34 -08:00
|
|
|
|
|
|
|
let mut mini = agents::PlayerAgent::new(Player::Human);
|
|
|
|
let mut maxi = agents::Diffuse {};
|
|
|
|
|
|
|
|
let b = play(&mut maxi, Player::Computer, &mut mini, Player::Human)?;
|
|
|
|
if b.is_done() {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Computer score:{} {:.2}\n\n",
|
|
|
|
color::Fg(Player::Human.color()),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
b.evaluate().unwrap()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Quitting{}\r\n",
|
|
|
|
color::Fg(color::Red),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
);
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
match a.evaluate().partial_cmp(&b.evaluate()) {
|
|
|
|
Some(Ordering::Equal) => {
|
|
|
|
println!("\r\nTie");
|
|
|
|
}
|
|
|
|
Some(Ordering::Greater) => {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Human wins{}",
|
|
|
|
color::Fg(Player::Human.color()),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Some(Ordering::Less) => {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Computer wins{}",
|
|
|
|
color::Fg(Player::Computer.color()),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
println!(
|
|
|
|
"\r\n{}Error{}",
|
|
|
|
color::Fg(color::Red),
|
|
|
|
color::Fg(color::Reset),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 08:54:35 -08:00
|
|
|
Ok(())
|
|
|
|
}
|