Go Fish/Rust

From Rosetta Code
Revision as of 17:50, 11 May 2022 by rosettacode>Cianhauser (go fish rust)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Go Fish/Rust is part of Go_Fish. You may find other members of Go_Fish at Category:Go_Fish.

Rust implementation of Go Fish.

<lang Rust> use rand::thread_rng; use rand::seq::SliceRandom; use std::io::Write;

// parameters const STARTING_HAND_SIZE: usize = 9; const NUM_SUITS: usize = 4;

struct Deck {

   cards: Vec<String>,

}

impl Deck {

   fn new() -> Self {
       Self { // initializes deck with cards
           cards: {
               let mut deck = vec![];
               for i in "2 3 4 5 6 7 8 9 10 J Q K A".split(" ") {
                   for _ in 0..NUM_SUITS {
                       deck.push(String::from(i));
                   }
               }
               deck
           }
       }
   }
   fn shuffle(&mut self) {
       self.cards.shuffle(&mut thread_rng());
   }
   fn done(&self) -> bool {
       self.cards.len() == 0
   }
   fn draw(& mut self) -> String {
       self.cards.pop().unwrap()
   }

}

struct Player {

   hand: Vec<String>,
   score: usize,
   name: String,

}

impl Player {

   fn new(deck: &mut Deck, name: &str) -> Self {
       // initializes player, draws starting hand
       let mut p = Self {
           hand: vec![],
           score: 0,
           name: String::from(name),
       };
       for _ in 0..STARTING_HAND_SIZE {
           p.add(deck.draw(), deck);
       }
       p
   }
   fn done(&self) -> bool {
       self.hand.len() == 0
   }
   fn draw(&mut self, deck: &mut Deck) {
       self.add(deck.draw(), deck);
   }
   fn has(&self, card: &String) -> bool {
       self.hand.contains(card)
   }
   fn take(&mut self, card: &String) -> Option<String> {
       if self.has(card) {
           let mut i = 0;
           for c in &self.hand {
               if c == card {
                   break;
               }
               i += 1;
           }
           Some(self.hand.remove(i))
       } else {
           None
       }
   }
   fn add(&mut self, card: String, deck: &mut Deck) {
       // adds card to hand. If you have NUM_SUITS, get a book. If you have no cards, draw.
       if self.hand.contains(&card) {
           let mut i = 0;
           for item in &self.hand {
               if item == &card {
                   i += 1;
               }
           }
           if i == NUM_SUITS-1 {
               while self.has(&card) { self.take(&card); }
               self.score += 1;
               if self.done() && !deck.done() {
                   self.draw(deck);
               }
               return;
           }
       }
       self.hand.push(card);
       self.hand.sort();
   }

}

fn input(string: &str) -> String {

   print!("{}", string);
   std::io::stdout().flush().unwrap();
   let mut line = String::new();
   std::io::stdin().read_line(&mut line).unwrap();
   line.pop(); // \n\r
   line.pop();
   line

}

fn main() {

   let mut thread = thread_rng();
   let mut deck = Deck::new();
   deck.shuffle();
   let mut user = Player::new(&mut deck, &input("Enter your name: "));
   let mut npc = Player::new(&mut deck, "NPC");
   let mut has_guessed = vec![];
   let mut player_turn = true; // toggle
   while !deck.done() {
       println!("\n\ndeck size: {}", deck.cards.len());
       if player_turn {
           while !deck.done() {
               print!("\n== {}'s Turn ==\n{}: {}\nNPC: {}\nYOUR HAND: ", user.name, user.name, user.score, npc.score);
               for card in &user.hand {
                   print!("{} ", card);
               }
               let mut choice = input("\nYou fish for a: ");
               while !"2 3 4 5 6 7 8 9 10 J Q K A".split(" ").collect::<Vec<&str>>().contains(&choice.as_str()) || !user.hand.contains(&choice) {
                   println!("invalid response, expecting 2, 3, 4, 5, ..., Q, K, A. The card must be in your hand.");
                   choice = input("You fish for a: ");
               }
               if !has_guessed.contains(&choice) { has_guessed.push(choice.clone()); }
               match npc.take(&choice) {
                   Some(thing) => {
                       user.add(thing, &mut deck);
                       while npc.has(&choice) {
                           user.add(npc.take(&choice).unwrap(), &mut deck);
                       }
                       println!("Yes, go again");
                   }
                   None => {
                       user.draw(&mut deck);
                       println!("Go fish!");
                       break;
                   }
               }
           }
       } else {
           while !deck.done() {
               print!("\n== NPC's Turn ==\n{}: {}\nNPC: {}\nYOUR HAND: ", user.name, user.score, npc.score);
               for card in &user.hand {
                   print!("{} ", card);
               }
               // guess if user has guessed & you have
               let mut choice = String::new();
               for string in &has_guessed {
                   if npc.hand.contains(string) {
                       choice = string.clone();
                   }
               }
               if &choice == "" {
                   choice = npc.hand.choose(&mut thread).unwrap().clone();
               }
               println!("\nDo you have a {}?", choice);
               match user.take(&choice) {
                   Some(thing) => {
                       println!("Yes, I do.");
                       npc.add(thing, &mut deck);
                       while user.has(&choice) {
                           npc.add(user.take(&choice).unwrap(), &mut deck);
                       }
                       input("\n...");
                   }
                   None => {
                       npc.draw(&mut deck);
                       println!("Go fish!");
                       input("\n...");
                       break;
                   }
               }
           }
       }
       player_turn = !player_turn;
   }
   if deck.done() {
       println!("Deck Empty, Game Over");
   }
   if user.score > npc.score {
       println!("{} has won with a score of {}", user.name, user.score);
   } else if user.score == npc.score {
       println!("{} and {} have tied with a score of {}", user.name, npc.name, user.score);
   } else {
       println!("{} has won with a score of {}", npc.name, npc.score);
   }

} </lang>