480 lines
13 KiB
Rust
480 lines
13 KiB
Rust
// 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<Card>
|
||
}
|
||
|
||
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<Card>
|
||
}
|
||
|
||
impl Player
|
||
{
|
||
fn new() -> Player
|
||
{
|
||
let mut hand = Player
|
||
{
|
||
player_hand: vec![]
|
||
};
|
||
return hand;
|
||
}
|
||
fn add_cards(&mut self, mut card_vec: Vec<Card>)
|
||
{
|
||
// 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<Card>
|
||
{
|
||
// 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();
|
||
}
|