diff -r 000000000000 -r a95b84125269 src/main.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.rs Sun Jan 29 21:41:10 2023 +0100 @@ -0,0 +1,371 @@ +// 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, +} + +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 { + 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, + 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 ) { + 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 { + mem::take( &mut self.pile ) + // same effect: + // self.pile.drain(..).collect() + + // very cumbersome manual fiddling (also reverted...) +/* let mut throw: Vec = 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, +} + +impl Row { + const MAX_LEN: usize = 5; + + fn new() -> Self { + Row { + cards: VecDeque::new(), + } + } + + fn push_or_collect( &mut self, card: Card ) -> Option> { + 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, + player_cards: Vec, // 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 + + +*/ \ No newline at end of file