use std::cmp::Ordering; use anyhow::{bail, Result}; use termion::color::{self}; mod agents; mod board; mod util; use board::Board; use util::{Player, Symb}; fn play( maxi: &mut dyn agents::MaximizerAgent, maxi_player: Player, mini: &mut dyn agents::MinimizerAgent, mini_player: Player, ) -> Result { let mut board = Board::new(); let mut is_first_turn = true; let mut is_maxi_turn = true; while !board.is_done() { // Print board println!( "\r{}{}{}{}", " ".repeat(6), if is_first_turn { '╓' } else { '║' }, board.prettyprint()?, if is_first_turn { '╖' } else { '║' }, ); is_first_turn = false; // Take action let action = if is_maxi_turn { maxi.step_max(&board)? } else { mini.step_min(&board)? }; if !board.play( action, if is_maxi_turn { maxi_player } else { mini_player }, ) { bail!("agent made invalid move") } is_maxi_turn = !is_maxi_turn; } println!("\r{}║{}║", " ".repeat(6), board.prettyprint()?); println!("\r{}╙{}╜", " ".repeat(6), " ".repeat(board.size())); Ok(board) } fn main() -> Result<()> { rayon::ThreadPoolBuilder::new() .num_threads(4) .build_global() .unwrap(); let mut maxi = agents::PlayerAgent::new(Player::Human); let mut mini = agents::Diffuse {}; let a = play(&mut maxi, Player::Human, &mut mini, Player::Computer)?; 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(()); } 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), ); } } Ok(()) }