pub mod maxn;
pub mod mcts;
pub mod random;
pub mod user_input;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::error::Error;
use std::hash::Hash;
use crate::game::Game;
#[cfg(doc)]
use crate::game::{Action, State};
pub trait SearchScore<const N: usize, G: Game<N>>
where
G::Action: Hash + Eq,
{
type Error: SearchError;
type Score: PartialOrd;
fn score_actions(
&self,
game: &G,
state: &G::State,
) -> Result<HashMap<G::Action, Self::Score>, Self::Error>;
}
pub trait SearchRank<const N: usize, G: Game<N>> {
type Error: SearchError;
fn rank_actions(&self, game: &G, state: &G::State) -> Result<Vec<G::Action>, Self::Error>;
}
impl<const N: usize, G, T> SearchRank<N, G> for T
where
G: Game<N>,
G::Action: Hash + Eq,
T: SearchScore<N, G> + InternalSearch,
{
type Error = <T as SearchScore<N, G>>::Error;
fn rank_actions(&self, game: &G, state: &G::State) -> Result<Vec<G::Action>, Self::Error> {
let scores = self.score_actions(game, state)?;
let mut score_pairs = scores.into_iter().collect::<Vec<_>>();
score_pairs.sort_unstable_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal));
Ok(score_pairs.into_iter().map(|(action, _)| action).collect())
}
}
pub trait SearchChoose<const N: usize, G: Game<N>> {
type Error: SearchError;
fn choose_action(&self, game: &G, state: &G::State) -> Result<Option<G::Action>, Self::Error>;
}
impl<const N: usize, G, T> SearchChoose<N, G> for T
where
G: Game<N>,
G::Action: Hash + Eq,
T: SearchRank<N, G> + InternalSearch,
{
type Error = <T as SearchRank<N, G>>::Error;
fn choose_action(&self, game: &G, state: &G::State) -> Result<Option<G::Action>, Self::Error> {
let mut rank = self.rank_actions(game, state)?;
Ok(rank.pop())
}
}
trait InternalSearch {}
pub trait SearchError: Error {}