// import libraries, namespaces use std::io; use std::io::Write; use std::fmt; use rand::Rng; use rand::thread_rng; use rand::seq::SliceRandom; // enum for Rank // TWO = 2, ... ACE // implement fmt::Display #[derive(PartialEq, Eq, Clone)] enum Rank { None, TWO = 2, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE } impl fmt::Display for Rank { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Rank::None => write!(f, "{}", 'X'), Rank::TWO => write!(f, "{}", 2), Rank::THREE => write!(f, "{}", 3), Rank::FOUR => write!(f, "{}", 4), Rank::FIVE => write!(f, "{}", 5), Rank::SIX => write!(f, "{}", 6), Rank::SEVEN => write!(f, "{}", 7), Rank::EIGHT => write!(f, "{}", 8), Rank::NINE => write!(f, "{}", 9), Rank::TEN => write!(f, "{}", 10), Rank::JACK => write!(f, "{}", 'J'), Rank::QUEEN => write!(f, "{}", 'Q'), Rank::KING => write!(f, "{}", 'K'), Rank::ACE => write!(f, "{}", 'A') } } } fn number_to_rank(num_rank: i32) -> Rank { match num_rank { 1 => Rank::ACE, 2 => Rank::TWO, 3 => Rank::THREE, 4 => Rank::FOUR, 5 => Rank::FIVE, 6 => Rank::SIX, 7 => Rank::SEVEN, 8 => Rank::EIGHT, 9 => Rank::NINE, 10 => Rank::TEN, 11 => Rank::JACK, 12 => Rank::QUEEN, 13 => Rank::KING, _ => Rank::None } } fn rank_to_number(in_rank: Rank) -> i32 { match in_rank { Rank::ACE => 1, Rank::TWO => 2, Rank::THREE => 3, Rank::FOUR => 4, Rank::FIVE => 5, Rank::SIX => 6, Rank::SEVEN => 7, Rank::EIGHT => 8, Rank::NINE => 9, Rank::TEN => 10, Rank::JACK => 11, Rank::QUEEN => 12, Rank::KING => 13, Rank::None => -1 } } // enum for Suit // HEARTS, DIAMONDS, SPADES, CLUBS // implement fmt::Display #[derive(PartialEq, Eq, Clone)] enum Suit { None, HEARTS, DIAMONDS, SPADES, CLUBS } impl fmt::Display for Suit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Suit::None => write!(f, "{}", 'X'), Suit::HEARTS => write!(f, "{}", 'H'), Suit::DIAMONDS => write!(f, "{}", 'D'), Suit::SPADES => write!(f, "{}", 'S'), Suit::CLUBS => write!(f, "{}", 'C') } } } fn number_to_suit(num_suit: i32) -> Suit { match num_suit { 1 => Suit::HEARTS, 2 => Suit::DIAMONDS, 3 => Suit::SPADES, 4 => Suit::CLUBS, _ => Suit::None } } // Card struct // rank and suit variable // implement fmt::Display #[derive(Clone)] struct Card { card_rank: Rank, card_suit: Suit } impl fmt::Display for Card { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}{}", self.card_rank, self.card_suit) } } // Deck struct // vector of Cards // new() method, [creates deck of cards, shuffles, return a deck object] // shuffle() method [shuffles a deck object] // draw() method ['draws' an card from the top (last) of the deck, return card] // is_empty() method [returns t/f if the deck (reference) is empty] struct Deck { card_deck: Vec } impl Deck { fn new() -> Deck { // create deck of cards let mut full_deck = Deck { card_deck: vec![] }; // to create deck, // need a double for loop (or just loop with counter) to // iterate through 2-A (or 0 to 12 / 1-13) for each suit (diamonds, etc.) // add the card via index. let mut suit_counter = 0; let mut card_counter = 0; loop { if suit_counter == 4 { break; } else { loop { if card_counter == 13 { break; } else { // create card here. let temp_card = Card { card_rank: number_to_rank(card_counter + 1), card_suit: number_to_suit(suit_counter + 1) }; full_deck.card_deck.push(temp_card); card_counter = card_counter + 1; } } card_counter = 0; suit_counter = suit_counter + 1; } } // shuffle deck of cards full_deck.card_deck.shuffle(&mut thread_rng()); // return deck struct return full_deck; } fn shuffle(mut self) -> Deck { self.card_deck.shuffle(&mut thread_rng()); return self; } fn draw(&mut self) -> Card { if !self.card_deck.is_empty() { return self.card_deck.pop().unwrap(); } else { panic!("Card ran out somehow"); } } fn is_empty(&self) -> bool { return self.card_deck.is_empty(); } } // Player struct // vector of cards [referred to as hand] // new() method, [creates a new player object] // add_cards() method [takes vector of cards, adds to player hand.] // has_rank() method [accepts a Rank, returns vector of cards belonging to that // rank, removes the cards from player hand] // check_set() method [returns true if player has a set and removes the cards // belonging to that set] #[derive(Clone)] struct Player { player_hand: Vec } impl Player { fn new() -> Player { let mut hand = Player { player_hand: vec![] }; return hand; } fn add_cards(&mut self, mut card_vec: Vec) { // append the card vector to the player's hand. self.player_hand.append(&mut card_vec); } fn has_rank(&mut self, in_card_rank: &Rank) -> Vec { // check to see if the rank matches any of the items in vector // if they do match, remove from hand, place into temp vector, // return temp vector. let mut card_counter = 0; let mut card_out = vec![]; loop { if self.player_hand.is_empty() || self.player_hand.len() - 1 < card_counter { break; } if self.player_hand.get(card_counter).unwrap().card_rank == *in_card_rank { let current_card = Card { card_rank: self.player_hand.get(card_counter).unwrap().card_rank.clone(), card_suit: self.player_hand.get(card_counter).unwrap().card_suit.clone(), }; card_out.push(current_card); self.player_hand.remove(card_counter); } card_counter = card_counter + 1; } return card_out; } fn check_set(&mut self) -> bool { // check to see if the vector (self.player_hand) has four of the same rank. // if the player does, remove the cards, and return true, // otherwise, return false. let mut count = 0; let mut rank_check = 0; loop { if rank_check > 13 { break; } for card in &self.player_hand { if card.card_rank == number_to_rank(rank_check) { count += 1; } } if count >= 4 { self.player_hand.retain(|card| card.card_rank != number_to_rank(rank_check)); return true; } rank_check = rank_check + 1; count = 0; } return false; } } // Game struct // deck [main instance of deck] // human player [instance of Player] // computer player [instance of Player] // new() method [returns new Game object] // human_turn() [prompts the user to ask for a rank and check if the computer // has the requested rank. If the card is available, it will transfer the cards // to the human’s hand, otherwise, it will draw a card] // computer_turn() [that generates a random rank and checks if the human has the // requested rank. If the card is available, it will transfer the cards to the // computer’s hand, otherwise, it will draw a card] // play() [handles the gameplay by switching between the player’s turn and the // computer’s turn and checks for the game to be completed] // print_scores() [prints the final score of the players] // winner() [returns name of the winner (player or computer)] struct Game { // data full_card_deck: Deck, human_player: Player, computer_player: Player, human_score: u32, computer_score: u32 } impl Game { // methods fn new() -> Game { let mut full_game = Game { full_card_deck: Deck::new(), human_player: Player::new(), computer_player: Player::new(), human_score: 0, computer_score: 0 }; // deal seven cards to each player. let mut card_count = 0; let mut human_cards_vec = vec![]; let mut computer_cards_vec = vec![]; loop { if card_count > 6 { break; } human_cards_vec.push(full_game.full_card_deck.draw()); computer_cards_vec.push(full_game.full_card_deck.draw()); card_count = card_count + 1; } full_game.human_player.add_cards(human_cards_vec); full_game.computer_player.add_cards(computer_cards_vec); return full_game; } fn human_turn(&mut self) { print!("Human's Turn: "); for card in &*self.human_player.player_hand { print!("{} ", card); } println!(""); print!("Your turn. Enter a rank (2-10, A/1, J/11, Q/12, K/13): "); let _=io::stdout().flush(); let mut rank_enter = String::new(); let mut rank_num: i32 = 0; let mut rank_exit: Rank; io::stdin().read_line(&mut rank_enter).expect("String wrong"); rank_num = rank_enter.trim().parse().unwrap(); rank_exit = number_to_rank(rank_num); // check if the computer has the rank requested. let mut temp_vec = self.computer_player.has_rank(&rank_exit); if !temp_vec.is_empty() { println!("Computer has {}s.", rank_exit); // add the cards from the temp_vec. self.human_player.add_cards(temp_vec); } else { println!("Computer does not have {}s. Go fish.", rank_exit); // draw a card. let mut new_card_vec = vec![]; new_card_vec.push(self.full_card_deck.draw()); self.human_player.add_cards(new_card_vec) } if self.human_player.check_set() { self.human_score = self.human_score + 1; } } fn computer_turn(&mut self) { print!("Computer's Turn... "); println!(""); let rank_pick = rand::thread_rng().gen_range(1..=13); // check if the computer has the rank requested. let mut temp_vec = self.human_player.has_rank(&number_to_rank(rank_pick)); if !temp_vec.is_empty() { println!("Human has {}s.", number_to_rank(rank_pick)); // add the cards from the temp_vec. self.computer_player.add_cards(temp_vec); } else { println!("Human does not have {}s. Computer goes fish.", number_to_rank(rank_pick)); // draw a card. let mut new_card_vec = vec![]; new_card_vec.push(self.full_card_deck.draw()); self.computer_player.add_cards(new_card_vec) } if self.computer_player.check_set() { self.computer_score = self.computer_score + 1; } } fn play(&mut self) { loop { if self.full_card_deck.card_deck.len() == 0 { println!("Game Over."); self.print_scores(); self.winner(); break; } self.human_turn(); self.computer_turn(); } } fn print_scores(&mut self) { println!("Human Score: {}", self.human_score); println!("Computer Score: {}", self.computer_score); } fn winner(&mut self) { if self.human_score > self.computer_score { println!("Human Wins with a score of: {}", self.human_score); } else if self.human_score < self.computer_score { println!("Computer Wins with a score of: {}", self.computer_score); } else { println!("It's a tie!"); } } } fn main() { println!("Welcome to the Go Fish Game!"); println!("----------------------------"); let mut game = Game::new(); game.play(); }