// vigyazz6! autplayer//usecore::{fmt,panic};usestd::collections::VecDeque;userand::Rng;usestd::mem;fnmain(){game();}#[derive(Debug)]structCard{value: i8,points: i8,}implCard{fnnew(value: i8)->Self{letmutpoints=0;ifvalue%10==5{// ends with 5 = 2 pointpoints=2;// println!("*5 add 1, val={}, pt={}", value, points);}ifvalue%10==0{// ends with 0 = 3 pointpoints=3;// println!("*0 add 2, val={}, pt={}", value, points);}ifvalue%10==value/10{// same numbers = 5 points (55=7)points+=5;// println!("NN add 5, val={}, pt={}", value, points);}ifpoints==0{points=1;}Card{value,points,}}}implfmt::DisplayforCard{fnfmt(&self,f: &mutfmt::Formatter)-> fmt::Result{write!(f,"(Card {}, points {})",self.value,self.points)}}implPartialEqforCard{fneq(&self,other: &Self)-> bool{self.value==other.value}}implEqforCard{}implPartialOrdforCard{fnpartial_cmp(&self,other: &Self)-> Option<std::cmp::Ordering>{matchself.value.partial_cmp(&other.value){Some(core::cmp::Ordering::Equal)=>{None}ord=>returnord,}}}implOrdforCard{fncmp(&self,other: &Self)-> std::cmp::Ordering{self.value.cmp(&other.value)}}#[derive(Debug)]structDeck{content: VecDeque<Card>,}implDeck{fnnew_empty()-> Self{Deck{content: VecDeque::new(),}}fnnew()-> Self{letcontent=(1..104).into_iter().map(|n|Card::new(n)).collect();Deck{content,}}fnshuffle(&mutself){letmutrng=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 cardsfor_iin1..=500{letc1=rng.gen_range(0..self.content.len());letc2=rng.gen_range(0..self.content.len());ifc1!=c2{self.content.swap(c1,c2);}}}// get top card from deckfnpop(&mutself)-> Option<Card>{self.content.pop_front()}// put a card into the bottom of the deckfnpush(&mutself,c: Card){self.content.push_back(c);}fnlen(&self)-> usize{self.content.len()}fnget_nth(&mutself,n: usize)-> Card{ifletSome(c)=self.content.remove(n){c}else{panic!("get_nth: index {} out of bounds ({})!",n,self.content.len());}}}#[derive(Debug)]structPlayer{name: String,hand: Deck,pile: Vec<Card>,game_point: i32,total_point: i32,rows_busted: i32,}implPlayer{fnnew(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 dealerfnget_card(&mutself,card: Card){self.hand.push(card);}// throw a card from hand to the tablefnthrow_card(&mutself)->Card{ifletSome(c)=self.hand.pop(){c}else{panic!("throw_card: Player {} has no card in hand!",self.name);}}// get a busted row of cardsfnget_pile(&mutself,cards: VecDeque<Card>){forcincards.into_iter(){self.game_point+=c.pointsasi32;self.pile.push(c);}self.rows_busted+=1;}// ask the player their scorefntell_points(self)-> i32{self.game_point}// give back cards from the pilefngive_pile(&mutself)-> Vec<Card>{mem::take(&mutself.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 } */fnclose_round(&mutself){ifself.hand.len()>0{panic!("Closing round when {} has {} cards in hand",self.name,self.hand.len());}ifself.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)#[derive(Debug)]structRow{cards: VecDeque<Card>,}implRow{constMAX_LEN: usize=5;fnnew()-> Self{Row{cards: VecDeque::new(),}}fnpush_or_collect(&mutself,card: Card)-> Option<VecDeque<Card>>{ifself.cards.len()<Self::MAX_LEN{self.cards.push_back(card);None}else{// row overflowletrow_cards=mem::take(&mutself.cards);self.cards.push_back(card);ifself.cards.len()!=1{panic!("New row must have one card, not {}",self.cards.len());}Some(row_cards)}}fnlast_card_value(&self)-> i8{println!("last_card_value: cards {:?}, len {}",self.cards,self.cards.len());self.cards.get(self.cards.len()-1).unwrap().value}}#[derive(Debug)]structPlayerCard{player_id: i32,card: Card,}implPlayerCard{fnget_player(&self)-> i32{self.player_id}}implPartialEqforPlayerCard{fneq(&self,other: &Self)-> bool{self.card==other.card}}implPartialOrdforPlayerCard{fnpartial_cmp(&self,other: &Self)-> Option<std::cmp::Ordering>{matchself.card.partial_cmp(&other.card){Some(core::cmp::Ordering::Equal)=>{None}ord=>returnord,}}}#[derive(Debug)]structTable{rows: Vec<Row>,player_cards: Vec<PlayerCard>,// owned by a player}implTable{fnnew(row_cards: Vec<Card>)-> Self{letmutrows=Vec::new();forcardinrow_cards{// create a new row then put a card into itletmutrow=Row::new();ifletSome(c)=row.push_or_collect(card){panic!("Freshly created row overflowed");}rows.push(row);}Table{rows,player_cards: Vec::new(),}}fnlay_player_card(&mutself,card: Card,player_id: i32){self.player_cards.push(PlayerCard{player_id,card});}fnsort_cards(&mutself){self.player_cards.sort_by(|a,b|b.card.cmp(&a.card));}fnget_smallest_player_card(&mutself)-> PlayerCard{self.player_cards.pop().expect("out of player cards on table")}fnget_closest_row(&self,pcard: &PlayerCard)-> Option<i8>{// get the row id with last card closest smaller to players'todo!()}fnput_card_into_row(&mutself,pcard: PlayerCard,row_id: i8)-> Option<VecDeque<Card>>{self.rows[row_idasusize].push_or_collect(pcard.card)}}fngame(){letmutcnt_shuffle=0;letmutdeck=Deck::new();letplayer_names=vec!["grin","moni","icbalint","orsi","topi","kgb","zsu","csilla"];letmutplayers: Vec<Player>=player_names.iter().map(|n|Player::new(n.to_string())).collect();letplayer_count=players.len();// pc - 1for_cnt_gamein1..=2{deck.shuffle();cnt_shuffle+=1;// dealingforiin1..=10{forplayerin0..player_count{players[player].get_card(deck.pop().expect("Deck is empty while dealing to players"));}}// we need 5 crds from deckletmutcards=Vec::new();foriin1..=5{cards.push(deck.pop().expect("deck empty before starting the game"));}println!("We push 5 cards to rows: {:?}\n",cards);letmuttable=Table::new(cards);// DEBUGprintln!("Table: {:?}\n",table);println!("PLayers: {:?}\n",players);println!("Deck: {:?}\n",deck);// playingforturnin1..=10{// everyone puts a card face downforplayerin0..player_count{letplayer_id: i32=player.try_into().unwrap();// get a card from the playerlettopcard=players[player].throw_card();// put it on the table ("turned face down")table.lay_player_card(topcard,player_id);}// process cardstable.sort_cards();letsmallest=table.get_smallest_player_card();letclosest_row=table.get_closest_row(&smallest);matchclosest_row{Some(rowid)=>{letplayer_id: usize=smallest.player_id.try_into().unwrap();letoverflow=table.put_card_into_row(smallest,rowid);ifletSome(cards)=overflow{// row is full, got pile// player gets pile, card gets into row headplayers[player_id].get_pile(cards);}},None=>{// card too small, need to pick row!todo!();}}}// end of round// recollect deckpanic!("FInish now.");}}#[cfg(test)]modtests{usecore::panic;usestd::collections::VecDeque;userand::Rng;usecrate::{Card,Player,Row};#[test]fncard_values(){letcard_values=vec![1,2,5,10,33,55,77];letcard_points=vec![1,1,2,3,5,7,5];foriin1..card_values.len(){letc=Card::new(card_values[i]);letp=c.points;assert!(p==card_points[i],"card={} card points={} i={} expected point={}",card_values[i],p,i,card_points[i]);}}#[test]fnplayer_take_pile(){// create a playerletmutp=Player::new("bob".to_string());// create a pileletmutpile=VecDeque::new();letmutrefpile=Vec::new();foriin5..10{letc=Card::new(i);pile.push_back(c);letc=Card::new(i);refpile.push(c);}// add the pile to playerp.get_pile(pile);assert!(p.rows_busted==1);// get back the pile from player// p = p.gimme_pile();letpile=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 itemsassert!(pile.iter().all(|item|refpile.contains(item)));letmutpile=VecDeque::new();foriin4..=9{letc=Card::new(i);pile.push_back(c);}p.get_pile(pile);assert!(p.rows_busted==2);}#[test]fnrow_push(){letmutrow=Row::new();letmutrefcard=Vec::new();// reference vec to checkforiin1..=7{letcval=i+5;letcard=Card::new(cval);// push a card into the rowifletSome(cards)=row.push_or_collect(card){// got the overflowprintln!("Got overflow row at {}!",i);assert!(i==6,"Overflow at wrong position: {} != 6",i);// we need to get the proper vecassert!(cards.iter().all(|item|refcard.contains(item)),"Got cards {:?}",cards);}else{println!("push success {}",i);}// remember the correct vec for checkingletcard=Card::new(cval);refcard.push(card);// check card valueassert!(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());}#[test]fnsort_cards(){letmutcards: Vec<Card>=Vec::new();letmutrng=rand::thread_rng();foriin1..50{letn=rng.gen_range(1..104);cards.push(Card::new(n));}cards.sort();foriin1..cards.len(){assert!(cards[i-1].value<=cards[i].value,"Bad ordering: {} > {}",cards[i-1].value,cards[i].value);}}}/*- 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*/