Split main into module files.
authorPeter Gervai <grin@grin.hu>
Tue, 31 Jan 2023 23:25:50 +0100
changeset 4 a2f0cb2b5c13
parent 3 3d9dba5b16e0
child 5 0dd7f2c9fd81
Split main into module files.
.hgignore
src/card.rs
src/deck.rs
src/main.rs
src/player.rs
src/row.rs
src/table.rs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,3 @@
+syntax: glob
+target
+Cargo.lock
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/card.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,70 @@
+use core::fmt;
+
+/*** Card ****/
+#[derive(Debug)]
+pub struct Card {
+    pub value: i8,
+    pub points: i8,
+}
+
+impl Card {
+    pub fn new(value: i8)->Self {
+
+        let mut points = 0;
+        if value % 10 == 5 {
+            // ends with 5 = 2 point
+            points = 2;
+            // println!("*5 add 1, val={}, pt={}", value, points);
+        }
+
+        if value % 10 == 0 {
+            // ends with 0 = 3 point
+            points = 3;
+            // println!("*0 add 2, val={}, pt={}", value, points);
+        }
+
+        if value % 10 == value / 10 {
+            // same numbers = 5 points (55=7)
+            points += 5;
+            // println!("NN add 5, val={}, pt={}", value, points);
+        }
+
+        if points == 0 {
+            points = 1;
+        }
+
+        Card {
+            value,
+            points,
+        }
+    }
+}
+
+impl fmt::Display for Card {
+    fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result {
+        write!(f, "(Card {}, points {})", self.value, self.points)
+    }
+}
+
+impl PartialEq for Card {
+    fn eq(&self, other: &Self) -> bool {
+        self.value == other.value
+    }
+}
+
+impl Eq for Card {} 
+
+impl PartialOrd for Card {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        match self.value.partial_cmp(&other.value) {
+            Some(core::cmp::Ordering::Equal) => {None}
+            ord => return ord,
+        }
+    }
+}
+
+impl Ord for Card {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.value.cmp(&other.value)
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/deck.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,82 @@
+/*** Deck ****/
+use std::collections::VecDeque;
+
+use rand::Rng;
+
+use crate::card::Card;
+
+#[derive(Debug)]
+pub(crate) struct Deck {
+    content: VecDeque<Card>,
+}
+
+impl Deck {
+    /// Creates an empty [`Deck`] of undefined size
+    pub(crate) fn new_empty() -> Self {
+        debug!("Empty deck generated");
+        Deck {
+            content: VecDeque::new(),
+        }
+    }
+
+    /// Creates a new full [`Deck`] with 104 cards.
+    pub(crate) fn new() -> Self {
+        debug!("Full deck generated");
+        let content = (1..=104).into_iter().map( |n| Card::new(n) ).collect();
+        Deck {
+            content,
+        }
+    }
+
+    /// Shuffles this [`Deck`] (using its default method)
+    pub(crate) fn shuffle( &mut self ) {
+        let mut rng = rand::thread_rng();
+        
+        trace!("Deck before shuffle: len {}, {:?}", self.content.len(), self);
+        debug!("Deck shuffled");
+        // shufflers:
+        // * naive: swap cards n times
+        // * kgb: half the deck, take 1..4 cards sequentially from each
+        // * grin: take 1..6 from front and put at bottom
+
+        // naive shuffle: exchange random cards
+        for _i in 1..=500 {
+            let c1 = rng.gen_range(0 .. self.content.len());
+            let c2 = rng.gen_range(0 .. self.content.len());
+            if c1 != c2 {
+                self.content.swap(c1, c2);
+            }
+        }
+        trace!("Deck after shuffle: len {}, {:?}", self.content.len(), self);
+    }
+
+    /// Returns the top card of this [`Deck`].
+    pub(crate) fn pop( &mut self ) -> Option<Card> {
+        self.content.pop_front() 
+    }
+
+    /// Put a card into the bottom of the [`Deck`]
+    pub(crate) fn push( &mut self, c: Card ) {
+        self.content.push_back(c);
+    }
+
+    /// Push multiple cards to the bottom of the [`Deck`]
+    pub(crate) fn push_cards( &mut self, cards: VecDeque<Card> ) {
+        trace!("Collecting back, deck len is {}, cards {}", self.content.len(), cards.len());
+        cards.into_iter().for_each( |card| self.push(card) );
+        trace!("Deck len is {}", self.content.len());
+    }
+
+    /// Returns the length of this [`Deck`].
+    pub(crate) fn len( &self ) -> usize {
+        self.content.len()
+    }
+
+    fn _get_nth( &mut self, n: usize ) -> Card {
+        if let Some(c) = self.content.remove(n) {
+            c
+        } else {
+            panic!("get_nth: index {} out of bounds ({})!", n, self.content.len());
+        }
+    }
+}
--- a/src/main.rs	Tue Jan 31 22:16:26 2023 +0100
+++ b/src/main.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -2,15 +2,23 @@
 // vigyazz6! autplayer
 //
 
-use core::{fmt, panic};
+use core::panic;
 use std::{collections::VecDeque, time::Instant, cmp::Reverse};
-use rand::Rng;
-use std::mem;
+
+use crate::{deck::Deck, player::Player, table::Table};
+// use rand::Rng;
+// use std::mem;
+
+mod deck;
+mod table;
+mod player;
+mod card;
+mod row;
 
 extern crate pretty_env_logger;
 #[macro_use] extern crate log;
 
-const GAME_ROUNDS: i32 = 1_000_000;
+const GAME_ROUNDS: i32 = 100_000;
 
 fn main() {
     // RUST_LOG=debug cargo run
@@ -20,459 +28,11 @@
     info!("End of run.");
 }
 
-/*** Card ****/
-#[derive(Debug)]
-struct Card {
-    value: i8,
-    points: i8,
-}
-
-impl Card {
-    fn new(value: i8)->Self {
-
-        let mut points = 0;
-        if value % 10 == 5 {
-            // ends with 5 = 2 point
-            points = 2;
-            // println!("*5 add 1, val={}, pt={}", value, points);
-        }
-
-        if value % 10 == 0 {
-            // ends with 0 = 3 point
-            points = 3;
-            // println!("*0 add 2, val={}, pt={}", value, points);
-        }
-
-        if value % 10 == value / 10 {
-            // same numbers = 5 points (55=7)
-            points += 5;
-            // println!("NN add 5, val={}, pt={}", value, points);
-        }
-
-        if points == 0 {
-            points = 1;
-        }
-
-        Card {
-            value,
-            points,
-        }
-    }
-}
-
-impl fmt::Display for Card {
-    fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result {
-        write!(f, "(Card {}, points {})", self.value, self.points)
-    }
-}
-
-impl PartialEq for Card {
-    fn eq(&self, other: &Self) -> bool {
-        self.value == other.value
-    }
-}
-
-impl Eq for Card {} 
-
-impl PartialOrd for Card {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        match self.value.partial_cmp(&other.value) {
-            Some(core::cmp::Ordering::Equal) => {None}
-            ord => return ord,
-        }
-    }
-}
-
-impl Ord for Card {
-    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
-        self.value.cmp(&other.value)
-    }
-}
-
-/*** Deck ****/
-#[derive(Debug)]
-struct Deck {
-    content: VecDeque<Card>,
-}
-
-impl Deck {
-    fn new_empty() -> Self {
-        debug!("Empty deck generated");
-        Deck {
-            content: VecDeque::new(),
-        }
-    }
-
-    fn new() -> Self {
-        debug!("Full deck generated");
-        let content = (1..=104).into_iter().map( |n| Card::new(n) ).collect();
-        Deck {
-            content,
-        }
-    }
-
-    fn shuffle( &mut self ) {
-        let mut rng = rand::thread_rng();
-        
-        trace!("Deck before shuffle: len {}, {:?}", self.content.len(), self);
-        debug!("Deck shuffled");
-        // shufflers:
-        // * naive: swap cards n times
-        // * kgb: half the deck, take 1..4 cards sequentially from each
-        // * grin: take 1..6 from front and put at bottom
-
-        // naive shuffle: exchange random cards
-        for _i in 1..=500 {
-            let c1 = rng.gen_range(0 .. self.content.len());
-            let c2 = rng.gen_range(0 .. self.content.len());
-            if c1 != c2 {
-                self.content.swap(c1, c2);
-            }
-        }
-        trace!("Deck after shuffle: len {}, {:?}", self.content.len(), self);
-    }
-
-    // get top card from deck
-    fn pop( &mut self ) -> Option<Card> {
-        self.content.pop_front() 
-    }
-
-    // put a card into the bottom of the deck
-    fn push( &mut self, c: Card ) {
-        self.content.push_back(c);
-    }
-
-    fn push_cards( &mut self, cards: VecDeque<Card> ) {
-        trace!("Collecting back, deck len is {}, cards {}", self.content.len(), cards.len());
-        cards.into_iter().for_each( |card| self.push(card) );
-        trace!("Deck len is {}", self.content.len());
-    }
-
-    fn len( &self ) -> usize {
-        self.content.len()
-    }
-
-    fn _get_nth( &mut self, n: usize ) -> Card {
-        if let Some(c) = self.content.remove(n) {
-            c
-        } else {
-            panic!("get_nth: index {} out of bounds ({})!", n, self.content.len());
-        }
-    }
-}
-
-/*** Player ****/
-#[derive(Debug)]
-struct Player {
-    name: String,
-    hand: Deck,
-    pile: VecDeque<Card>,
-    game_point: i32,
-    total_point: i32,
-    rows_busted: i32,
-    wins: i32,
-}
-
-impl Player {
-    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 th dealer
-    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
-    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
-    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);
-    }
-
-    // ask the player their score
-    fn _tell_points( self ) -> i32 {
-        self.game_point
-    }
-
-    fn inc_wins( &mut self ) {
-        self.wins += 1;
-    }
-
-    // give back cards from the pile
-    fn get_pile( &mut self ) -> VecDeque<Card> {
-        trace!("Player {} gives back their pile", self.name);
-        mem::take( &mut self.pile )
-        // same effect:
-        // self.pile.drain(..).collect()
-
-        // very cumbersome manual fiddling (also reverted...)
-/*         let mut throw: Vec<Card> = Vec::new();
-        for _i in 0 .. self.pile.len() {
-            throw.push( self.pile.pop().unwrap() );
-        }
-        throw
- */    
-    }
+// Card
+// Deck
+// Player
+// Row
 
-    // I can do this just because I *throw away* c!
-    // doesn't work if I want to use it.
-/*     fn _gimme_pile(self)->Self {
-        for c in &self.pile {
-            println!("Throw {} ", c);
-        }
-        self
-    }
- */
-    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
-    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
-        let mut smallest = 999;
-        // how many rows have the same smallest score
-        let mut same_point = 0;
-        // the first smallest row_id
-        let mut smallest_rowid = 255;
-
-        for rowid in 0 .. rows.len() {
-            // DEBUG
-            // println!("pick_row_for_small_card: rowlen {}, rowid {}", rows.len(), rowid);
-            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
-        
-        } else {
-            // bored, we pick the first now anyway
-            smallest_rowid.try_into().unwrap()
-        }
-        
-    }
-}
-
-/*** Row ****/
-// a row of cards on the table (max 5)
-#[derive(Debug)]
-struct Row {
-    cards: VecDeque<Card>,
-}
-
-impl Row {
-    const MAX_LEN: usize = 5;
-
-    fn new() -> Self {
-        Row {
-            cards: VecDeque::with_capacity(5),
-        }
-    }
-
-    fn push_or_collect( &mut self, card: Card ) -> Option<VecDeque<Card>> {
-        trace!("Called push_or_collect on row {:?}", &self);
-        if self.cards.len() < Self::MAX_LEN {
-            trace!("Less than {} cards, putting at the end", Self::MAX_LEN);
-            self.cards.push_back(card);
-            None
-
-        } else {
-            trace!("Row is full, len {}, maxlen {}", self.cards.len(), Self::MAX_LEN);
-            // row overflow
-            let row_cards = mem::take( &mut self.cards );
-            self.cards.push_back(card);
-            if self.cards.len() != 1 {
-                panic!("New row must have one card, not {}", self.cards.len());
-            }
-            Some(row_cards)
-        }
-    }
-
-    fn take_row( &mut self ) -> VecDeque<Card> {
-        // take cards and empty the row
-        mem::take( &mut self.cards )
-    }
-
-    fn last_card_value(&self) -> i8 {
-        // println!("last_card_value: cards {:?}, len {}", self.cards, self.cards.len());
-        self.cards.get( self.cards.len()-1 ).unwrap().value
-    }
-
-    // sum of row card points
-    fn sum(&self) -> i32 {
-        let mut sum: i32 = 0;
-        self.cards.iter().for_each(|card| {
-            sum += card.points as i32;
-        });
-        sum
-    }
-}
-
-/*** PlayerCard ****/
-#[derive(Debug)]
-struct PlayerCard {
-    player_id: i32,
-    card: Card,
-}
-
-impl PlayerCard {
-    fn _get_player(&self) -> i32 {
-        self.player_id
-    }
-}
-
-impl PartialEq for PlayerCard {
-    fn eq(&self, other: &Self) -> bool {
-        self.card == other.card
-    }
-}
-
-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,
-        }
-    }
-}
-
-/*** Table ****/
-#[derive(Debug)]
-struct Table {
-    rows: Vec<Row>,
-    player_cards: VecDeque<PlayerCard>, // owned by a player
-}
-
-impl Table {
-    fn new(row_cards: VecDeque<Card>) -> Self {
-        let mut rows = Vec::with_capacity(5);
-        for card in row_cards {
-            // create a new row then put a card into it
-            let mut row = Row::new();
-            if let Some(_c) = row.push_or_collect(card) {
-                panic!("Freshly created row overflowed");
-            }
-            rows.push( row );
-        }
-
-        Table {
-            rows,
-            player_cards: VecDeque::new(),
-        }
-    }
-
-    fn lay_player_card( &mut self, card: Card, player_id: i32 ) {
-        self.player_cards.push_back( PlayerCard { player_id, card } );
-    }
-
-    fn sort_cards( &mut self ) {
-        self.player_cards.make_contiguous().sort_by( |a,b| b.card.cmp(&a.card) );
-    }
-
-    fn has_player_cards( &self ) -> bool {
-        self.player_cards.len() > 0
-    }
-
-    fn get_smallest_player_card( &mut self ) -> PlayerCard {
-        // FIXME: check!
-        self.player_cards.pop_back().expect("out of player cards on table")
-    }
-
-    fn get_closest_row( &self, pcard: &PlayerCard ) -> Option<usize> {
-        // get the row id with last card closest smaller to players'
-        let row_heads = self.get_row_heads();
-        let mut closest_val = None;
-        let mut diff = 127;
-        for i in 0..row_heads.len() {
-            if row_heads[i] < pcard.card.value && pcard.card.value - row_heads[i] < diff {
-                closest_val = Some(i);
-                diff = pcard.card.value - row_heads[i];
-                // println!("DEBUG: pcard {}, row {}, head {}, diff {}, closest {:?}", pcard.card.value, i, row_heads[i], diff, closest_val);
-            }
-        }
-
-        closest_val
-    }
-
-    fn put_card_into_row( &mut self, pcard: PlayerCard, row_id: usize ) -> Option<VecDeque<Card>> {
-        self.rows[row_id as usize].push_or_collect(pcard.card)
-    }
-
-    fn get_row_heads( &self ) -> Vec<i8> {
-        let mut heads: Vec<i8> = Vec::new();
-        for i in 0..self.rows.len() {
-            heads.push( self.rows[i].last_card_value() );
-        }
-        heads
-    }
-
-    // take a whole row and hand it over
-    fn take_row( &mut self, row_id: usize ) -> VecDeque<Card> {
-        self.rows[row_id].take_row()
-    }
-
-    // collect remaining cards in the rows at the end of round
-    fn collect_rows( &mut self ) -> VecDeque<Card> {
-        let mut cards = VecDeque::new();
-        for row in 0..self.rows.len() {
-            self.rows[row]
-                .take_row()
-                .into_iter()
-                .for_each(|card| cards.push_back(card));
-        }
-        cards
-    }
-}
 
 
 /*** Game ****/
@@ -556,7 +116,7 @@
                         let overflow = table.put_card_into_row(smallest, rowid);
                         if let Some(cards) = overflow {
                             // row is full, got pile
-                            debug!("Row is busted, {} collects", players[player_id].name);
+                            debug!("Row is busted, {} collects", players[player_id].get_name());
                             // player gets pile, card gets into row head
                             players[ player_id ].give_pile( cards );
                         }
@@ -564,9 +124,10 @@
                     None => {
                         // card too small, need to pick row!
                         let player_id: usize = smallest.player_id.try_into().unwrap();
-                        debug!("Too small from {}, picking row", players[player_id].name);
+                        debug!("Too small from {}, picking row", players[player_id].get_name());
                         // pick any row to take
-                        let rowid = players[ player_id ].pick_row_for_small_card(&table.rows, &smallest.card);
+                        // let rowid = players[ player_id ].pick_row_for_small_card(&table.rows, &smallest.card);
+                        let rowid = players[ player_id ].pick_row_for_small_card(table.peek_rows(), &smallest.card);
                         trace!("Picked row {}", rowid);
                         // take the row cards
                         let cards = table.take_row(rowid);
@@ -590,16 +151,16 @@
         let mut winscore: i32 = i32::MAX-1;
 
         for i in 0..player_count {
-            info!("Player {} has {} points", players[i].name, players[i].game_point);
+            info!("Player {} has {} points", players[i].get_name(), players[i].get_points());
 
-            if players[i].game_point < winscore  {
-                trace!("New winner {} with score {}", players[i].name, players[i].game_point);
+            if players[i].get_points() < winscore  {
+                trace!("New winner {} with score {}", players[i].get_name(), players[i].get_points());
                 winners.clear();
                 winners.push(i);
-                winscore = players[i].game_point;
+                winscore = players[i].get_points();
             
-            } else if players[i].game_point == winscore {
-                trace!("New co-winner {} with score {}", players[i].name, players[i].game_point);
+            } else if players[i].get_points() == winscore {
+                trace!("New co-winner {} with score {}", players[i].get_name(), players[i].get_points());
                 winners.push(i);
             }
             trace!("The list of winners is {:?}", winners);
@@ -614,7 +175,7 @@
 
         // collect cards from table
         deck.push_cards( table.collect_rows() );
-        trace!("Shall have full deck now, len {}", deck.content.len());
+        trace!("Shall have full deck now, len {}", deck.len());
 
         let mut finals = Vec::new();
         for i in winners.iter() {
@@ -622,7 +183,7 @@
         }
 
         for i in winners {
-            finals.push( &players[i].name );
+            finals.push( players[i].get_name() );
         }
         info!("The winner(s): {:?}", &finals);
 
@@ -635,9 +196,10 @@
  */
     }
 
+    // do the type conversions _very_ visibly 
     let elapsed_micro: f64 = stats.start_time.elapsed().as_micros() as f64;
     let game_rounds: f64 = GAME_ROUNDS.into();
-
+    // which is same as the slightly uglier
     let _res: f64 = stats.start_time.elapsed().as_micros() as f64 / <i32 as Into<f64>>::into(GAME_ROUNDS);
 
     println!("Totals (game time {} µs, or {} s; {} µs/game), {} games played ({} shuffles):", 
@@ -650,22 +212,24 @@
 
     // players.sort_by( |a, b| a.total_point.partial_cmp(&b.total_point).unwrap() );    // ASC points
     // players.sort_by( |a, b| b.wins.partial_cmp(&a.wins).unwrap() );                  // DESC wins
-    players.sort_by_cached_key( |x| Reverse(x.wins) );                                  // DESC wins (caching is just for the show)
+    players.sort_by_cached_key( |x| Reverse(x.get_wins()) );                                  // DESC wins (caching is just for the show)
 
     for i in 0..players.len() {
         let p = &players[i];
-        println!("Player {} has wins {}, score {} (busted {} times)", p.name, p.wins, p.total_point, p.rows_busted);
+        println!("Player {} has wins {}, score {} (busted {} times)", 
+            p.get_name(), 
+            p.get_wins(), 
+            p.get_total_points(), 
+            p.get_rows_busted());
     }
 }
 
 #[cfg(test)]
 mod tests {
-    // use core::panic;
     use std::collections::VecDeque;
-
     use rand::Rng;
 
-    use crate::{Card, Player, Row, Table, PlayerCard};
+    use crate::{card::Card, player::{Player, PlayerCard}, row::Row, table::Table};
 
     #[test]
     fn card_values() {
@@ -693,7 +257,7 @@
         }
         // give the pile to player
         p.give_pile(pile);
-        assert!( p.rows_busted == 1 );
+        assert!( p.get_rows_busted() == 1 );
 
         // get back the pile from player
         // p = p.gimme_pile();
@@ -710,7 +274,7 @@
             pile.push_back(c);
         }
         p.give_pile(pile);
-        assert!( p.rows_busted == 2 );
+        assert!( p.get_rows_busted() == 2 );
     }
 
     #[test]
@@ -737,7 +301,7 @@
             // check card value
             assert!( row.last_card_value() == cval, "Last card value mismatch: got {} vs expected {}", row.last_card_value(), cval );
         }
-        assert!( row.cards.len() == 2, "Row contains wrong amount of cards: {}", row.cards.len() );
+        assert!( row.len() == 2, "Row contains wrong amount of cards: {}", row.len() );
     }
 
     #[test]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/player.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,196 @@
+/*** Player ****/
+
+use std::collections::VecDeque;
+use std::mem;
+
+use crate::deck::*;
+use crate::card::*;
+use crate::row::*;
+
+#[derive(Debug)]
+pub(crate) struct Player {
+    name: String,
+    hand: Deck,
+    pile: VecDeque<Card>,
+    game_point: i32,
+    total_point: i32,
+    rows_busted: i32,
+    wins: i32,
+}
+
+impl Player {
+    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 th 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);
+    }
+
+    pub fn get_name(&self) -> &String {
+        &self.name
+    }
+
+    // ask the player their score
+    pub(crate) fn get_points( &self ) -> i32 {
+        self.game_point
+    }
+
+    pub fn get_wins(&self) -> i32 {
+        self.wins
+    }
+
+    pub(crate) fn inc_wins( &mut self ) {
+        self.wins += 1;
+    }
+
+    pub fn get_total_points(&self) -> i32 {
+        self.total_point
+    }
+
+    pub fn get_rows_busted(&self) -> i32 {
+        self.rows_busted
+    }
+
+    // give back cards from the pile
+    pub(crate) fn get_pile( &mut self ) -> VecDeque<Card> {
+        trace!("Player {} gives back their pile", self.name);
+        mem::take( &mut self.pile )
+        // same effect:
+        // self.pile.drain(..).collect()
+
+        // very cumbersome manual fiddling (also reverted...)
+/*         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 it.
+/*     fn _gimme_pile(self)->Self {
+        for c in &self.pile {
+            println!("Throw {} ", c);
+        }
+        self
+    }
+ */
+    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
+    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
+        let mut smallest = 999;
+        // how many rows have the same smallest score
+        let mut same_point = 0;
+        // the first smallest row_id
+        let mut smallest_rowid = 255;
+
+        for rowid in 0 .. rows.len() {
+            // DEBUG
+            // println!("pick_row_for_small_card: rowlen {}, rowid {}", rows.len(), rowid);
+            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
+        
+        } else {
+            // bored, we pick the first now anyway
+            smallest_rowid.try_into().unwrap()
+        }
+        
+    }
+
+}
+
+/*** PlayerCard ****/
+#[derive(Debug)]
+pub(crate) struct PlayerCard {
+    pub player_id: i32,
+    pub card: Card,
+}
+
+impl PlayerCard {
+    fn _get_player(&self) -> i32 {
+        self.player_id
+    }
+}
+
+impl PartialEq for PlayerCard {
+    fn eq(&self, other: &Self) -> bool {
+        self.card == other.card
+    }
+}
+
+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,
+        }
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/row.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,63 @@
+/*** Row ****/
+// a row of cards on the table (max 5)
+
+use std::{collections::VecDeque, mem};
+
+use crate::card::Card;
+
+#[derive(Debug)]
+pub(crate) struct Row {
+    cards: VecDeque<Card>,
+}
+
+impl Row {
+    const MAX_LEN: usize = 5;
+
+    pub(crate) fn new() -> Self {
+        Row {
+            cards: VecDeque::with_capacity(5),
+        }
+    }
+
+    pub(crate) fn push_or_collect( &mut self, card: Card ) -> Option<VecDeque<Card>> {
+        trace!("Called push_or_collect on row {:?}", &self);
+        if self.cards.len() < Self::MAX_LEN {
+            trace!("Less than {} cards, putting at the end", Self::MAX_LEN);
+            self.cards.push_back(card);
+            None
+
+        } else {
+            trace!("Row is full, len {}, maxlen {}", self.cards.len(), Self::MAX_LEN);
+            // row overflow
+            let row_cards = mem::take( &mut self.cards );
+            self.cards.push_back(card);
+            if self.cards.len() != 1 {
+                panic!("New row must have one card, not {}", self.cards.len());
+            }
+            Some(row_cards)
+        }
+    }
+
+    pub(crate) fn take_row( &mut self ) -> VecDeque<Card> {
+        // take cards and empty the row
+        mem::take( &mut self.cards )
+    }
+
+    pub(crate) fn last_card_value(&self) -> i8 {
+        // println!("last_card_value: cards {:?}, len {}", self.cards, self.cards.len());
+        self.cards.get( self.cards.len()-1 ).unwrap().value
+    }
+
+    // sum of row card points
+    pub(crate) fn sum(&self) -> i32 {
+        let mut sum: i32 = 0;
+        self.cards.iter().for_each(|card| {
+            sum += card.points as i32;
+        });
+        sum
+    }
+
+    pub fn len(&self) -> usize {
+        self.cards.len()
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/table.rs	Tue Jan 31 23:25:50 2023 +0100
@@ -0,0 +1,99 @@
+/*** Table ****/
+
+use std::collections::VecDeque;
+
+use crate::card::Card;
+use crate::row::Row;
+use crate::player::PlayerCard;
+
+#[derive(Debug)]
+pub(crate) struct Table {
+    rows: Vec<Row>,
+    player_cards: VecDeque<PlayerCard>, // owned by a player
+}
+
+impl Table {
+    pub(crate) fn new(row_cards: VecDeque<Card>) -> Self {
+        let mut rows = Vec::with_capacity(5);
+        for card in row_cards {
+            // create a new row then put a card into it
+            let mut row = Row::new();
+            if let Some(_c) = row.push_or_collect(card) {
+                panic!("Freshly created row overflowed");
+            }
+            rows.push( row );
+        }
+
+        Table {
+            rows,
+            player_cards: VecDeque::new(),
+        }
+    }
+
+    pub(crate) fn lay_player_card( &mut self, card: Card, player_id: i32 ) {
+        self.player_cards.push_back( PlayerCard { player_id, card } );
+    }
+
+    pub(crate) fn sort_cards( &mut self ) {
+        self.player_cards.make_contiguous().sort_by( |a,b| b.card.cmp(&a.card) );
+    }
+
+    pub(crate) fn has_player_cards( &self ) -> bool {
+        self.player_cards.len() > 0
+    }
+
+    pub(crate) fn get_smallest_player_card( &mut self ) -> PlayerCard {
+        // FIXME: check!
+        self.player_cards.pop_back().expect("out of player cards on table")
+    }
+
+    pub(crate) fn get_closest_row( &self, pcard: &PlayerCard ) -> Option<usize> {
+        // get the row id with last card closest smaller to players'
+        let row_heads = self.get_row_heads();
+        let mut closest_val = None;
+        let mut diff = 127;
+        for i in 0..row_heads.len() {
+            if row_heads[i] < pcard.card.value && pcard.card.value - row_heads[i] < diff {
+                closest_val = Some(i);
+                diff = pcard.card.value - row_heads[i];
+                // println!("DEBUG: pcard {}, row {}, head {}, diff {}, closest {:?}", pcard.card.value, i, row_heads[i], diff, closest_val);
+            }
+        }
+
+        closest_val
+    }
+
+    pub(crate) fn put_card_into_row( &mut self, pcard: PlayerCard, row_id: usize ) -> Option<VecDeque<Card>> {
+        self.rows[row_id as usize].push_or_collect(pcard.card)
+    }
+
+    pub(crate) fn get_row_heads( &self ) -> Vec<i8> {
+        let mut heads: Vec<i8> = Vec::new();
+        for i in 0..self.rows.len() {
+            heads.push( self.rows[i].last_card_value() );
+        }
+        heads
+    }
+
+    // take a whole row and hand it over
+    pub(crate) fn take_row( &mut self, row_id: usize ) -> VecDeque<Card> {
+        self.rows[row_id].take_row()
+    }
+
+    // collect remaining cards in the rows at the end of round
+    pub(crate) fn collect_rows( &mut self ) -> VecDeque<Card> {
+        let mut cards = VecDeque::new();
+        for row in 0..self.rows.len() {
+            self.rows[row]
+                .take_row()
+                .into_iter()
+                .for_each(|card| cards.push_back(card));
+        }
+        cards
+    }
+
+    pub fn peek_rows(&self) -> &Vec<Row> {
+        &self.rows
+    }
+}
+