use std::error::Error;
use std::fmt::Debug;
#[derive(Debug, thiserror::Error)]
pub enum GeneralGameError {
#[error("Unknown player: {0}")]
UnknownPlayer(String),
}
impl GameError for GeneralGameError {}
pub trait Game<const N: usize>: Debug {
type State: State<N, Self>;
type Player: Player<N, Self> + Eq + Debug;
type Action: Action<N, Self>;
type Score: Debug;
type Error: GameError;
fn players(&self) -> &[Self::Player; N];
fn player_index(&self, player: &Self::Player) -> Result<usize, Self::Error> {
Ok(self
.players()
.iter()
.position(|p| p == player)
.ok_or_else(|| GeneralGameError::UnknownPlayer(format!("{:?}", player)))?)
}
fn active_player(&self, state: &Self::State) -> Result<&Self::Player, Self::Error>;
fn active_player_index(&self, state: &Self::State) -> Result<usize, Self::Error> {
self.player_index(self.active_player(state)?)
}
fn available_actions(&self, state: &Self::State) -> Result<Vec<Self::Action>, Self::Error>;
fn do_action(
&self,
action: &Self::Action,
state: Self::State,
) -> Result<Self::State, Self::Error>;
fn score(&self, player: &Self::Player, state: &Self::State)
-> Result<Self::Score, Self::Error>;
fn is_complete(&self, state: &Self::State) -> Result<bool, Self::Error>;
}
pub trait GameError: Error + From<GeneralGameError> {}
pub trait State<const N: usize, G: Game<N> + ?Sized>: Debug {}
pub trait Player<const N: usize, G: Game<N, Player = Self> + ?Sized> {}
pub trait Heuristic<const N: usize, G: Game<N, Player = Self> + ?Sized>: Player<N, G> {
type Error: Error;
fn heuristic(
&self,
game: &G,
state: &<G as Game<N>>::State,
) -> Result<<G as Game<N>>::Score, Self::Error>;
}
pub trait Action<const N: usize, G: Game<N, Action = Self> + ?Sized> {}