1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::summary::Summary;
use crate::{Move, PerPlayer, PlayerIndex, Plies, Transcript};
/// A record of moves played during a game.
///
/// The canonical implementations of this trait are:
/// - [`Profile`](crate::Profile) for simultaneous games
/// - [`Transcript`](crate::Transcript) for sequential games
/// - [`History`](crate::History) for repeated games
pub trait Record<M: Move, const P: usize> {
/// An iterator over the played moves in this record.
///
/// A [ply](https://en.wikipedia.org/wiki/Ply_(game_theory)) typically refers only to a move
/// played in a sequential game. For records of simultaneous games this iterator will return
/// the move played by each player in order of their player index.
fn plies(&self) -> Plies<M, P>;
/// A summary of the number of moves in this record.
fn summary(&self) -> Summary<P>;
/// Get the moves played in the form of a transcript.
fn to_transcript(&self) -> Transcript<M, P> {
self.plies().into_transcript()
}
/// An iterator over all moves by chance.
fn played_moves_by_chance(&self) -> PlayedMoves<M> {
let move_iter = self
.plies()
.filter(move |ply| ply.player.is_none())
.map(|ply| ply.the_move);
PlayedMoves::new(move_iter)
}
/// An iterator over all moves by a particular player.
fn played_moves_by_player(&self, player: PlayerIndex<P>) -> PlayedMoves<M> {
let move_iter = self
.plies()
.filter(move |ply| ply.player == Some(player))
.map(|ply| ply.the_move);
PlayedMoves::new(move_iter)
}
/// Iterators over the moves by each player.
fn played_moves_per_player(&self) -> PerPlayer<PlayedMoves<M>, P> {
PerPlayer::generate(|player| self.played_moves_by_player(player))
}
}
/// An iterator over the moves played in a game.
///
/// This iterator is double-ended, so it can be traversed forward (starting from the beginning of
/// the game) or backward (starting from the most recent move).
pub struct PlayedMoves<'a, M> {
iterator: Box<dyn DoubleEndedIterator<Item = M> + 'a>,
}
impl<'a, M: Move> PlayedMoves<'a, M> {
/// Construct a new played move iterator for a game in which no moves have been played.
pub fn empty() -> Self {
PlayedMoves {
iterator: Box::new(std::iter::empty()),
}
}
/// Construct a new played move iterator for a game in which only one move has been played.
pub fn from_move(the_move: M) -> Self {
PlayedMoves {
iterator: Box::new(std::iter::once(the_move)),
}
}
/// Construct a new played move iterator from a double-ended iterator of moves.
pub fn new(iterator: impl DoubleEndedIterator<Item = M> + 'a) -> Self {
PlayedMoves {
iterator: Box::new(iterator),
}
}
/// Construct a new played move iterator from a vector of moves.
pub fn from_vec(moves: Vec<M>) -> Self {
PlayedMoves::new(moves.into_iter())
}
}
impl<'a, M> Iterator for PlayedMoves<'a, M> {
type Item = M;
fn next(&mut self) -> Option<Self::Item> {
self.iterator.next()
}
}
impl<'a, M> DoubleEndedIterator for PlayedMoves<'a, M> {
fn next_back(&mut self) -> Option<Self::Item> {
self.iterator.next_back()
}
}