use std::marker::PhantomData;
use crate::{
Move, Outcome, Past, Payoff, PlayerIndex, Plies, Profile, Record, SequentialOutcome,
SimultaneousOutcome, State, Summary, Transcript, Utility,
};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct History<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> {
outcomes: im::Vector<O>,
score: Payoff<U, P>,
summary: Summary<P>,
move_type: PhantomData<M>,
}
impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> History<M, U, O, P> {
pub fn empty() -> Self {
History::default()
}
pub fn add(&mut self, outcome: O) -> &O {
self.score = self.score + *outcome.payoff();
self.summary = self.summary + outcome.record().summary();
self.outcomes.push_back(outcome);
self.outcomes.back().unwrap()
}
pub fn outcomes(&self) -> Past<&O> {
Past::from_iter(self.outcomes.len(), self.outcomes.iter())
}
pub fn records(&self) -> Past<&<O as Outcome<M, U, P>>::Record> {
Past::from_iter(
self.outcomes.len(),
self.outcomes().map(|outcome| outcome.record()),
)
}
pub fn payoffs(&self) -> Past<&Payoff<U, P>> {
Past::from_iter(
self.outcomes.len(),
self.outcomes().map(|outcome| outcome.payoff()),
)
}
pub fn score(&self) -> &Payoff<U, P> {
&self.score
}
}
impl<M: Move, U: Utility, const P: usize> History<M, U, SimultaneousOutcome<M, U, P>, P> {
pub fn profiles(&self) -> Past<&Profile<M, P>> {
Past::from_iter(
self.outcomes.len(),
self.outcomes().map(|outcome| outcome.profile()),
)
}
pub fn moves_for_player(&self, player: PlayerIndex<P>) -> Past<M> {
Past::from_iter(
self.outcomes.len(),
self.profiles().map(move |profile| profile[player]),
)
}
}
impl<S: State, M: Move, U: Utility, const P: usize>
History<M, U, SequentialOutcome<S, M, U, P>, P>
{
pub fn transcripts(&self) -> Past<&Transcript<M, P>> {
Past::from_iter(
self.outcomes.len(),
self.outcomes().map(|outcome| outcome.transcript()),
)
}
}
impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Default for History<M, U, O, P> {
fn default() -> Self {
History {
outcomes: im::Vector::new(),
score: Payoff::zeros(),
summary: Summary::empty(),
move_type: PhantomData,
}
}
}
impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Record<M, P>
for History<M, U, O, P>
{
fn plies(&self) -> Plies<M, P> {
Past::from_iter(
self.outcomes.len(),
self.outcomes
.iter()
.flat_map(|outcome| outcome.record().plies()),
)
}
fn summary(&self) -> Summary<P> {
self.summary
}
}
impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Outcome<M, U, P>
for History<M, U, O, P>
{
type Record = Self;
fn record(&self) -> &Self {
self
}
fn payoff(&self) -> &Payoff<U, P> {
&self.score
}
}