/// This is the implementation of a Player.
use std::collections::VecDeque;
// We use this to move variables out of a Vec with ownership.
use std::mem;
use crate::deck::*;
use crate::card::*;
use crate::row::*;
#[derive(Debug)]
/// A `Player` is a person in the game.
/// # Structure members
/// * `name` - the name of the Player
/// * `hand` - the cards in the hand of Player, stored as a [`Deck`], so, for example, it could be shuffled or sorted.
/// * `pile` - the pile of busted [`Row`] [`Card`]s, counted at the end of the round.
/// * `game_point` - points in the current game round
/// * `total_point` - points in all the games total
/// * `rows_busted` - just counting how many rows the player have collected
/// * `wins` - how many games have the Player won
pub(crate) struct Player {
name: String,
hand: Deck,
pile: VecDeque<Card>,
game_point: i32,
total_point: i32,
rows_busted: i32,
wins: i32,
}
impl Player {
/// Creates a new [`Player`] with a given `name`.
pub(crate) fn new(name: String)->Self {
debug!("Player {} created", name);
Player {
name,
hand: Deck::new_empty(),
pile: VecDeque::new(),
game_point: 0,
total_point: 0,
rows_busted: 0,
wins: 0,
}
}
/// get one card from the dealer
pub(crate) fn get_card( &mut self, card: Card ) {
trace!("Player {} got a card {:?}, cards before {}", self.name, &card, self.hand.len());
self.hand.push(card);
}
/// throw a card from hand to the table
pub(crate) fn throw_card( &mut self )->Card {
if let Some(c) = self.hand.pop() {
trace!("Player {} throws a card {:?}", self.name, &c);
c
} else {
panic!("throw_card: Player {} has no card in hand!", self.name);
}
}
/// get a busted row of cards
pub(crate) fn give_pile( &mut self, cards: VecDeque<Card> ) {
for c in cards.into_iter() {
self.game_point += c.points as i32;
self.pile.push_back(c);
}
self.rows_busted += 1;
trace!("Player {} got busted, count {}", self.name, &self.rows_busted);
}
/// Get the name of the Player
pub fn get_name(&self) -> &String {
&self.name
}
/// ask the player their score
pub(crate) fn get_points( &self ) -> i32 {
self.game_point
}
/// Get the number of games won
pub fn get_wins(&self) -> i32 {
self.wins
}
/// Player won this game, increment counter
pub(crate) fn inc_wins( &mut self ) {
self.wins += 1;
}
/// Get total points of all games
pub fn get_total_points(&self) -> i32 {
self.total_point
}
/// Get the number of total busted rows
pub fn get_rows_busted(&self) -> i32 {
self.rows_busted
}
/// give back cards from the player's pile ino the Deck
pub(crate) fn get_pile( &mut self ) -> VecDeque<Card> {
trace!("Player {} gives back their pile", self.name);
// Here we take the ownership of the `pile` VecDeque<Card> structure,
// and replace it with "the default" (an empty VecDeque); we can
// return it now without taking a mutable borrow of `self`.
mem::take( &mut self.pile )
// same effect (`drain()` also transfers ownership):
// self.pile.drain(..).collect()
// very cumbersome manual fiddling (also in wrong/reverted order...)
/* let mut throw: Vec<Card> = Vec::new();
for _i in 0 .. self.pile.len() {
throw.push( self.pile.pop().unwrap() );
}
throw
*/
}
// I can do this just because I *throw away* c!
// Doesn't work if I want to use/return it.
/* fn _gimme_pile(self)->Self {
for c in &self.pile {
println!("Throw {} ", c);
}
self
}
*/
/// End of round, "close" the Player and verify that we did all right.
/// These ought to be `assert()` calls, but... same thing.
pub(crate) fn close_round( &mut self ) {
if self.hand.len() > 0 {
panic!("Closing round when {} has {} cards in hand", self.name, self.hand.len());
}
if self.pile.len() > 0 {
panic!("Closing round when {} stil have pile with {} cards", self.name, self.pile.len());
}
trace!("Player {} closing round; points={} total so far {}", self.name, self.game_point, self.total_point);
self.total_point += self.game_point;
self.game_point = 0;
}
/// Card too small: pick a row to collect from the rows.
/// It selects the first row with the lowest `points`.
///
/// # Arguments
/// * `rows` - A `Vec`tor of [`Row`]s to pick from
/// * `playercard` - The actual card the player just thrown, which could be used in decision (but it isn't now)
pub(crate) fn pick_row_for_small_card( &self, rows: &Vec<Row>, playercard: &Card ) -> usize {
trace!("Player {} picking a row for small card, card {:?}, rows {:?}", self.name, playercard, rows);
// contains the summary point for each row
let mut row_points = Vec::with_capacity(5);
// the smallest row score (we start by something larger than anything possible)
let mut smallest = 999;
// how many rows have the same smallest score
let mut same_point = 0;
// the first smallest row_id (start by larger than max)
let mut smallest_rowid = 255;
for rowid in 0 .. rows.len() {
// debug!("pick_row_for_small_card: rowlen {}, rowid {}", rows.len(), rowid);
// As Row to calculate the summary points for itself and store it in a Vec
row_points.push( rows[rowid].sum() );
if row_points[rowid] < smallest {
// we have a new smallest row
smallest = row_points[rowid];
same_point = 0;
smallest_rowid = rowid;
} else if row_points[rowid] == smallest {
// we have another row with same point as smallest
same_point += 1;
}
}
if same_point < 1 {
// we have one smallest row
smallest_rowid.try_into().unwrap() // it's tiny, will fit into u8, so unwrap() is safe
} else {
// bored, we pick the first now anyway; this could be smarter, but possibly
// it would require peeking at other rows and the thrown cards of others.
smallest_rowid.try_into().unwrap()
}
}
}
/// `PlayerCard` is a [`Card`] associated with a Player.
#[derive(Debug)]
pub(crate) struct PlayerCard {
pub player_id: i32,
pub card: Card,
}
impl PlayerCard {
/// It isn't used because I was tired fighting with the borrow checker ;-)
fn _get_player(&self) -> i32 {
self.player_id
}
}
/// We use this to sort the [`Card`]s, using its own knowledge about equality.
impl PartialEq for PlayerCard {
fn eq(&self, other: &Self) -> bool {
self.card == other.card
}
}
/// We use this to sort the [`Card`]s, using its own knowledge about ordering.
impl PartialOrd for PlayerCard {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self.card.partial_cmp(&other.card) {
Some(core::cmp::Ordering::Equal) => {None}
ord => return ord,
}
}
}