t4t/
history.rs

1use std::marker::PhantomData;
2
3use crate::{
4    Move, Outcome, Past, Payoff, PlayerIndex, Plies, Profile, Record, SequentialOutcome,
5    SimultaneousOutcome, State, Summary, Transcript, Utility,
6};
7
8/// For repeated games, a history of previously played games.
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub struct History<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> {
11    outcomes: im::Vector<O>,
12    score: Payoff<U, P>,
13    summary: Summary<P>,
14    move_type: PhantomData<M>,
15}
16
17impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> History<M, U, O, P> {
18    /// Construct a new, empty history.
19    pub fn empty() -> Self {
20        History::default()
21    }
22
23    /// Update the history by adding a new game outcome. Returns a reference to the newly added
24    /// outcome.
25    pub fn add(&mut self, outcome: O) -> &O {
26        self.score = self.score + *outcome.payoff();
27        self.summary = self.summary + outcome.record().summary();
28        self.outcomes.push_back(outcome);
29        self.outcomes.back().unwrap()
30    }
31
32    /// Get an iterator over the outcomes of previously played games.
33    pub fn outcomes(&self) -> Past<&O> {
34        Past::from_iter(self.outcomes.len(), self.outcomes.iter())
35    }
36
37    /// Get an iterator over the move records of previously played games.
38    pub fn records(&self) -> Past<&<O as Outcome<M, U, P>>::Record> {
39        Past::from_iter(
40            self.outcomes.len(),
41            self.outcomes().map(|outcome| outcome.record()),
42        )
43    }
44
45    /// Get an iterator over the payoffs of previously played games.
46    pub fn payoffs(&self) -> Past<&Payoff<U, P>> {
47        Past::from_iter(
48            self.outcomes.len(),
49            self.outcomes().map(|outcome| outcome.payoff()),
50        )
51    }
52
53    /// Get the cumulative score of all previously played games.
54    pub fn score(&self) -> &Payoff<U, P> {
55        &self.score
56    }
57}
58
59impl<M: Move, U: Utility, const P: usize> History<M, U, SimultaneousOutcome<M, U, P>, P> {
60    /// Get an iterator over the profiles of previously played games.
61    pub fn profiles(&self) -> Past<&Profile<M, P>> {
62        Past::from_iter(
63            self.outcomes.len(),
64            self.outcomes().map(|outcome| outcome.profile()),
65        )
66    }
67
68    /// Get an iterator over all moves played by a given player.
69    pub fn moves_for_player(&self, player: PlayerIndex<P>) -> Past<M> {
70        Past::from_iter(
71            self.outcomes.len(),
72            self.profiles().map(move |profile| profile[player]),
73        )
74    }
75}
76
77impl<S: State, M: Move, U: Utility, const P: usize>
78    History<M, U, SequentialOutcome<S, M, U, P>, P>
79{
80    /// Get an iterator over the transcripts of previously played games.
81    pub fn transcripts(&self) -> Past<&Transcript<M, P>> {
82        Past::from_iter(
83            self.outcomes.len(),
84            self.outcomes().map(|outcome| outcome.transcript()),
85        )
86    }
87}
88
89impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Default for History<M, U, O, P> {
90    fn default() -> Self {
91        History {
92            outcomes: im::Vector::new(),
93            score: Payoff::zeros(),
94            summary: Summary::empty(),
95            move_type: PhantomData,
96        }
97    }
98}
99
100impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Record<M, P>
101    for History<M, U, O, P>
102{
103    fn plies(&self) -> Plies<M, P> {
104        Past::from_iter(
105            self.outcomes.len(),
106            self.outcomes
107                .iter()
108                .flat_map(|outcome| outcome.record().plies()),
109        )
110    }
111
112    fn summary(&self) -> Summary<P> {
113        self.summary
114    }
115}
116
117impl<M: Move, U: Utility, O: Outcome<M, U, P>, const P: usize> Outcome<M, U, P>
118    for History<M, U, O, P>
119{
120    type Record = Self;
121
122    fn record(&self) -> &Self {
123        self
124    }
125
126    fn payoff(&self) -> &Payoff<U, P> {
127        &self.score
128    }
129}