254 lines
5.5 KiB
C++
254 lines
5.5 KiB
C++
#include <algorithm>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <random>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace std;
|
|
|
|
enum Rank {
|
|
TWO = 2,
|
|
THREE,
|
|
FOUR,
|
|
FIVE,
|
|
SIX,
|
|
SEVEN,
|
|
EIGHT,
|
|
NINE,
|
|
TEN,
|
|
JACK,
|
|
QUEEN,
|
|
KING,
|
|
ACE
|
|
};
|
|
|
|
enum Suit { HEARTS, DIAMONDS, CLUBS, SPADES };
|
|
|
|
struct Card {
|
|
Rank rank;
|
|
Suit suit;
|
|
|
|
friend ostream &operator<<(ostream &os, const Card &card) {
|
|
const string ranks[] = {"2", "3", "4", "5", "6", "7", "8",
|
|
"9", "10", "J", "Q", "K", "A"};
|
|
const string suits[] = {"H", "D", "C", "S"};
|
|
|
|
os << ranks[static_cast<int>(card.rank) - 2]
|
|
<< suits[static_cast<int>(card.suit)];
|
|
return os;
|
|
}
|
|
};
|
|
|
|
class Deck {
|
|
private:
|
|
vector<Card> cards;
|
|
|
|
void shuffle() {
|
|
random_device rd;
|
|
mt19937 g(rd());
|
|
std::shuffle(cards.begin(), cards.end(), g);
|
|
}
|
|
|
|
public:
|
|
Deck() {
|
|
for (int i = static_cast<int>(Rank::TWO); i <= static_cast<int>(Rank::ACE);
|
|
i++) {
|
|
for (int j = static_cast<int>(Suit::HEARTS);
|
|
j <= static_cast<int>(Suit::SPADES); j++) {
|
|
cards.push_back(Card{static_cast<Rank>(i), static_cast<Suit>(j)});
|
|
}
|
|
}
|
|
|
|
shuffle();
|
|
}
|
|
|
|
Card draw() {
|
|
if (cards.empty()) {
|
|
throw runtime_error("No more cards in the deck!");
|
|
}
|
|
|
|
Card card = cards.back();
|
|
cards.pop_back();
|
|
return card;
|
|
}
|
|
|
|
bool empty() const { return cards.empty(); }
|
|
};
|
|
|
|
class Player {
|
|
public:
|
|
vector<Card> hand;
|
|
map<Rank, int> rank_count;
|
|
|
|
void draw_card(Deck &deck) {
|
|
try {
|
|
Card card = deck.draw();
|
|
hand.push_back(card);
|
|
rank_count[card.rank]++;
|
|
} catch (const runtime_error &e) {
|
|
cout << e.what() << endl;
|
|
}
|
|
}
|
|
|
|
bool has_rank(Rank rank) const {
|
|
return rank_count.count(rank) > 0 && rank_count.at(rank) > 0;
|
|
}
|
|
|
|
vector<Card> remove_rank(Rank rank) {
|
|
vector<Card> removed_cards;
|
|
|
|
for (auto it = hand.begin(); it != hand.end();) {
|
|
if (it->rank == rank) {
|
|
removed_cards.push_back(*it);
|
|
rank_count[it->rank]--;
|
|
it = hand.erase(it);
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
|
|
return removed_cards;
|
|
}
|
|
|
|
bool check_for_set() {
|
|
for (const auto &pair : rank_count) {
|
|
if (pair.second == 4) {
|
|
cout << "Player has a set of " << static_cast<int>(pair.first) << "s"
|
|
<< endl;
|
|
rank_count[pair.first] = 0;
|
|
|
|
hand.erase(remove_if(hand.begin(), hand.end(),
|
|
[pair](const Card &card) {
|
|
return card.rank == pair.first;
|
|
}),
|
|
hand.end());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void add_cards(const vector<Card> &cards) {
|
|
for (const Card &card : cards) {
|
|
hand.push_back(card);
|
|
rank_count[card.rank]++;
|
|
}
|
|
}
|
|
};
|
|
|
|
class Game {
|
|
private:
|
|
Deck deck;
|
|
Player human;
|
|
Player computer;
|
|
int human_score;
|
|
int computer_score;
|
|
|
|
void deal_initial_cards() {
|
|
for (int i = 0; i < 7; i++) {
|
|
human.draw_card(deck);
|
|
computer.draw_card(deck);
|
|
}
|
|
}
|
|
|
|
void human_turn() {
|
|
Rank requested_rank = get_human_request();
|
|
if (computer.has_rank(requested_rank)) {
|
|
cout << "Computer has " << static_cast<int>(requested_rank) << "s"
|
|
<< endl;
|
|
vector<Card> cards = computer.remove_rank(requested_rank);
|
|
human.add_cards(cards);
|
|
} else {
|
|
cout << "Computer does not have the rank. Go fish!" << endl;
|
|
human.draw_card(deck);
|
|
}
|
|
|
|
if (human.check_for_set()) {
|
|
human_score++;
|
|
}
|
|
}
|
|
|
|
void computer_turn() {
|
|
cout << "Computer's turn..." << endl;
|
|
Rank requested_rank = get_computer_request();
|
|
if (human.has_rank(requested_rank)) {
|
|
cout << "Player has " << static_cast<int>(requested_rank) << "s" << endl;
|
|
vector<Card> cards = human.remove_rank(requested_rank);
|
|
computer.add_cards(cards);
|
|
} else {
|
|
cout << "Player does not have the rank. Computer goes fishing!" << endl;
|
|
computer.draw_card(deck);
|
|
}
|
|
|
|
if (computer.check_for_set()) {
|
|
computer_score++;
|
|
}
|
|
}
|
|
|
|
Rank get_human_request() {
|
|
cout << "Your turn. Enter the rank (2-14 where 11=J, 12=Q, 13=K, 14=A): ";
|
|
int rank;
|
|
cin >> rank;
|
|
return static_cast<Rank>(rank);
|
|
}
|
|
|
|
Rank get_computer_request() {
|
|
vector<Rank> available_ranks;
|
|
for (const auto &pair : computer.rank_count) {
|
|
if (pair.second > 0) {
|
|
available_ranks.push_back(pair.first);
|
|
}
|
|
}
|
|
|
|
return available_ranks[rand() % available_ranks.size()];
|
|
}
|
|
|
|
void show_hand(const vector<Card> &hand) const {
|
|
for (const Card &card : hand) {
|
|
cout << card << " ";
|
|
}
|
|
cout << endl;
|
|
}
|
|
|
|
public:
|
|
Game() : human_score(0), computer_score(0) { deal_initial_cards(); }
|
|
|
|
void play() {
|
|
while (true) {
|
|
cout << endl << "Your hand: ";
|
|
show_hand(human.hand);
|
|
|
|
human_turn();
|
|
computer_turn();
|
|
|
|
if (deck.empty() && human.hand.empty() && computer.hand.empty()) {
|
|
cout << "Game over!" << endl;
|
|
cout << "Your score: " << human_score << endl;
|
|
cout << "Computer score: " << computer_score << endl;
|
|
|
|
if (human_score > computer_score) {
|
|
cout << "You win!" << endl;
|
|
} else if (human_score < computer_score) {
|
|
cout << "Computer wins!" << endl;
|
|
} else {
|
|
cout << "It's a tie!" << endl;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
int main(void) {
|
|
srand(static_cast<unsigned>(time(nullptr)));
|
|
|
|
Game game;
|
|
game.play();
|
|
|
|
return 0;
|
|
}
|