src/player.rs
author Peter Gervai <grin@grin.hu>
Sat, 04 Feb 2023 22:57:08 +0100
changeset 7 c2b77cc8664c
parent 5 0dd7f2c9fd81
permissions -rw-r--r--
Update version to 1.00

/// 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,
        }
    }
}