2
|
1 |
// #[allow(dead_code, unused)] |
0
|
2 |
// vigyazz6! autplayer |
|
3 |
// |
|
4 |
|
1
|
5 |
use core::{fmt, panic}; |
3
|
6 |
use std::{collections::VecDeque, time::Instant, cmp::Reverse}; |
0
|
7 |
use rand::Rng; |
|
8 |
use std::mem; |
|
9 |
|
2
|
10 |
extern crate pretty_env_logger; |
|
11 |
#[macro_use] extern crate log; |
|
12 |
|
|
13 |
const GAME_ROUNDS: i32 = 1_000_000; |
|
14 |
|
0
|
15 |
fn main() { |
2
|
16 |
// RUST_LOG=debug cargo run |
|
17 |
pretty_env_logger::init(); |
|
18 |
info!("Program starting."); |
1
|
19 |
game(); |
2
|
20 |
info!("End of run."); |
0
|
21 |
} |
|
22 |
|
2
|
23 |
/*** Card ****/ |
0
|
24 |
#[derive(Debug)] |
|
25 |
struct Card { |
|
26 |
value: i8, |
|
27 |
points: i8, |
|
28 |
} |
|
29 |
|
|
30 |
impl Card { |
|
31 |
fn new(value: i8)->Self { |
|
32 |
|
|
33 |
let mut points = 0; |
|
34 |
if value % 10 == 5 { |
|
35 |
// ends with 5 = 2 point |
|
36 |
points = 2; |
|
37 |
// println!("*5 add 1, val={}, pt={}", value, points); |
|
38 |
} |
|
39 |
|
|
40 |
if value % 10 == 0 { |
|
41 |
// ends with 0 = 3 point |
|
42 |
points = 3; |
|
43 |
// println!("*0 add 2, val={}, pt={}", value, points); |
|
44 |
} |
|
45 |
|
|
46 |
if value % 10 == value / 10 { |
|
47 |
// same numbers = 5 points (55=7) |
|
48 |
points += 5; |
|
49 |
// println!("NN add 5, val={}, pt={}", value, points); |
|
50 |
} |
|
51 |
|
|
52 |
if points == 0 { |
|
53 |
points = 1; |
|
54 |
} |
|
55 |
|
|
56 |
Card { |
|
57 |
value, |
|
58 |
points, |
|
59 |
} |
|
60 |
} |
|
61 |
} |
|
62 |
|
|
63 |
impl fmt::Display for Card { |
|
64 |
fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result { |
|
65 |
write!(f, "(Card {}, points {})", self.value, self.points) |
|
66 |
} |
|
67 |
} |
|
68 |
|
|
69 |
impl PartialEq for Card { |
|
70 |
fn eq(&self, other: &Self) -> bool { |
|
71 |
self.value == other.value |
|
72 |
} |
|
73 |
} |
|
74 |
|
1
|
75 |
impl Eq for Card {} |
|
76 |
|
|
77 |
impl PartialOrd for Card { |
|
78 |
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
|
79 |
match self.value.partial_cmp(&other.value) { |
|
80 |
Some(core::cmp::Ordering::Equal) => {None} |
|
81 |
ord => return ord, |
|
82 |
} |
|
83 |
} |
|
84 |
} |
|
85 |
|
|
86 |
impl Ord for Card { |
|
87 |
fn cmp(&self, other: &Self) -> std::cmp::Ordering { |
|
88 |
self.value.cmp(&other.value) |
|
89 |
} |
|
90 |
} |
|
91 |
|
2
|
92 |
/*** Deck ****/ |
1
|
93 |
#[derive(Debug)] |
0
|
94 |
struct Deck { |
|
95 |
content: VecDeque<Card>, |
|
96 |
} |
|
97 |
|
|
98 |
impl Deck { |
|
99 |
fn new_empty() -> Self { |
2
|
100 |
debug!("Empty deck generated"); |
0
|
101 |
Deck { |
|
102 |
content: VecDeque::new(), |
|
103 |
} |
|
104 |
} |
|
105 |
|
|
106 |
fn new() -> Self { |
2
|
107 |
debug!("Full deck generated"); |
|
108 |
let content = (1..=104).into_iter().map( |n| Card::new(n) ).collect(); |
0
|
109 |
Deck { |
|
110 |
content, |
|
111 |
} |
|
112 |
} |
|
113 |
|
|
114 |
fn shuffle( &mut self ) { |
|
115 |
let mut rng = rand::thread_rng(); |
2
|
116 |
|
|
117 |
trace!("Deck before shuffle: len {}, {:?}", self.content.len(), self); |
|
118 |
debug!("Deck shuffled"); |
0
|
119 |
// shufflers: |
|
120 |
// * naive: swap cards n times |
|
121 |
// * kgb: half the deck, take 1..4 cards sequentially from each |
|
122 |
// * grin: take 1..6 from front and put at bottom |
|
123 |
|
|
124 |
// naive shuffle: exchange random cards |
1
|
125 |
for _i in 1..=500 { |
|
126 |
let c1 = rng.gen_range(0 .. self.content.len()); |
|
127 |
let c2 = rng.gen_range(0 .. self.content.len()); |
0
|
128 |
if c1 != c2 { |
|
129 |
self.content.swap(c1, c2); |
|
130 |
} |
|
131 |
} |
2
|
132 |
trace!("Deck after shuffle: len {}, {:?}", self.content.len(), self); |
0
|
133 |
} |
|
134 |
|
|
135 |
// get top card from deck |
|
136 |
fn pop( &mut self ) -> Option<Card> { |
|
137 |
self.content.pop_front() |
|
138 |
} |
|
139 |
|
|
140 |
// put a card into the bottom of the deck |
|
141 |
fn push( &mut self, c: Card ) { |
|
142 |
self.content.push_back(c); |
|
143 |
} |
|
144 |
|
2
|
145 |
fn push_cards( &mut self, cards: VecDeque<Card> ) { |
|
146 |
trace!("Collecting back, deck len is {}, cards {}", self.content.len(), cards.len()); |
|
147 |
cards.into_iter().for_each( |card| self.push(card) ); |
|
148 |
trace!("Deck len is {}", self.content.len()); |
|
149 |
} |
|
150 |
|
0
|
151 |
fn len( &self ) -> usize { |
|
152 |
self.content.len() |
|
153 |
} |
|
154 |
|
3
|
155 |
fn _get_nth( &mut self, n: usize ) -> Card { |
0
|
156 |
if let Some(c) = self.content.remove(n) { |
|
157 |
c |
|
158 |
} else { |
|
159 |
panic!("get_nth: index {} out of bounds ({})!", n, self.content.len()); |
|
160 |
} |
|
161 |
} |
|
162 |
} |
|
163 |
|
2
|
164 |
/*** Player ****/ |
1
|
165 |
#[derive(Debug)] |
0
|
166 |
struct Player { |
|
167 |
name: String, |
|
168 |
hand: Deck, |
2
|
169 |
pile: VecDeque<Card>, |
0
|
170 |
game_point: i32, |
|
171 |
total_point: i32, |
|
172 |
rows_busted: i32, |
2
|
173 |
wins: i32, |
0
|
174 |
} |
|
175 |
|
|
176 |
impl Player { |
|
177 |
fn new(name: String)->Self { |
2
|
178 |
debug!("Player {} created", name); |
0
|
179 |
Player { |
|
180 |
name, |
|
181 |
hand: Deck::new_empty(), |
2
|
182 |
pile: VecDeque::new(), |
0
|
183 |
game_point: 0, |
|
184 |
total_point: 0, |
|
185 |
rows_busted: 0, |
2
|
186 |
wins: 0, |
0
|
187 |
} |
|
188 |
} |
|
189 |
|
|
190 |
// get one card from th dealer |
|
191 |
fn get_card( &mut self, card: Card ) { |
2
|
192 |
trace!("Player {} got a card {:?}, cards before {}", self.name, &card, self.hand.len()); |
0
|
193 |
self.hand.push(card); |
|
194 |
} |
|
195 |
|
|
196 |
// throw a card from hand to the table |
|
197 |
fn throw_card( &mut self )->Card { |
|
198 |
if let Some(c) = self.hand.pop() { |
2
|
199 |
trace!("Player {} throws a card {:?}", self.name, &c); |
0
|
200 |
c |
|
201 |
} else { |
|
202 |
panic!("throw_card: Player {} has no card in hand!", self.name); |
|
203 |
} |
|
204 |
} |
|
205 |
|
|
206 |
// get a busted row of cards |
2
|
207 |
fn give_pile( &mut self, cards: VecDeque<Card> ) { |
0
|
208 |
for c in cards.into_iter() { |
|
209 |
self.game_point += c.points as i32; |
2
|
210 |
self.pile.push_back(c); |
0
|
211 |
} |
|
212 |
self.rows_busted += 1; |
2
|
213 |
trace!("Player {} got busted, count {}", self.name, &self.rows_busted); |
0
|
214 |
} |
|
215 |
|
|
216 |
// ask the player their score |
3
|
217 |
fn _tell_points( self ) -> i32 { |
0
|
218 |
self.game_point |
|
219 |
} |
|
220 |
|
2
|
221 |
fn inc_wins( &mut self ) { |
|
222 |
self.wins += 1; |
|
223 |
} |
|
224 |
|
0
|
225 |
// give back cards from the pile |
2
|
226 |
fn get_pile( &mut self ) -> VecDeque<Card> { |
|
227 |
trace!("Player {} gives back their pile", self.name); |
0
|
228 |
mem::take( &mut self.pile ) |
|
229 |
// same effect: |
|
230 |
// self.pile.drain(..).collect() |
|
231 |
|
|
232 |
// very cumbersome manual fiddling (also reverted...) |
|
233 |
/* let mut throw: Vec<Card> = Vec::new(); |
|
234 |
for _i in 0 .. self.pile.len() { |
|
235 |
throw.push( self.pile.pop().unwrap() ); |
|
236 |
} |
|
237 |
throw |
|
238 |
*/ |
|
239 |
} |
|
240 |
|
|
241 |
// I can do this just because I *throw away* c! |
|
242 |
// doesn't work if I want to use it. |
|
243 |
/* fn _gimme_pile(self)->Self { |
|
244 |
for c in &self.pile { |
|
245 |
println!("Throw {} ", c); |
|
246 |
} |
|
247 |
self |
|
248 |
} |
|
249 |
*/ |
|
250 |
fn close_round( &mut self ) { |
|
251 |
if self.hand.len() > 0 { |
|
252 |
panic!("Closing round when {} has {} cards in hand", self.name, self.hand.len()); |
|
253 |
} |
|
254 |
|
|
255 |
if self.pile.len() > 0 { |
|
256 |
panic!("Closing round when {} stil have pile with {} cards", self.name, self.pile.len()); |
|
257 |
} |
|
258 |
|
2
|
259 |
trace!("Player {} closing round; points={} total so far {}", self.name, self.game_point, self.total_point); |
0
|
260 |
self.total_point += self.game_point; |
|
261 |
self.game_point = 0; |
|
262 |
} |
2
|
263 |
|
|
264 |
// card too small: pick a row to collect from the rows |
|
265 |
fn pick_row_for_small_card( &self, rows: &Vec<Row>, playercard: &Card ) -> usize { |
|
266 |
trace!("Player {} picking a row for small card, card {:?}, rows {:?}", self.name, playercard, rows); |
|
267 |
|
|
268 |
// contains the summary point for each row |
3
|
269 |
let mut row_points = Vec::with_capacity(5); |
2
|
270 |
// the smallest row score |
|
271 |
let mut smallest = 999; |
|
272 |
// how many rows have the same smallest score |
|
273 |
let mut same_point = 0; |
|
274 |
// the first smallest row_id |
|
275 |
let mut smallest_rowid = 255; |
|
276 |
|
|
277 |
for rowid in 0 .. rows.len() { |
|
278 |
// DEBUG |
|
279 |
// println!("pick_row_for_small_card: rowlen {}, rowid {}", rows.len(), rowid); |
|
280 |
row_points.push( rows[rowid].sum() ); |
|
281 |
|
|
282 |
if row_points[rowid] < smallest { |
|
283 |
// we have a new smallest row |
|
284 |
smallest = row_points[rowid]; |
|
285 |
same_point = 0; |
|
286 |
smallest_rowid = rowid; |
|
287 |
|
|
288 |
} else if row_points[rowid] == smallest { |
|
289 |
// we have another row with same point as smallest |
|
290 |
same_point += 1; |
|
291 |
} |
|
292 |
} |
|
293 |
|
|
294 |
if same_point < 1 { |
|
295 |
// we have one smallest row |
|
296 |
smallest_rowid.try_into().unwrap() // it's tiny, will fit into u8 |
|
297 |
|
|
298 |
} else { |
|
299 |
// bored, we pick the first now anyway |
|
300 |
smallest_rowid.try_into().unwrap() |
|
301 |
} |
|
302 |
|
|
303 |
} |
0
|
304 |
} |
|
305 |
|
2
|
306 |
/*** Row ****/ |
0
|
307 |
// a row of cards on the table (max 5) |
1
|
308 |
#[derive(Debug)] |
0
|
309 |
struct Row { |
|
310 |
cards: VecDeque<Card>, |
|
311 |
} |
|
312 |
|
|
313 |
impl Row { |
|
314 |
const MAX_LEN: usize = 5; |
|
315 |
|
|
316 |
fn new() -> Self { |
|
317 |
Row { |
3
|
318 |
cards: VecDeque::with_capacity(5), |
0
|
319 |
} |
|
320 |
} |
|
321 |
|
|
322 |
fn push_or_collect( &mut self, card: Card ) -> Option<VecDeque<Card>> { |
2
|
323 |
trace!("Called push_or_collect on row {:?}", &self); |
0
|
324 |
if self.cards.len() < Self::MAX_LEN { |
2
|
325 |
trace!("Less than {} cards, putting at the end", Self::MAX_LEN); |
0
|
326 |
self.cards.push_back(card); |
|
327 |
None |
|
328 |
|
|
329 |
} else { |
2
|
330 |
trace!("Row is full, len {}, maxlen {}", self.cards.len(), Self::MAX_LEN); |
0
|
331 |
// row overflow |
|
332 |
let row_cards = mem::take( &mut self.cards ); |
|
333 |
self.cards.push_back(card); |
|
334 |
if self.cards.len() != 1 { |
|
335 |
panic!("New row must have one card, not {}", self.cards.len()); |
|
336 |
} |
|
337 |
Some(row_cards) |
|
338 |
} |
|
339 |
} |
|
340 |
|
2
|
341 |
fn take_row( &mut self ) -> VecDeque<Card> { |
|
342 |
// take cards and empty the row |
|
343 |
mem::take( &mut self.cards ) |
|
344 |
} |
|
345 |
|
0
|
346 |
fn last_card_value(&self) -> i8 { |
2
|
347 |
// println!("last_card_value: cards {:?}, len {}", self.cards, self.cards.len()); |
0
|
348 |
self.cards.get( self.cards.len()-1 ).unwrap().value |
|
349 |
} |
2
|
350 |
|
|
351 |
// sum of row card points |
|
352 |
fn sum(&self) -> i32 { |
|
353 |
let mut sum: i32 = 0; |
|
354 |
self.cards.iter().for_each(|card| { |
|
355 |
sum += card.points as i32; |
|
356 |
}); |
|
357 |
sum |
|
358 |
} |
0
|
359 |
} |
|
360 |
|
2
|
361 |
/*** PlayerCard ****/ |
1
|
362 |
#[derive(Debug)] |
0
|
363 |
struct PlayerCard { |
1
|
364 |
player_id: i32, |
0
|
365 |
card: Card, |
|
366 |
} |
|
367 |
|
1
|
368 |
impl PlayerCard { |
3
|
369 |
fn _get_player(&self) -> i32 { |
1
|
370 |
self.player_id |
|
371 |
} |
|
372 |
} |
|
373 |
|
|
374 |
impl PartialEq for PlayerCard { |
|
375 |
fn eq(&self, other: &Self) -> bool { |
|
376 |
self.card == other.card |
|
377 |
} |
|
378 |
} |
|
379 |
|
|
380 |
impl PartialOrd for PlayerCard { |
|
381 |
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { |
|
382 |
match self.card.partial_cmp(&other.card) { |
|
383 |
Some(core::cmp::Ordering::Equal) => {None} |
|
384 |
ord => return ord, |
|
385 |
} |
|
386 |
} |
|
387 |
} |
|
388 |
|
2
|
389 |
/*** Table ****/ |
1
|
390 |
#[derive(Debug)] |
0
|
391 |
struct Table { |
|
392 |
rows: Vec<Row>, |
2
|
393 |
player_cards: VecDeque<PlayerCard>, // owned by a player |
0
|
394 |
} |
|
395 |
|
1
|
396 |
impl Table { |
2
|
397 |
fn new(row_cards: VecDeque<Card>) -> Self { |
3
|
398 |
let mut rows = Vec::with_capacity(5); |
1
|
399 |
for card in row_cards { |
|
400 |
// create a new row then put a card into it |
|
401 |
let mut row = Row::new(); |
3
|
402 |
if let Some(_c) = row.push_or_collect(card) { |
1
|
403 |
panic!("Freshly created row overflowed"); |
|
404 |
} |
|
405 |
rows.push( row ); |
|
406 |
} |
0
|
407 |
|
1
|
408 |
Table { |
|
409 |
rows, |
2
|
410 |
player_cards: VecDeque::new(), |
1
|
411 |
} |
|
412 |
} |
|
413 |
|
|
414 |
fn lay_player_card( &mut self, card: Card, player_id: i32 ) { |
2
|
415 |
self.player_cards.push_back( PlayerCard { player_id, card } ); |
1
|
416 |
} |
|
417 |
|
|
418 |
fn sort_cards( &mut self ) { |
2
|
419 |
self.player_cards.make_contiguous().sort_by( |a,b| b.card.cmp(&a.card) ); |
|
420 |
} |
|
421 |
|
|
422 |
fn has_player_cards( &self ) -> bool { |
|
423 |
self.player_cards.len() > 0 |
1
|
424 |
} |
|
425 |
|
|
426 |
fn get_smallest_player_card( &mut self ) -> PlayerCard { |
2
|
427 |
// FIXME: check! |
|
428 |
self.player_cards.pop_back().expect("out of player cards on table") |
|
429 |
} |
|
430 |
|
|
431 |
fn get_closest_row( &self, pcard: &PlayerCard ) -> Option<usize> { |
|
432 |
// get the row id with last card closest smaller to players' |
|
433 |
let row_heads = self.get_row_heads(); |
|
434 |
let mut closest_val = None; |
|
435 |
let mut diff = 127; |
|
436 |
for i in 0..row_heads.len() { |
|
437 |
if row_heads[i] < pcard.card.value && pcard.card.value - row_heads[i] < diff { |
|
438 |
closest_val = Some(i); |
|
439 |
diff = pcard.card.value - row_heads[i]; |
|
440 |
// println!("DEBUG: pcard {}, row {}, head {}, diff {}, closest {:?}", pcard.card.value, i, row_heads[i], diff, closest_val); |
|
441 |
} |
|
442 |
} |
|
443 |
|
|
444 |
closest_val |
|
445 |
} |
|
446 |
|
|
447 |
fn put_card_into_row( &mut self, pcard: PlayerCard, row_id: usize ) -> Option<VecDeque<Card>> { |
|
448 |
self.rows[row_id as usize].push_or_collect(pcard.card) |
1
|
449 |
} |
|
450 |
|
2
|
451 |
fn get_row_heads( &self ) -> Vec<i8> { |
|
452 |
let mut heads: Vec<i8> = Vec::new(); |
|
453 |
for i in 0..self.rows.len() { |
|
454 |
heads.push( self.rows[i].last_card_value() ); |
|
455 |
} |
|
456 |
heads |
1
|
457 |
} |
|
458 |
|
2
|
459 |
// take a whole row and hand it over |
|
460 |
fn take_row( &mut self, row_id: usize ) -> VecDeque<Card> { |
|
461 |
self.rows[row_id].take_row() |
|
462 |
} |
|
463 |
|
|
464 |
// collect remaining cards in the rows at the end of round |
|
465 |
fn collect_rows( &mut self ) -> VecDeque<Card> { |
|
466 |
let mut cards = VecDeque::new(); |
|
467 |
for row in 0..self.rows.len() { |
|
468 |
self.rows[row] |
|
469 |
.take_row() |
|
470 |
.into_iter() |
|
471 |
.for_each(|card| cards.push_back(card)); |
|
472 |
} |
|
473 |
cards |
1
|
474 |
} |
|
475 |
} |
0
|
476 |
|
|
477 |
|
2
|
478 |
/*** Game ****/ |
|
479 |
|
|
480 |
struct GameStat { |
|
481 |
game_count: i64, |
|
482 |
shuffle_count: i64, |
|
483 |
start_time: Instant, // use start_time.elapsed().as_nanos() or .as_secs() |
|
484 |
} |
|
485 |
|
0
|
486 |
fn game() { |
2
|
487 |
let mut stats = GameStat { game_count:0, shuffle_count: 0, start_time: Instant::now() }; |
1
|
488 |
|
|
489 |
let mut deck = Deck::new(); |
|
490 |
|
|
491 |
let player_names = vec![ "grin", "moni", "icbalint", "orsi", "topi", "kgb", "zsu", "csilla" ]; |
|
492 |
let mut players: Vec<Player> = player_names.iter().map( |n| Player::new(n.to_string()) ).collect(); |
|
493 |
|
|
494 |
let player_count = players.len(); // pc - 1 |
|
495 |
|
2
|
496 |
for cnt_game in 1..=GAME_ROUNDS { |
|
497 |
debug!("Game round {} starts", cnt_game); |
1
|
498 |
deck.shuffle(); |
2
|
499 |
stats.shuffle_count += 1; |
|
500 |
stats.game_count += 1; |
1
|
501 |
|
|
502 |
// dealing |
2
|
503 |
debug!("Dealing."); |
3
|
504 |
for _i in 1..=10 { |
1
|
505 |
for player in 0 .. player_count { |
|
506 |
players[player].get_card( deck.pop().expect("Deck is empty while dealing to players") ); |
|
507 |
} |
|
508 |
} |
|
509 |
|
|
510 |
// we need 5 crds from deck |
2
|
511 |
debug!("Building the rows."); |
|
512 |
let mut cards = VecDeque::new(); |
3
|
513 |
(1..=5).for_each(|_| { |
2
|
514 |
cards.push_back( deck.pop().expect("deck empty before starting the game") ); |
3
|
515 |
}); |
2
|
516 |
// println!("We push 5 cards to rows: {:?}\n", cards); |
1
|
517 |
let mut table = Table::new(cards); |
|
518 |
|
|
519 |
// DEBUG |
2
|
520 |
/* println!("Table: {:?}\n", table); |
1
|
521 |
println!("PLayers: {:?}\n", players); |
|
522 |
println!("Deck: {:?}\n", deck); |
2
|
523 |
*/ |
|
524 |
debug!("We have the table ready: {:?}", table); |
1
|
525 |
|
|
526 |
// playing |
2
|
527 |
debug!("Players start taking turns"); |
1
|
528 |
for turn in 1..=10 { |
2
|
529 |
debug!("Turn {}!", turn); |
|
530 |
trace!("The table: {:?}", table); |
0
|
531 |
|
1
|
532 |
// everyone puts a card face down |
|
533 |
for player in 0 .. player_count { |
|
534 |
let player_id: i32 = player.try_into().unwrap(); |
|
535 |
// get a card from the player |
|
536 |
let topcard = players[player].throw_card(); |
|
537 |
// put it on the table ("turned face down") |
|
538 |
table.lay_player_card( topcard, player_id ); |
|
539 |
} |
|
540 |
|
|
541 |
// process cards |
2
|
542 |
debug!("The Table process the throws."); |
1
|
543 |
table.sort_cards(); |
|
544 |
|
2
|
545 |
while table.has_player_cards() { |
|
546 |
let smallest = table.get_smallest_player_card(); |
|
547 |
trace!("Take smallest card {:?}", &smallest); |
|
548 |
|
|
549 |
let closest_row = table.get_closest_row(&smallest); |
|
550 |
trace!("Choose closest row: {:?}", closest_row); |
0
|
551 |
|
2
|
552 |
match closest_row { |
|
553 |
Some(rowid) => { |
|
554 |
debug!("Putting down card into row {}", rowid); |
|
555 |
let player_id: usize = smallest.player_id.try_into().unwrap(); |
|
556 |
let overflow = table.put_card_into_row(smallest, rowid); |
|
557 |
if let Some(cards) = overflow { |
|
558 |
// row is full, got pile |
|
559 |
debug!("Row is busted, {} collects", players[player_id].name); |
|
560 |
// player gets pile, card gets into row head |
|
561 |
players[ player_id ].give_pile( cards ); |
|
562 |
} |
|
563 |
}, |
|
564 |
None => { |
|
565 |
// card too small, need to pick row! |
|
566 |
let player_id: usize = smallest.player_id.try_into().unwrap(); |
|
567 |
debug!("Too small from {}, picking row", players[player_id].name); |
|
568 |
// pick any row to take |
|
569 |
let rowid = players[ player_id ].pick_row_for_small_card(&table.rows, &smallest.card); |
|
570 |
trace!("Picked row {}", rowid); |
|
571 |
// take the row cards |
|
572 |
let cards = table.take_row(rowid); |
|
573 |
trace!("Took cards: {:?}", cards); |
|
574 |
players[ player_id ].give_pile( cards ); |
|
575 |
// put new card in the row |
|
576 |
let overflow = table.put_card_into_row(smallest, rowid); |
3
|
577 |
if let Some(_) = overflow { |
2
|
578 |
panic!("Player took whole row and it's already full"); |
|
579 |
} |
1
|
580 |
} |
|
581 |
} |
|
582 |
} |
|
583 |
} |
|
584 |
|
|
585 |
// end of round |
2
|
586 |
info!("Round finished, len is {} ??sec", stats.start_time.elapsed().as_micros()); |
1
|
587 |
|
2
|
588 |
debug!("End of round, counting and collecting back piles"); |
|
589 |
let mut winners: Vec<usize> = Vec::new(); |
|
590 |
let mut winscore: i32 = i32::MAX-1; |
|
591 |
|
|
592 |
for i in 0..player_count { |
|
593 |
info!("Player {} has {} points", players[i].name, players[i].game_point); |
|
594 |
|
|
595 |
if players[i].game_point < winscore { |
|
596 |
trace!("New winner {} with score {}", players[i].name, players[i].game_point); |
|
597 |
winners.clear(); |
|
598 |
winners.push(i); |
|
599 |
winscore = players[i].game_point; |
|
600 |
|
|
601 |
} else if players[i].game_point == winscore { |
|
602 |
trace!("New co-winner {} with score {}", players[i].name, players[i].game_point); |
|
603 |
winners.push(i); |
|
604 |
} |
|
605 |
trace!("The list of winners is {:?}", winners); |
|
606 |
|
|
607 |
// get pile from player |
|
608 |
let cards = players[i].get_pile(); |
|
609 |
// and give it back to the deck |
|
610 |
deck.push_cards(cards); |
|
611 |
// close player round and update stats |
|
612 |
players[i].close_round(); |
|
613 |
} |
|
614 |
|
|
615 |
// collect cards from table |
|
616 |
deck.push_cards( table.collect_rows() ); |
|
617 |
trace!("Shall have full deck now, len {}", deck.content.len()); |
1
|
618 |
|
2
|
619 |
let mut finals = Vec::new(); |
|
620 |
for i in winners.iter() { |
|
621 |
players[*i].inc_wins(); |
|
622 |
} |
|
623 |
|
|
624 |
for i in winners { |
|
625 |
finals.push( &players[i].name ); |
|
626 |
} |
|
627 |
info!("The winner(s): {:?}", &finals); |
|
628 |
|
|
629 |
/* players.iter().for_each(|player| { |
|
630 |
println!("Player {} has {} points", player.name, player.game_point); |
|
631 |
let cards = player.get_pile(); |
|
632 |
deck.push_cards(cards); |
|
633 |
player.close_round(); |
|
634 |
}); |
|
635 |
*/ |
|
636 |
} |
|
637 |
|
3
|
638 |
let elapsed_micro: f64 = stats.start_time.elapsed().as_micros() as f64; |
|
639 |
let game_rounds: f64 = GAME_ROUNDS.into(); |
|
640 |
|
|
641 |
let _res: f64 = stats.start_time.elapsed().as_micros() as f64 / <i32 as Into<f64>>::into(GAME_ROUNDS); |
|
642 |
|
|
643 |
println!("Totals (game time {} ??s, or {} s; {} ??s/game), {} games played ({} shuffles):", |
2
|
644 |
stats.start_time.elapsed().as_micros(), |
|
645 |
stats.start_time.elapsed().as_secs(), |
3
|
646 |
elapsed_micro / game_rounds, |
2
|
647 |
stats.game_count, |
|
648 |
stats.shuffle_count, |
|
649 |
); |
|
650 |
|
3
|
651 |
// players.sort_by( |a, b| a.total_point.partial_cmp(&b.total_point).unwrap() ); // ASC points |
|
652 |
// players.sort_by( |a, b| b.wins.partial_cmp(&a.wins).unwrap() ); // DESC wins |
|
653 |
players.sort_by_cached_key( |x| Reverse(x.wins) ); // DESC wins (caching is just for the show) |
2
|
654 |
|
|
655 |
for i in 0..players.len() { |
|
656 |
let p = &players[i]; |
|
657 |
println!("Player {} has wins {}, score {} (busted {} times)", p.name, p.wins, p.total_point, p.rows_busted); |
0
|
658 |
} |
|
659 |
} |
|
660 |
|
|
661 |
#[cfg(test)] |
|
662 |
mod tests { |
3
|
663 |
// use core::panic; |
1
|
664 |
use std::collections::VecDeque; |
|
665 |
|
|
666 |
use rand::Rng; |
|
667 |
|
2
|
668 |
use crate::{Card, Player, Row, Table, PlayerCard}; |
0
|
669 |
|
|
670 |
#[test] |
|
671 |
fn card_values() { |
|
672 |
let card_values = vec![1,2,5,10,33,55,77]; |
|
673 |
let card_points = vec![1,1,2,3, 5, 7, 5]; |
|
674 |
for i in 1 .. card_values.len() { |
|
675 |
let c = Card::new( card_values[i] ); |
|
676 |
let p = c.points; |
|
677 |
assert!(p == card_points[i], "card={} card points={} i={} expected point={}", card_values[i], p, i, card_points[i]); |
|
678 |
} |
|
679 |
} |
|
680 |
|
|
681 |
#[test] |
|
682 |
fn player_take_pile() { |
|
683 |
// create a player |
|
684 |
let mut p = Player::new("bob".to_string()); |
|
685 |
// create a pile |
1
|
686 |
let mut pile = VecDeque::new(); |
2
|
687 |
let mut refpile = VecDeque::new(); |
0
|
688 |
for i in 5..10 { |
|
689 |
let c = Card::new(i); |
1
|
690 |
pile.push_back(c); |
0
|
691 |
let c = Card::new(i); |
2
|
692 |
refpile.push_back(c); |
0
|
693 |
} |
2
|
694 |
// give the pile to player |
|
695 |
p.give_pile(pile); |
0
|
696 |
assert!( p.rows_busted == 1 ); |
|
697 |
|
|
698 |
// get back the pile from player |
|
699 |
// p = p.gimme_pile(); |
2
|
700 |
let pile = p.get_pile(); |
0
|
701 |
|
|
702 |
// the pile we got shall be same as the pile we gave |
|
703 |
// this check is O(n^2), doesn't matter for less than 100 items |
2
|
704 |
assert_eq!( pile, refpile ); |
0
|
705 |
assert!( pile.iter().all( |item| refpile.contains(item)) ); |
|
706 |
|
1
|
707 |
let mut pile = VecDeque::new(); |
|
708 |
for i in 4..=9 { |
0
|
709 |
let c = Card::new(i); |
1
|
710 |
pile.push_back(c); |
0
|
711 |
} |
2
|
712 |
p.give_pile(pile); |
0
|
713 |
assert!( p.rows_busted == 2 ); |
|
714 |
} |
|
715 |
|
|
716 |
#[test] |
|
717 |
fn row_push() { |
|
718 |
let mut row = Row::new(); |
2
|
719 |
let mut refcard = VecDeque::new(); // reference vec to check |
0
|
720 |
for i in 1..=7 { |
|
721 |
let cval = i+5; |
|
722 |
let card = Card::new(cval); |
|
723 |
// push a card into the row |
|
724 |
if let Some(cards) = row.push_or_collect(card) { |
|
725 |
// got the overflow |
|
726 |
println!("Got overflow row at {}!", i); |
|
727 |
assert!( i == 6, "Overflow at wrong position: {} != 6", i ); |
|
728 |
// we need to get the proper vec |
|
729 |
assert!( cards.iter().all( |item| refcard.contains(item) ), "Got cards {:?}", cards ); |
|
730 |
} else { |
|
731 |
println!("push success {}", i); |
|
732 |
} |
|
733 |
// remember the correct vec for checking |
|
734 |
let card = Card::new(cval); |
2
|
735 |
refcard.push_back(card); |
0
|
736 |
|
|
737 |
// check card value |
|
738 |
assert!( row.last_card_value() == cval, "Last card value mismatch: got {} vs expected {}", row.last_card_value(), cval ); |
|
739 |
} |
|
740 |
assert!( row.cards.len() == 2, "Row contains wrong amount of cards: {}", row.cards.len() ); |
|
741 |
} |
1
|
742 |
|
|
743 |
#[test] |
|
744 |
fn sort_cards() { |
2
|
745 |
let mut cards: VecDeque<Card> = VecDeque::new(); |
1
|
746 |
let mut rng = rand::thread_rng(); |
3
|
747 |
for _ in 1..50 { |
1
|
748 |
let n = rng.gen_range(1..104); |
2
|
749 |
cards.push_back( Card::new(n) ); |
1
|
750 |
} |
2
|
751 |
cards.make_contiguous().sort(); |
1
|
752 |
|
|
753 |
for i in 1..cards.len() { |
|
754 |
assert!( cards[i-1].value <= cards[i].value, "Bad ordering: {} > {}", cards[i-1].value,cards[i].value ); |
|
755 |
} |
|
756 |
} |
|
757 |
|
2
|
758 |
#[test] |
|
759 |
fn check_closest_row() { |
|
760 |
let table = generate_table(); |
|
761 |
let pcard = PlayerCard{ player_id: 42, card: Card::new(42) }; |
|
762 |
let closest = table.get_closest_row(&pcard); |
|
763 |
assert_eq!( closest, Some(3) ); // index from 0 |
|
764 |
} |
|
765 |
|
|
766 |
#[test] |
|
767 |
fn check_smallest_player_card() { |
|
768 |
let mut table = generate_table(); |
|
769 |
|
|
770 |
let mut player_id = 1; |
|
771 |
vec![103, 8, 71, 93, 6].into_iter().for_each(|c| { |
|
772 |
table.lay_player_card( Card::new(c), player_id); |
|
773 |
player_id += 1; |
|
774 |
}); |
|
775 |
|
|
776 |
let smallest = table.get_smallest_player_card(); |
|
777 |
assert_eq!( smallest, PlayerCard{ player_id: 5, card: Card::new(6) } ); |
|
778 |
} |
|
779 |
|
|
780 |
fn generate_table() -> Table { |
|
781 |
let mut row_cards = VecDeque::new(); |
|
782 |
vec![5,7,10,33,70].into_iter().for_each(|c| row_cards.push_back( Card::new(c) )); |
|
783 |
let table = Table::new(row_cards); |
|
784 |
table |
|
785 |
} |
0
|
786 |
} |
|
787 |
|
|
788 |
/* |
|
789 |
|
|
790 |
- 1-104 lap, |
|
791 |
- *5 - 2 |
|
792 |
- *0 - 3 |
|
793 |
- NN - 5 |
|
794 |
- 55 - 7 |
|
795 |
- deck |
|
796 |
- jatekosok; kezben tartott lapok; elvitt lapok; pontszamok; counter: elvitt sorok, okrok, total pont |
|
797 |
-- keveres (keveresek szama) |
|
798 |
-- osztas: mindenki 10 lap |
|
799 |
-- start sorok: 5 kartya |
|
800 |
- jatek (jatekok szama) |
|
801 |
-- mindenki a felso lapot kiteszi |
|
802 |
-- szamsorrendben felkerulnek, aki viszi, viszi |
|
803 |
--- ha kisebb, akkor dontes |
|
804 |
---- ha van legkevesebb, viszi |
|
805 |
---- ha tobb min van, random valaszt |
|
806 |
- osszesites |
|
807 |
-- okrok, elvitt sorok |
|
808 |
-- keveresek szama, jatekok szama, eltelt ido |
|
809 |
- deck osszegyujtes |
|
810 |
|
|
811 |
|
|
812 |
*/ |