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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use crate::{PerPlayer, PlayerIndex};
use std::ops::Add;
/// Tracks the number of moves played so far in a game.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Summary<const P: usize> {
/// The number of moves played by each player.
players: PerPlayer<usize, P>,
/// The number of moves played by chance.
chance: usize,
/// The total number of moves played.
total: usize,
}
impl<const P: usize> Default for Summary<P> {
fn default() -> Self {
Summary {
players: PerPlayer::init_with(0),
chance: 0,
total: 0,
}
}
}
impl<const P: usize> Summary<P> {
/// Construct a new move summary with the given move counts for each player and chance.
///
/// # Example
/// ```
/// use t4t::{PerPlayer, Summary};
///
/// let s = Summary::new(PerPlayer::new([1, 2, 3]), 4);
///
/// assert_eq!(s.number_of_moves_per_player(), PerPlayer::new([1, 2, 3]));
/// assert_eq!(s.number_of_moves_by_chance(), 4);
/// assert_eq!(s.total_number_of_moves(), 10);
pub fn new(players: PerPlayer<usize, P>, chance: usize) -> Self {
let total = players.iter().sum::<usize>() + chance;
Summary {
players,
chance,
total,
}
}
/// Construct a new move summary with all counts set to zero.
///
/// # Example
/// ```
/// use t4t::{PerPlayer, Summary};
///
/// let s: Summary<2> = Summary::empty();
///
/// assert_eq!(s.number_of_moves_per_player(), PerPlayer::new([0, 0]));
/// assert_eq!(s.number_of_moves_by_chance(), 0);
/// assert_eq!(s.total_number_of_moves(), 0);
pub fn empty() -> Self {
Summary::default()
}
/// Construct a move summary for a completed simultaneous game where each player has played one
/// move.
///
/// # Example
/// ```
/// use t4t::{PerPlayer, Summary};
///
/// let s: Summary<4> = Summary::simultaneous();
///
/// assert_eq!(s.number_of_moves_per_player(), PerPlayer::new([1, 1, 1, 1]));
/// assert_eq!(s.number_of_moves_by_chance(), 0);
/// assert_eq!(s.total_number_of_moves(), 4);
pub fn simultaneous() -> Self {
Summary {
players: PerPlayer::init_with(1),
chance: 0,
total: P,
}
}
/// The number of moves made by each player.
pub fn number_of_moves_per_player(&self) -> PerPlayer<usize, P> {
self.players
}
/// The number of moves made by a particular player.
pub fn number_of_moves_by_player(&self, player: PlayerIndex<P>) -> usize {
self.players[player]
}
/// The number of moves made by chance.
pub fn number_of_moves_by_chance(&self) -> usize {
self.chance
}
/// The total number of moves.
pub fn total_number_of_moves(&self) -> usize {
self.total
}
/// Increment the move count for the given player (`Some`) or chance (`None`).
pub fn increment_moves_by(&mut self, player: Option<PlayerIndex<P>>) {
match player {
Some(p) => self.players[p] += 1,
None => self.chance += 1,
}
self.total += 1;
}
/// Increment the move count for the given player.
///
/// # Examples
/// ```
/// use t4t::{for3, PerPlayer, Summary};
///
/// let mut s = Summary::empty();
/// s.increment_moves_by_player(for3::P0);
/// s.increment_moves_by_player(for3::P2);
/// s.increment_moves_by_player(for3::P0);
///
/// assert_eq!(s.total_number_of_moves(), 3);
/// assert_eq!(s.number_of_moves_by_player(for3::P0), 2);
/// assert_eq!(s.number_of_moves_by_player(for3::P1), 0);
/// assert_eq!(s.number_of_moves_by_player(for3::P2), 1);
/// ```
pub fn increment_moves_by_player(&mut self, player: PlayerIndex<P>) {
self.increment_moves_by(Some(player))
}
/// Increment the move count for chance.
///
/// # Examples
/// ```
/// use t4t::{for2, PerPlayer, Summary};
///
/// let mut s = Summary::empty();
/// s.increment_moves_by_chance();
/// s.increment_moves_by_player(for2::P1);
/// s.increment_moves_by_chance();
///
/// assert_eq!(s.total_number_of_moves(), 3);
/// assert_eq!(s.number_of_moves_by_player(for2::P0), 0);
/// assert_eq!(s.number_of_moves_by_player(for2::P1), 1);
/// assert_eq!(s.number_of_moves_by_chance(), 2);
/// ```
pub fn increment_moves_by_chance(&mut self) {
self.increment_moves_by(None)
}
}
impl<const P: usize> Add<Self> for Summary<P> {
type Output = Self;
/// Combine two summaries by adding all the corresponding move counts.
///
/// # Examples
/// ```
/// use t4t::{PerPlayer, Summary};
///
/// assert_eq!(
/// Summary::new(PerPlayer::new([1, 2, 3]), 4) + Summary::new(PerPlayer::new([0, 10, 20]), 30),
/// Summary::new(PerPlayer::new([1, 12, 23]), 34)
/// );
/// ```
fn add(self, other: Self) -> Self {
Summary {
players: self.players.map_with_index(|p, n| n + other.players[p]),
chance: self.chance + other.chance,
total: self.total + other.total,
}
}
}