1 // #[allow(dead_code, unused)] |
1 // #[allow(dead_code, unused)] |
2 // vigyazz6! autplayer |
2 // vigyazz6! autplayer |
3 // |
3 // |
4 |
4 |
5 use core::{fmt, panic}; |
5 use core::panic; |
6 use std::{collections::VecDeque, time::Instant, cmp::Reverse}; |
6 use std::{collections::VecDeque, time::Instant, cmp::Reverse}; |
7 use rand::Rng; |
7 |
8 use std::mem; |
8 use crate::{deck::Deck, player::Player, table::Table}; |
|
9 // use rand::Rng; |
|
10 // use std::mem; |
|
11 |
|
12 mod deck; |
|
13 mod table; |
|
14 mod player; |
|
15 mod card; |
|
16 mod row; |
9 |
17 |
10 extern crate pretty_env_logger; |
18 extern crate pretty_env_logger; |
11 #[macro_use] extern crate log; |
19 #[macro_use] extern crate log; |
12 |
20 |
13 const GAME_ROUNDS: i32 = 1_000_000; |
21 const GAME_ROUNDS: i32 = 100_000; |
14 |
22 |
15 fn main() { |
23 fn main() { |
16 // RUST_LOG=debug cargo run |
24 // RUST_LOG=debug cargo run |
17 pretty_env_logger::init(); |
25 pretty_env_logger::init(); |
18 info!("Program starting."); |
26 info!("Program starting."); |
19 game(); |
27 game(); |
20 info!("End of run."); |
28 info!("End of run."); |
21 } |
29 } |
22 |
30 |
23 /*** Card ****/ |
31 // Card |
24 #[derive(Debug)] |
32 // Deck |
25 struct Card { |
33 // Player |
26 value: i8, |
34 // Row |
27 points: i8, |
35 |
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 |
|
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 |
|
92 /*** Deck ****/ |
|
93 #[derive(Debug)] |
|
94 struct Deck { |
|
95 content: VecDeque<Card>, |
|
96 } |
|
97 |
|
98 impl Deck { |
|
99 fn new_empty() -> Self { |
|
100 debug!("Empty deck generated"); |
|
101 Deck { |
|
102 content: VecDeque::new(), |
|
103 } |
|
104 } |
|
105 |
|
106 fn new() -> Self { |
|
107 debug!("Full deck generated"); |
|
108 let content = (1..=104).into_iter().map( |n| Card::new(n) ).collect(); |
|
109 Deck { |
|
110 content, |
|
111 } |
|
112 } |
|
113 |
|
114 fn shuffle( &mut self ) { |
|
115 let mut rng = rand::thread_rng(); |
|
116 |
|
117 trace!("Deck before shuffle: len {}, {:?}", self.content.len(), self); |
|
118 debug!("Deck shuffled"); |
|
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 |
|
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()); |
|
128 if c1 != c2 { |
|
129 self.content.swap(c1, c2); |
|
130 } |
|
131 } |
|
132 trace!("Deck after shuffle: len {}, {:?}", self.content.len(), self); |
|
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 |
|
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 |
|
151 fn len( &self ) -> usize { |
|
152 self.content.len() |
|
153 } |
|
154 |
|
155 fn _get_nth( &mut self, n: usize ) -> Card { |
|
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 |
|
164 /*** Player ****/ |
|
165 #[derive(Debug)] |
|
166 struct Player { |
|
167 name: String, |
|
168 hand: Deck, |
|
169 pile: VecDeque<Card>, |
|
170 game_point: i32, |
|
171 total_point: i32, |
|
172 rows_busted: i32, |
|
173 wins: i32, |
|
174 } |
|
175 |
|
176 impl Player { |
|
177 fn new(name: String)->Self { |
|
178 debug!("Player {} created", name); |
|
179 Player { |
|
180 name, |
|
181 hand: Deck::new_empty(), |
|
182 pile: VecDeque::new(), |
|
183 game_point: 0, |
|
184 total_point: 0, |
|
185 rows_busted: 0, |
|
186 wins: 0, |
|
187 } |
|
188 } |
|
189 |
|
190 // get one card from th dealer |
|
191 fn get_card( &mut self, card: Card ) { |
|
192 trace!("Player {} got a card {:?}, cards before {}", self.name, &card, self.hand.len()); |
|
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() { |
|
199 trace!("Player {} throws a card {:?}", self.name, &c); |
|
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 |
|
207 fn give_pile( &mut self, cards: VecDeque<Card> ) { |
|
208 for c in cards.into_iter() { |
|
209 self.game_point += c.points as i32; |
|
210 self.pile.push_back(c); |
|
211 } |
|
212 self.rows_busted += 1; |
|
213 trace!("Player {} got busted, count {}", self.name, &self.rows_busted); |
|
214 } |
|
215 |
|
216 // ask the player their score |
|
217 fn _tell_points( self ) -> i32 { |
|
218 self.game_point |
|
219 } |
|
220 |
|
221 fn inc_wins( &mut self ) { |
|
222 self.wins += 1; |
|
223 } |
|
224 |
|
225 // give back cards from the pile |
|
226 fn get_pile( &mut self ) -> VecDeque<Card> { |
|
227 trace!("Player {} gives back their pile", self.name); |
|
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 |
|
259 trace!("Player {} closing round; points={} total so far {}", self.name, self.game_point, self.total_point); |
|
260 self.total_point += self.game_point; |
|
261 self.game_point = 0; |
|
262 } |
|
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 |
|
269 let mut row_points = Vec::with_capacity(5); |
|
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 } |
|
304 } |
|
305 |
|
306 /*** Row ****/ |
|
307 // a row of cards on the table (max 5) |
|
308 #[derive(Debug)] |
|
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 { |
|
318 cards: VecDeque::with_capacity(5), |
|
319 } |
|
320 } |
|
321 |
|
322 fn push_or_collect( &mut self, card: Card ) -> Option<VecDeque<Card>> { |
|
323 trace!("Called push_or_collect on row {:?}", &self); |
|
324 if self.cards.len() < Self::MAX_LEN { |
|
325 trace!("Less than {} cards, putting at the end", Self::MAX_LEN); |
|
326 self.cards.push_back(card); |
|
327 None |
|
328 |
|
329 } else { |
|
330 trace!("Row is full, len {}, maxlen {}", self.cards.len(), Self::MAX_LEN); |
|
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 |
|
341 fn take_row( &mut self ) -> VecDeque<Card> { |
|
342 // take cards and empty the row |
|
343 mem::take( &mut self.cards ) |
|
344 } |
|
345 |
|
346 fn last_card_value(&self) -> i8 { |
|
347 // println!("last_card_value: cards {:?}, len {}", self.cards, self.cards.len()); |
|
348 self.cards.get( self.cards.len()-1 ).unwrap().value |
|
349 } |
|
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 } |
|
359 } |
|
360 |
|
361 /*** PlayerCard ****/ |
|
362 #[derive(Debug)] |
|
363 struct PlayerCard { |
|
364 player_id: i32, |
|
365 card: Card, |
|
366 } |
|
367 |
|
368 impl PlayerCard { |
|
369 fn _get_player(&self) -> i32 { |
|
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 |
|
389 /*** Table ****/ |
|
390 #[derive(Debug)] |
|
391 struct Table { |
|
392 rows: Vec<Row>, |
|
393 player_cards: VecDeque<PlayerCard>, // owned by a player |
|
394 } |
|
395 |
|
396 impl Table { |
|
397 fn new(row_cards: VecDeque<Card>) -> Self { |
|
398 let mut rows = Vec::with_capacity(5); |
|
399 for card in row_cards { |
|
400 // create a new row then put a card into it |
|
401 let mut row = Row::new(); |
|
402 if let Some(_c) = row.push_or_collect(card) { |
|
403 panic!("Freshly created row overflowed"); |
|
404 } |
|
405 rows.push( row ); |
|
406 } |
|
407 |
|
408 Table { |
|
409 rows, |
|
410 player_cards: VecDeque::new(), |
|
411 } |
|
412 } |
|
413 |
|
414 fn lay_player_card( &mut self, card: Card, player_id: i32 ) { |
|
415 self.player_cards.push_back( PlayerCard { player_id, card } ); |
|
416 } |
|
417 |
|
418 fn sort_cards( &mut self ) { |
|
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 |
|
424 } |
|
425 |
|
426 fn get_smallest_player_card( &mut self ) -> PlayerCard { |
|
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) |
|
449 } |
|
450 |
|
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 |
|
457 } |
|
458 |
|
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 |
|
474 } |
|
475 } |
|
476 |
36 |
477 |
37 |
478 /*** Game ****/ |
38 /*** Game ****/ |
479 |
39 |
480 struct GameStat { |
40 struct GameStat { |