1use std::{fmt, slice::{Iter, IterMut}, vec::IntoIter};
2
3use crate::{Frame, ScoreProvider, TenPinScoreProvider};
4
5#[derive(Clone, Debug, Default, Hash)]
7pub struct Game {
8 pub frame_count: usize,
10 frames: Vec<Frame>
12}
13
14impl Game {
15 pub fn new(frames: Vec<Frame>) -> Self {
17 Self {
18 frame_count: 10,
19 frames
20 }
21 }
22
23 pub fn with_frame_count(frame_count: usize, frames: Vec<Frame>) -> Self {
25 Self {
26 frame_count,
27 frames
28 }
29 }
30
31 pub fn iter(&self) -> Iter<Frame> {
33 self.frames.iter()
34 }
35
36 pub fn iter_mut(&mut self) -> IterMut<Frame> {
38 self.frames.iter_mut()
39 }
40
41 pub fn into_iter(self) -> IntoIter<Frame> {
43 self.frames.into_iter()
44 }
45
46 pub fn add_frame(&mut self, frame: Frame) {
48 self.frames.push(frame);
49 }
50
51 pub fn remove_frame(&mut self, index: usize) -> Frame {
53 self.frames.remove(index)
54 }
55
56 pub fn frame(&self, index: usize) -> Option<&Frame> {
58 self.frames.get(index)
59 }
60
61 pub fn set_frame(&mut self, index: usize, frame: Frame) {
63 self.frames[index] = frame;
64 }
65
66 pub fn is_perfect(&self) -> bool {
68 self.score() == 300
69 }
70
71 pub fn computed_with_provider(&self, provider: impl ScoreProvider) -> Vec<usize> {
73 provider.computed(&self)
74 }
75
76 pub fn computed(&self) -> Vec<usize> {
78 self.computed_with_provider(TenPinScoreProvider)
79 }
80
81 pub fn score_with_provider(&self, provider: impl ScoreProvider) -> usize {
83 provider.score(&self)
84 }
85
86 pub fn score(&self) -> usize {
88 self.score_with_provider(TenPinScoreProvider)
89 }
90
91 pub fn max_with_provider(&self, provider: impl ScoreProvider) -> usize {
93 provider.max(&self, &provider)
94 }
95
96 pub fn max(&self) -> usize {
98 self.max_with_provider(TenPinScoreProvider)
99 }
100}
101
102impl fmt::Display for Game {
104 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
105 write!(formatter, "Game ({} frame{}) [\n{:#?}\n]", self.frame_count, if self.frame_count == 1 { "" } else { "s" }, self.frames)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::{Frame, Game, Score};
112
113 #[test]
114 fn game_300() {
115 let mut game = Game::new(vec![Frame::strike(); 9]);
116 game.frames.push(Frame::triple_strike());
117
118 assert_eq!(game.score(), 300);
119 }
120
121 #[test]
122 fn game_299() {
123 let mut game = Game::new(vec![Frame::strike(); 9]);
124 game.frames.push(Frame::with_bonus(Score::STRIKE, Score::STRIKE, Score::PINS(9)));
125
126 assert_eq!(game.score(), 299);
127 }
128
129 #[test]
130 fn game_290_0() {
131 let mut game = Game::new(vec![Frame::strike(); 9]);
132 game.frames.push(Frame::with_bonus(Score::STRIKE, Score::STRIKE, Score::PINS(0)));
133
134 assert_eq!(game.score(), 290);
135 }
136
137 #[test]
138 fn game_290_1() {
139 let mut game = Game::new(vec![Frame::spare(9)]);
140 game.frames.append(&mut vec![Frame::strike(); 8]);
141 game.frames.push(Frame::triple_strike());
142
143 assert_eq!(game.score(), 290);
144 }
145
146 #[test]
147 fn game_289() {
148 let mut game = Game::new(vec![Frame::strike(); 9]);
149 game.frames.push(Frame::with_bonus(Score::STRIKE, Score::PINS(9), Score::SPARE));
150
151 assert_eq!(game.score(), 289);
152 }
153
154 #[test]
155 fn game_280() {
156 let mut game = Game::new(vec![Frame::strike(), Frame::spare(9)]);
157 game.frames.append(&mut vec![Frame::strike(); 7]);
158 game.frames.push(Frame::triple_strike());
159
160 assert_eq!(game.score(), 280);
161 }
162
163 #[test]
164 fn game_279_0() {
165 let mut game = Game::new(vec![Frame::strike(), Frame::strike(), Frame::spare(9)]);
166 game.frames.append(&mut vec![Frame::strike(); 6]);
167 game.frames.push(Frame::triple_strike());
168
169 assert_eq!(game.score(), 279);
170 }
171
172 #[test]
173 fn game_279_1() {
174 let mut game = Game::new(vec![Frame::strike(); 9]);
175 game.frames.push(Frame::with_bonus(Score::PINS(9), Score::SPARE, Score::STRIKE));
176
177 assert_eq!(game.score(), 279);
178 }
179
180 #[test]
181 fn game_245() {
182 let game = Game::new(vec![Frame::new(Score::PINS(7), Score::PINS(1)), Frame::spare(9), Frame::strike(), Frame::spare(8), Frame::strike(), Frame::strike(), Frame::strike(), Frame::strike(), Frame::strike(), Frame::with_bonus(Score::STRIKE, Score::STRIKE, Score::PINS(7))]);
183 assert_eq!(game.score(), 245);
184 }
185
186 #[test]
187 fn game_223() {
188 let game = Game::new(vec![Frame::spare(9), Frame::spare(8), Frame::strike(), Frame::strike(), Frame::strike(), Frame::strike(), Frame::spare(8), Frame::strike(), Frame::strike(), Frame::new(Score::PINS(9), Score::PINS(0))]);
189 assert_eq!(game.score(), 223);
190 }
191
192 #[test]
193 fn game_200() {
194 let game = Game::new(vec![Frame::spare(9), Frame::strike(), Frame::spare(9), Frame::strike(), Frame::spare(9), Frame::strike(), Frame::spare(9), Frame::strike(), Frame::spare(9), Frame::with_bonus(Score::STRIKE, Score::PINS(9), Score::SPARE)]);
195 assert_eq!(game.score(), 200);
196 }
197
198 #[test]
199 fn game_0() {
200 let game = Game::new(vec![]);
201 assert_eq!(game.score(), 0);
202 }
203
204 #[test]
205 fn spare_strike() {
206 let game = Game::new(vec![Frame::spare(9), Frame::strike()]);
207 assert_eq!(game.score(), 30);
208 }
209
210 #[test]
211 fn spare_5() {
212 let game = Game::new(vec![Frame::spare(9), Frame::new(Score::PINS(5), Score::PINS(0))]);
213 assert_eq!(game.score(), 20);
214 }
215
216 #[test]
217 fn strike_5_2_1() {
218 let game = Game::new(vec![Frame::strike(), Frame::new(Score::PINS(5), Score::PINS(2)), Frame::new(Score::PINS(1), Score::PINS(0))]);
219 assert_eq!(game.score(), 25);
220 }
221
222 #[test]
223 fn spare_strike_spare() {
224 let game = Game::new(vec![Frame::spare(9), Frame::strike(), Frame::spare(9)]);
225 assert_eq!(game.score(), 50);
226 }
227
228 #[test]
229 fn max_300() {
230 let game = Game::new(vec![]);
231 assert_eq!(game.max(), 300);
232 }
233
234 #[test]
235 fn max_290() {
236 let game = Game::new(vec![Frame::new(Score::PINS(9), Score::EMPTY)]);
237 assert_eq!(game.max(), 290);
238 }
239
240 #[test]
241 fn max_289() {
242 let mut game = Game::new(vec![Frame::strike(); 9]);
243 game.frames.push(Frame::with_bonus(Score::STRIKE, Score::PINS(9), Score::EMPTY));
244
245 assert_eq!(game.max(), 289);
246 }
247
248 #[test]
249 fn max_279_0() {
250 let game = Game::new(vec![Frame::new(Score::PINS(9), Score::PINS(0))]);
251 assert_eq!(game.max(), 279);
252 }
253
254 #[test]
255 fn max_279_1() {
256 let game = Game::new(vec![Frame::strike(), Frame::strike(), Frame::new(Score::PINS(9), Score::EMPTY)]);
257 assert_eq!(game.max(), 279);
258 }
259}