src/main.rs
author Peter Gervai <grin@grin.hu>
Sun, 29 Jan 2023 21:41:10 +0100
changeset 0 a95b84125269
child 1 5f81068a8a88
permissions -rw-r--r--
Add repo.

// vigyazz6! autplayer
//

use core::fmt;
use std::collections::VecDeque;
use rand::Rng;
use std::mem;

fn main() {
    println!("Hello, world!");
}

#[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
    }
}

struct Deck {
    content: VecDeque<Card>,
}

impl Deck {
    fn new_empty() -> Self {
        Deck {
            content: VecDeque::new(),
        }
    }

    fn new() -> Self {
        let content = (1..104).into_iter().map( |n| Card::new(n) ).collect();
        Deck {
            content,
        }
    }

    fn shuffle( &mut self ) {
        let mut rng = rand::thread_rng();

        // 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(1 .. self.content.len());
            let c2 = rng.gen_range(1 .. self.content.len());
            if c1 != c2 {
                self.content.swap(c1, c2);
            }
        }
    }

    // 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 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());
        }
    }
}

struct Player {
    name: String,
    hand: Deck,
    pile: Vec<Card>,
    game_point: i32,
    total_point: i32,
    rows_busted: i32,
}

impl Player {
    fn new(name: String)->Self {
        Player {
            name,
            hand: Deck::new_empty(),
            pile: Vec::new(),
            game_point: 0,
            total_point: 0,
            rows_busted: 0,
        }
    }

    // get one card from th dealer
    fn get_card( &mut self, card: Card ) {
        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() {
            c
        } else {
            panic!("throw_card: Player {} has no card in hand!", self.name);
        }
    }

    // get a busted row of cards
    fn get_pile( &mut self, cards: Vec<Card> ) {
        for c in cards.into_iter() {
            self.game_point += c.points as i32;
            self.pile.push(c);
        }
        self.rows_busted += 1;
    }

    // ask the player their score
    fn tell_points( self ) -> i32 {
        self.game_point
    }

    // give back cards from the pile
    fn give_pile( &mut self ) -> Vec<Card> {
        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
    }
 */
    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());
        }

        self.total_point += self.game_point;
        self.game_point = 0;
    }
}

// a row of cards on the table (max 5)
struct Row {
    cards: VecDeque<Card>,
}

impl Row {
    const MAX_LEN: usize = 5;

    fn new() -> Self {
        Row {
            cards: VecDeque::new(),
        }
    }

    fn push_or_collect( &mut self, card: Card ) -> Option<VecDeque<Card>> {
        if self.cards.len() < Self::MAX_LEN {
            self.cards.push_back(card);
            None

        } else {
            // 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 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
    }
}

struct PlayerCard {
    player_id: u32,
    card: Card,
}

struct Table {
    rows: Vec<Row>,
    player_cards: Vec<PlayerCard>, // owned by a player
}




fn game() {
/*
    let mut deck = deck_init();
    let mut players = Vec::new();

    for cnt_game in (1..100) {

    }
     */
}

#[cfg(test)]
mod tests {
    use crate::{Card, Player, Row};

    #[test]
    fn card_values() {
        let card_values = vec![1,2,5,10,33,55,77];
        let card_points = vec![1,1,2,3, 5, 7, 5];
        for i in 1 .. card_values.len() {
            let c = Card::new( card_values[i] );
            let p = c.points;
            assert!(p == card_points[i], "card={} card points={} i={} expected point={}", card_values[i], p, i, card_points[i]);
        }
    }

    #[test]
    fn player_take_pile() {
        // create a player
        let mut p = Player::new("bob".to_string());
        // create a pile
        let mut pile = Vec::new();
        let mut refpile = Vec::new();
        for i in 5..10 {
            let c = Card::new(i);
            pile.push(c);
            let c = Card::new(i);
            refpile.push(c);
        }
        // add the pile to player
        p.get_pile(pile);
        assert!( p.rows_busted == 1 );

        // get back the pile from player
        // p = p.gimme_pile();
        let pile = p.give_pile();
        
        // the pile we got shall be same as the pile we gave
        // this check is O(n^2), doesn't matter for less than 100 items
        assert!( pile.iter().all( |item| refpile.contains(item)) );

        let mut pile = Vec::new();
        for i in 4..9 {
            let c = Card::new(i);
            pile.push(c);
        }
        p.get_pile(pile);
        assert!( p.rows_busted == 2 );
    }

    #[test]
    fn row_push() {
        let mut row = Row::new();
        let mut refcard = Vec::new();   // reference vec to check
        for i in 1..=7 {
            let cval = i+5;
            let card = Card::new(cval);
            // push a card into the row
            if let Some(cards) = row.push_or_collect(card) {
                // got the overflow
                println!("Got overflow row at {}!", i);
                assert!( i == 6, "Overflow at wrong position: {} != 6", i );
                // we need to get the proper vec
                assert!( cards.iter().all( |item| refcard.contains(item) ), "Got cards {:?}", cards ); 
            } else {
                println!("push success {}", i);
            }
            // remember the correct vec for checking
            let card = Card::new(cval);
            refcard.push(card);

            // 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() );
    }
}

/*

- 1-104 lap, 
    - *5 - 2
    - *0 - 3
    - NN - 5
    - 55 - 7
- deck
- jatekosok; kezben tartott lapok; elvitt lapok; pontszamok; counter: elvitt sorok, okrok, total pont
-- keveres (keveresek szama)
-- osztas: mindenki 10 lap
-- start sorok: 5 kartya
- jatek (jatekok szama)
-- mindenki a felso lapot kiteszi
-- szamsorrendben felkerulnek, aki viszi, viszi
--- ha kisebb, akkor dontes
---- ha van legkevesebb, viszi
---- ha tobb min van, random valaszt
- osszesites
-- okrok, elvitt sorok
-- keveresek szama, jatekok szama, eltelt ido
- deck osszegyujtes


*/