use std::error::Error;
use std::fmt::Debug;
use super::Node;
use crate::prelude::{Game, Random, SearchChoose};
use crate::search::random::RandomError;
pub trait Playout<const N: usize, G: Game<N>, T>
where
G::State: Clone,
G::Player: Clone,
Self::Error: From<G::Error>,
T: Debug,
{
type Error: Error;
fn one_move(&self, game: &G, state: &G::State) -> Result<G::State, Self::Error>;
fn until_end(
&self,
game: &G,
node: &Node<N, G::State, T>,
) -> Result<[G::Score; N], Self::Error> {
log::debug!("running the playout strategy from {:?}", node);
let mut state = node.state.clone();
while !game.is_complete(&state)? {
state = self.one_move(game, &state)?;
}
Ok(game
.players()
.iter()
.map(|p| game.score(p, &state))
.collect::<Result<Vec<_>, _>>()?
.try_into()
.unwrap_or_else(|_| panic!("Couldn't collect to an {N}-length array???")))
}
}
impl<const N: usize, G: Game<N>, T> Playout<N, G, T> for Random
where
G::Action: Clone + Debug,
G::State: Clone,
G::Player: Clone,
T: Debug,
{
type Error = RandomError<N, G>;
fn one_move(&self, game: &G, state: &G::State) -> Result<G::State, Self::Error> {
let Some(action) = self.choose_action(game, state)? else {
return Ok(state.clone());
};
Ok(game.do_action(&action, state.clone())?)
}
}