Comments. Lot of Comments. v1.00
authorPeter Gervai <grin@grin.hu>
Sat, 04 Feb 2023 22:46:13 +0100
changeset 5 0dd7f2c9fd81
parent 4 a2f0cb2b5c13
child 6 9cdd932eceda
Comments. Lot of Comments.
src/card.rs
src/deck.rs
src/main.rs
src/player.rs
src/row.rs
src/table.rs
--- a/src/card.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/card.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,13 +1,20 @@
 use core::fmt;
 
-/*** Card ****/
+/// This is the implementation of a Card. 
+/// Smart card! ;-) Can do a few things by herself.
+
 #[derive(Debug)]
+/// A playing Card. Knows its face `value` 
+/// and the punishment `points` (in the game 
+/// these are symbolised by little bull heads).
 pub struct Card {
     pub value: i8,
     pub points: i8,
 }
 
 impl Card {
+    /// Generate a new card with the face `value` parameter.
+    /// Calculates the `points` for the value.
     pub fn new(value: i8)->Self {
 
         let mut points = 0;
@@ -24,15 +31,17 @@
         }
 
         if value % 10 == value / 10 {
-            // same numbers = 5 points (55=7)
+            // same numbers = 5 points (11,22,33... but 55=7)
             points += 5;
             // println!("NN add 5, val={}, pt={}", value, points);
         }
 
         if points == 0 {
+            // rest of the cards are 1 point
             points = 1;
         }
 
+        // Return a Card
         Card {
             value,
             points,
@@ -41,20 +50,24 @@
 }
 
 impl fmt::Display for Card {
+    /// Print formatter for a card, so it can be written in `println!()`
     fn fmt( &self, f: &mut fmt::Formatter ) -> fmt::Result {
         write!(f, "(Card {}, points {})", self.value, self.points)
     }
 }
 
 impl PartialEq for Card {
+    /// This is used for sorting cards.
     fn eq(&self, other: &Self) -> bool {
         self.value == other.value
     }
 }
 
+/// This is used for sorting cards. Eq is required some by some strict sorting methods.
 impl Eq for Card {} 
 
 impl PartialOrd for Card {
+    /// This is used for sorting cards.
     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
         match self.value.partial_cmp(&other.value) {
             Some(core::cmp::Ordering::Equal) => {None}
@@ -63,6 +76,7 @@
     }
 }
 
+/// This is used for sorting cards. Ord (and Eq) is required some by some strict sorting methods.
 impl Ord for Card {
     fn cmp(&self, other: &Self) -> std::cmp::Ordering {
         self.value.cmp(&other.value)
--- a/src/deck.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/deck.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,11 +1,19 @@
-/*** Deck ****/
+/// This is the implementation of a Deck of cards.
+/// There are two basic kinds:
+/// 1. The Game Deck, automatically generated 104 cards.
+/// 2. Any Deck-type pile, like the hand of a Player.
+/// Descks can be shuffled, cards pushed to bottom and
+/// pulled from top. Maybe others, too.
+/// 
+
 use std::collections::VecDeque;
-
 use rand::Rng;
 
+/// We reference [`Card`]s
 use crate::card::Card;
 
 #[derive(Debug)]
+/// A Deck is an ordered two-ended vector (`VecDeque`) of [`Card`]s.
 pub(crate) struct Deck {
     content: VecDeque<Card>,
 }
@@ -39,10 +47,14 @@
         // * 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 {
+        // naive shuffle: exchange <n> random cards
+        for _ in 1..=500 {
+            // Generate two random positions of cards in Deck
             let c1 = rng.gen_range(0 .. self.content.len());
             let c2 = rng.gen_range(0 .. self.content.len());
+            // If it's not the same card we swap them in the `content` vector.
+            // The `swap()` funtion handles ownership and does not angry 
+            // the borrow checker.
             if c1 != c2 {
                 self.content.swap(c1, c2);
             }
@@ -72,6 +84,8 @@
         self.content.len()
     }
 
+    /// Take a card from inside of the Deck.
+    /// Using an illegal index will `panic!()`, so don't.
     fn _get_nth( &mut self, n: usize ) -> Card {
         if let Some(c) = self.content.remove(n) {
             c
--- a/src/main.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/main.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,65 +1,95 @@
 // #[allow(dead_code, unused)]
-// vigyazz6! autplayer
+
+// vigyazz6! autoplayer
+//
+// This is a program automagically playing a card game called "Vigyazz6!".
+//
+// The rules are rather simple, but I'mrather lazy to reprint it in detail,
+// so it'll be brief.
+// 
+// The code is based on a deck of 104 numbered cards, all of them having
+// a face `value` and punishment `points` (the less the better).
+// There are 2 to 10 players (but above 8 the code shall be modified to
+// deal less cards), and the game has 5 rows of maximum 5 cards on the
+// table. 
+// All players throw cards at once, and they are put in the row with 
+// closest less value; if there is none, they have to pick and take
+// any row. When a row is full (5) they have to take the row and their
+// card starts a new row head.
+// When players are out of cards the least points collected wins.
+//
+// Important: I do not use `unsafe` code, this is all tightly controlled.
 //
 
+/// We use panic in several places where the code shall not go. 
 use core::panic;
+/// `VecDeque` is a Vec which can be pushed/popped at both ends
+/// `time::Instant` is used to measure running time.
+/// `cmp::Reverse` used for reverse sorting.
 use std::{collections::VecDeque, time::Instant, cmp::Reverse};
 
-use crate::{deck::Deck, player::Player, table::Table};
-// use rand::Rng;
-// use std::mem;
+/// We use this `pretty_env_logger` as a logging framework.
+extern crate pretty_env_logger;
+#[macro_use] extern crate log;
 
+// I import structures from my module files to use here.
+use crate::{deck::Deck, player::{Player, PlayerCard}, table::Table};
+
+// Here we read the files and "get to know" what's in them. This isn't including, only scanning.
 mod deck;
 mod table;
 mod player;
 mod card;
 mod row;
 
-extern crate pretty_env_logger;
-#[macro_use] extern crate log;
-
+// We play this many game rounds. You want to keep this under 3 for any debug level above "warnings".
 const GAME_ROUNDS: i32 = 100_000;
 
 fn main() {
+    // Env variable makes the logger to log more or less:
     // RUST_LOG=debug cargo run
     pretty_env_logger::init();
-    info!("Program starting.");
+    info!("Program starting."); // info level logging
     game();
     info!("End of run.");
 }
 
-// Card
-// Deck
-// Player
-// Row
-
-
 
 /*** Game ****/
 
+/// `GameStat` structure collects global statistics about the run.
 struct GameStat {
     game_count: i64,
     shuffle_count: i64,
     start_time: Instant, // use start_time.elapsed().as_nanos() or .as_secs()
 }
 
+/// Play all the game rounds.
 fn game() {
+    // Whole game statistics stored here
     let mut stats = GameStat { game_count:0, shuffle_count: 0, start_time: Instant::now() };
 
+    // Create the game deck with all the card (ordered). Open box. Remove shrink wrap. :-)
     let mut deck = Deck::new();
 
-    let player_names = vec![ "grin", "moni", "icbalint", "orsi", "topi", "kgb", "zsu", "csilla" ];
+    // Create the players (up to 8 w/o changing the hand cards)
+    let player_names = vec![ "peter", "moni", "icbalint", "orsi", "topi", "kgb", "zsu", "csilla" ];
+    // Iterate on player names, create Player struct from them and collect them into a Vec'tor.
+    // (On the borrow level we don't consume the player_names vector [using `iter()` instead of `into_iter()`].)
     let mut players: Vec<Player> = player_names.iter().map( |n| Player::new(n.to_string()) ).collect();
 
-    let player_count = players.len(); // pc - 1
+    // We use this often, so take it now.
+    let player_count = players.len(); // = <number of players> - 1
 
+    // Start playing - GAME_ROUNDS rounds.
     for cnt_game in 1..=GAME_ROUNDS {
-        debug!("Game round {} starts", cnt_game);
+        debug!("Game round {} starts", cnt_game); // debug level logging
+        // Shuffle the deck (using various methods)
         deck.shuffle();
         stats.shuffle_count += 1;
         stats.game_count += 1;
 
-        // dealing
+        // dealing 10 cards for each player
         debug!("Dealing.");
         for _i in 1..=10 {
             for player in 0 .. player_count {
@@ -67,75 +97,88 @@
             }
         }
 
-        // we need 5 crds from deck
+        // we need 5 cards from deck to build the rows
         debug!("Building the rows.");
         let mut cards = VecDeque::new();
+        // This is another way to write "for _ in (1..=5) { ... }"
         (1..=5).for_each(|_| {
             cards.push_back( deck.pop().expect("deck empty before starting the game") );
         });
-        // println!("We push 5 cards to rows: {:?}\n", cards);
+        trace!("We pushed 5 cards to rows: {:?}\n", cards);
+
+        // Create the Table (contains the Deck, the Rows (with 5 starting `cards`) and occasional cards thrown by Players)
         let mut table = Table::new(cards);
 
-        // DEBUG
-/*         println!("Table: {:?}\n", table);
-        println!("PLayers: {:?}\n", players);
-        println!("Deck: {:?}\n", deck);
+/*      debug!("Table: {:?}\n", table);
+        debug!("Players: {:?}\n", players);
+        debug!("Deck: {:?}\n", deck);
  */        
         debug!("We have the table ready: {:?}", table);
 
-        // playing
+        // playing one game, players taking turns
         debug!("Players start taking turns");
+        // Since players have 10 cards dealt we have exactly 10 turns.
         for turn in 1..=10 {
             debug!("Turn {}!", turn);
             trace!("The table: {:?}", table);
 
-            // everyone puts a card face down
+            // Everyone puts a card "face down" (Rust promised not to peek).
+            // If I used the `players.for_each()` form I would hit the borrow checker:
+            // `players` would be repeatedly borrowed mutable and program wouldn't compile.
             for player in 0 .. player_count {
-                let player_id: i32 = player.try_into().unwrap();
                 // get a card from the player
-                let topcard = players[player].throw_card();
+                let player_id: i32 = player.try_into().unwrap();    // convert `usize` array index into `i32` [that was an unnecessary hassle: in fact I should rewrite this using usize everywhere]
+                let topcard = players[player].throw_card();         // If Player [module] was smart this would be a chosen card, but it would need player
+                                                                    // not just brains but possibility to peek at the rows. This wasn't in the plan, so 
+                                                                    // we just take the top card in hand.
                 // put it on the table ("turned face down")
-                table.lay_player_card( topcard, player_id );
+                table.lay_player_card( topcard, player_id );        // We actually move the card variable with its ownership everywhere, so no &refs.
             }
 
-            // process cards
+            // Process cards on the Table.
             debug!("The Table process the throws.");
+            // Sort the cards by `value` the players have thrown.
             table.sort_cards();
 
+            // Pick them one by one, from smallest to larger ones
             while table.has_player_cards() {
-                let smallest = table.get_smallest_player_card();
+                let smallest: PlayerCard = table.get_smallest_player_card(); // I just wrote the PlayerCard type to show; Rust is smart enough to know.
                 trace!("Take smallest card {:?}", &smallest);
 
-                let closest_row = table.get_closest_row(&smallest);
+                // Find the row with the closest smallest card, or None if smaller than any row head.
+                let closest_row = table.get_closest_row(&smallest); // That is an Option<usize>.
                 trace!("Choose closest row: {:?}", closest_row);
 
                 match closest_row {
                     Some(rowid) => {
+                        // We have to put it at the end of `rowid`.
                         debug!("Putting down card into row {}", rowid);
-                        let player_id: usize = smallest.player_id.try_into().unwrap();
-                        let overflow = table.put_card_into_row(smallest, rowid);
+                        let player_id: usize = smallest.player_id.try_into().unwrap(); // By "just" indexing `players` (by `player_id`) I have avoided borrowing it and get into trouble later.
+                        // Try to put the card to the end of the row, or collect full row first
+                        let overflow = table.put_card_into_row(smallest, rowid); // And this is Option<VecDeque<Card>>.
                         if let Some(cards) = overflow {
-                            // row is full, got pile
-                            debug!("Row is busted, {} collects", players[player_id].get_name());
-                            // player gets pile, card gets into row head
+                            // Row is full, we got pile ("bust")
+                            debug!("Row is busted, {} collects", players[player_id].get_name());    
+                            // Player gets pile, thrown card was put into row head
                             players[ player_id ].give_pile( cards );
                         }
                     },
                     None => {
-                        // card too small, need to pick row!
-                        let player_id: usize = smallest.player_id.try_into().unwrap();
+                        // Card too small, need to pick any row to take!
+                        let player_id: usize = smallest.player_id.try_into().unwrap(); // We _directly_ access `PlayerCard.player_id` structure member, because borrow checker wasn't helping my mental hygiene.
                         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);
+                        // Pick any row to take
                         let rowid = players[ player_id ].pick_row_for_small_card(table.peek_rows(), &smallest.card);
                         trace!("Picked row {}", rowid);
-                        // take the row cards
+                        // take the row cards ("bust")
                         let cards = table.take_row(rowid);
                         trace!("Took cards: {:?}", cards);
+                        // and give them to the player who owns the card
                         players[ player_id ].give_pile( cards );
                         // put new card in the row
                         let overflow = table.put_card_into_row(smallest, rowid);
                         if let Some(_) = overflow {
+                            // If this fires then I have fucked something up. :-)
                             panic!("Player took whole row and it's already full");
                         }
                     }
@@ -147,8 +190,9 @@
         info!("Round finished, len is {} µsec", stats.start_time.elapsed().as_micros());
 
         debug!("End of round, counting and collecting back piles");
+        // We collect the winner(s) and their score here
         let mut winners: Vec<usize> = Vec::new();
-        let mut winscore: i32 = i32::MAX-1;
+        let mut winscore: i32 = i32::MAX-1; // Getting facy here about "larger than any valid value".
 
         for i in 0..player_count {
             info!("Player {} has {} points", players[i].get_name(), players[i].get_points());
@@ -165,41 +209,36 @@
             }
             trace!("The list of winners is {:?}", winners);
 
-            // get pile from player
+            // get pile from Player
             let cards = players[i].get_pile();
-            // and give it back to the deck
+            // and give it back to the Deck
             deck.push_cards(cards);
-            // close player round and update stats
+            // close Player round and update stats
             players[i].close_round();
         }
 
-        // collect cards from table
+        // collect remaining Cards from Table
         deck.push_cards( table.collect_rows() );
         trace!("Shall have full deck now, len {}", deck.len());
 
-        let mut finals = Vec::new();
+        // This is a Vec of `player_id`s, i is a &ref
         for i in winners.iter() {
-            players[*i].inc_wins();
+            players[*i].inc_wins(); // Increment win count of &Vec<usize> player_id
         }
 
+        // Collect the names of the winners.
+        let mut finals = Vec::new();
         for i in winners {
             finals.push( players[i].get_name() );
         }
         info!("The winner(s): {:?}", &finals);
-
-/*         players.iter().for_each(|player| {
-            println!("Player {} has {} points", player.name, player.game_point);
-            let cards = player.get_pile();
-            deck.push_cards(cards);
-            player.close_round();
-        });
- */
     }
 
-    // do the type conversions _very_ visibly 
+    // Do the type conversions _very_ visibly. `as_micros()` results `u128`
     let elapsed_micro: f64 = stats.start_time.elapsed().as_micros() as f64;
+    // and `GAME_ROUNDS` is `i32`. We'll use `elapsed_micro/game_rounds` later.
     let game_rounds: f64 = GAME_ROUNDS.into();
-    // which is same as the slightly uglier
+    // …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):", 
@@ -212,10 +251,11 @@
 
     // 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.get_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); using std::cmp::Reverse
 
+    // Print out totals
     for i in 0..players.len() {
-        let p = &players[i];
+        let p = &players[i]; // the rest looks simpler by using this. (Seems to confuse rust-analyzer in codium though.)
         println!("Player {} has wins {}, score {} (busted {} times)", 
             p.get_name(), 
             p.get_wins(), 
--- a/src/player.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/player.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,6 +1,7 @@
-/*** Player ****/
+/// 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::*;
@@ -8,6 +9,15 @@
 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,
@@ -19,6 +29,7 @@
 }
 
 impl Player {
+    /// Creates a new [`Player`] with a given `name`.
     pub(crate) fn new(name: String)->Self {
         debug!("Player {} created", name);
         Player {
@@ -32,13 +43,13 @@
         }
     }
 
-    // get one card from th dealer
+    /// 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
+    /// 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);
@@ -48,7 +59,7 @@
         }
     }
 
-    // get a busted row of cards
+    /// 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;
@@ -58,40 +69,49 @@
         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
+    /// 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 pile
+    /// 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:
+
+        // same effect (`drain()` also transfers ownership):
         // self.pile.drain(..).collect()
 
-        // very cumbersome manual fiddling (also reverted...)
-/*         let mut throw: Vec<Card> = Vec::new();
+        // 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() );
         }
@@ -100,7 +120,7 @@
     }
 
     // I can do this just because I *throw away* c!
-    // doesn't work if I want to use it.
+    // Doesn't work if I want to use/return it.
 /*     fn _gimme_pile(self)->Self {
         for c in &self.pile {
             println!("Throw {} ", c);
@@ -108,6 +128,8 @@
         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());
@@ -122,22 +144,27 @@
         self.game_point = 0;
     }
 
-    // card too small: pick a row to collect from the rows
+    /// 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
+        // 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
+        // the first smallest row_id (start by larger than max)
         let mut smallest_rowid = 255;
 
         for rowid in 0 .. rows.len() {
-            // DEBUG
-            // println!("pick_row_for_small_card: rowlen {}, rowid {}", rows.len(), rowid);
+            // 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 {
@@ -154,10 +181,11 @@
 
         if same_point < 1 {
             // we have one smallest row
-            smallest_rowid.try_into().unwrap()      // it's tiny, will fit into u8
+            smallest_rowid.try_into().unwrap()      // it's tiny, will fit into u8, so unwrap() is safe
         
         } else {
-            // bored, we pick the first now anyway
+            // 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()
         }
         
@@ -165,7 +193,7 @@
 
 }
 
-/*** PlayerCard ****/
+/// `PlayerCard` is a [`Card`] associated with a Player.
 #[derive(Debug)]
 pub(crate) struct PlayerCard {
     pub player_id: i32,
@@ -173,17 +201,20 @@
 }
 
 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) {
--- a/src/row.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/row.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,24 +1,37 @@
-/*** Row ****/
-// a row of cards on the table (max 5)
+/// Implementation of a Row of Cards on the Table (max 5)
 
+// We use std::mem::take to do tricks with vector members and ownership.
 use std::{collections::VecDeque, mem};
 
 use crate::card::Card;
 
 #[derive(Debug)]
+/// A `Row` of [`Card`]s, in a two-ended vector (`VecDeque`).
+/// A Row is smart and can do a few things on herself.
 pub(crate) struct Row {
     cards: VecDeque<Card>,
 }
 
 impl Row {
+    /// The maximum length of a Row. More cards cause overflow and force collection.
     const MAX_LEN: usize = 5;
 
+    /// Create a new [`Row`] with capacity of 5 [`Card`]s.
     pub(crate) fn new() -> Self {
         Row {
             cards: VecDeque::with_capacity(5),
         }
     }
 
+    /// Push a [`Card`] to the end of the Row.
+    /// If it would make Row over maximum length the function 
+    /// returns the content of the row, and then push the new
+    /// Card as the new Row head.
+    /// Otherwise return None.
+    /// # Arguments
+    /// - [`Card`] - the new card to put into the Row
+    /// # Returns
+    /// - `Option<VecDequeue<Card>>` - None or Some(cards) to be collected from Row
     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 {
@@ -28,21 +41,28 @@
 
         } else {
             trace!("Row is full, len {}, maxlen {}", self.cards.len(), Self::MAX_LEN);
-            // row overflow
+            // Row overflow. We take out `cards` from `self` with its ownership and 
+            // leave the default (empty VecDeque) in its place, without disturbing
+            // `self` ownership.
             let row_cards = mem::take( &mut self.cards );
+            // We put new card as new Row head.
             self.cards.push_back(card);
             if self.cards.len() != 1 {
                 panic!("New row must have one card, not {}", self.cards.len());
             }
+            // Return the collected old Row content
             Some(row_cards)
         }
     }
 
+    /// Take out all `cards` (and their ownership) and return them.
     pub(crate) fn take_row( &mut self ) -> VecDeque<Card> {
         // take cards and empty the row
         mem::take( &mut self.cards )
     }
 
+    /// Return the `value` of the last card in the Row.
+    /// This is the largest value since the Row is always ordered.
     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
@@ -57,6 +77,10 @@
         sum
     }
 
+    #[allow(dead_code)]
+    /// We could use this, but... borrow checker, you know. Needs more love.
+    /// I could have used `_len` to shut up the dead_code warning, so this is
+    /// another example to do it the other way.
     pub fn len(&self) -> usize {
         self.cards.len()
     }
--- a/src/table.rs	Tue Jan 31 23:25:50 2023 +0100
+++ b/src/table.rs	Sat Feb 04 22:46:13 2023 +0100
@@ -1,4 +1,4 @@
-/*** Table ****/
+/// Implemantation of the playing Table.
 
 use std::collections::VecDeque;
 
@@ -7,67 +7,94 @@
 use crate::player::PlayerCard;
 
 #[derive(Debug)]
+/// A playing Table, containing 5 [`Row`]s and some [`PlayerCard`]s.
+/// A Table can do some useful function with its cards, like picking
+/// closest row or moving cards.
 pub(crate) struct Table {
     rows: Vec<Row>,
     player_cards: VecDeque<PlayerCard>, // owned by a player
 }
 
 impl Table {
+    /// Creates a new `Table`, filling Rows from `row_cards`.
     pub(crate) fn new(row_cards: VecDeque<Card>) -> Self {
+        // We have exactly 5 Rows.
         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) {
+            if let Some(_) = row.push_or_collect(card) {
+                // Row should have one card, so... mustn't happen.
                 panic!("Freshly created row overflowed");
             }
+            // Put the new row onto the Table.
             rows.push( row );
         }
 
+        // And return the newly created Table.
         Table {
             rows,
             player_cards: VecDeque::new(),
         }
     }
 
+    /// Gets a [`Card`] from a [`Player`] and put it into the `player_cards` area,
+    /// remembering whose (`player_id`) card it was.
     pub(crate) fn lay_player_card( &mut self, card: Card, player_id: i32 ) {
         self.player_cards.push_back( PlayerCard { player_id, card } );
     }
 
+    /// Sort the [`Card`]s thrown by the [`Player`]s, since we'd need
+    /// to get them ordered by value later.
     pub(crate) fn sort_cards( &mut self ) {
+        // Sorting a normal VecDeque is not possible since it may contain
+        // holes, so we need to de-hole it first, then it's sortable (through
+        // a returned pointer slice).
         self.player_cards.make_contiguous().sort_by( |a,b| b.card.cmp(&a.card) );
     }
 
+    /// Returns true if we have unprocessed Player cards on the table.
     pub(crate) fn has_player_cards( &self ) -> bool {
         self.player_cards.len() > 0
     }
 
+    /// Return the smallest player card on the table.
+    /// FIXME: shall check whether it's ordered.
     pub(crate) fn get_smallest_player_card( &mut self ) -> PlayerCard {
-        // FIXME: check!
+        // FIXME: check orderedness!
+        // FIXME: check asking when empty!
         self.player_cards.pop_back().expect("out of player cards on table")
     }
 
+    /// Return the row which is closest to the `pcard` arg, or None if
+    /// all Row tails are larger.
     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 row_tails = self.get_row_tails();
         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);
+        let mut diff = 127; // larger than any
+        // Check all the row tail cards
+        for i in 0..row_tails.len() {
+            if row_tails[i] < pcard.card.value && pcard.card.value - row_tails[i] < diff {
+                // it is smaller than pcard and closer than the old closest one: match!
+                // Store the row index
+                closest_val = Some(i); 
+                diff = pcard.card.value - row_tails[i];
+                // debug!("DEBUG: pcard {}, row {}, head {}, diff {}, closest {:?}", pcard.card.value, i, row_heads[i], diff, closest_val);
             }
         }
 
         closest_val
     }
 
+    /// Put a [`Card`] into the `row_id` Row (tail).
+    /// Returns `None` if ok or `Some(cards)` when the Row is full.
     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)
+        // We actually ask the Row to do it properly.
+        self.rows[row_id].push_or_collect(pcard.card)
     }
 
-    pub(crate) fn get_row_heads( &self ) -> Vec<i8> {
+    pub(crate) fn get_row_tails( &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() );
@@ -92,6 +119,7 @@
         cards
     }
 
+    /// Return a non-mutable borrow of the rows to look at
     pub fn peek_rows(&self) -> &Vec<Row> {
         &self.rows
     }