use crate::repr::{Board, Coord, Piece}; use rand::prelude::*; use std::io; use std::io::prelude::*; #[allow(dead_code)] pub trait Agent { /// Returns the move of an [`Agent`] fn next_move(&mut self, board: &Board) -> Option<(Coord, Coord)>; /// Returns the name of the [`Agent`] fn name(&self) -> &'static str; /// Returns the color the [`Agent`] is playing fn color(&self) -> Piece; } /// An [`Agent`] which a user controls pub struct ManualAgent { color: Piece, } impl ManualAgent { #[allow(dead_code)] pub const fn new(color: Piece) -> Self { Self { color } } } #[allow(dead_code)] impl Agent for ManualAgent { fn next_move(&mut self, board: &Board) -> Option<(Coord, Coord)> { let stdin = io::stdin(); let mut input = String::new(); println!("Your turn! ('Skip' to skip)"); loop { input.clear(); stdin.lock().read_line(&mut input).ok()?; if input.to_lowercase().trim() == "skip" { // skips move return None; } let got = input .split_whitespace() .map(str::parse) .map(Result::ok) .collect::>>() .and_then(|x| -> Option<[Coord; 2]> { x.try_into().ok() }) .map(|x| (x[0], x[1])); if let Some(got) = got { if board.possible_moves(self.color).all(|x| x != got) { println!("Invalid move! Try again."); continue; } return Some(got); } } } fn name(&self) -> &'static str { "Manual Agent" } fn color(&self) -> Piece { self.color } } /// An [`Agent`] that just makes a random move that is legal pub struct RandomAgent { color: Piece, } #[allow(dead_code)] impl Agent for RandomAgent { fn next_move(&mut self, board: &Board) -> Option<(Coord, Coord)> { board.possible_moves(self.color).choose(&mut rand::rng()) } fn name(&self) -> &'static str { "Random Agent" } fn color(&self) -> Piece { self.color } } impl RandomAgent { #[allow(dead_code)] pub const fn new(color: Piece) -> Self { Self { color } } }