Bist-o-yek: a card game similar to Blackjack
up vote
3
down vote
favorite
Bist-o-yek (21) is a Persian card game very similar to blackjack, except it doesn't have things like double down and split. I did, though, change it a little. For example, added dealer dealing to 17.
First, there's a class called Cards that carries each card's name and score. Then, some functions for drawing, shuffling and dealing. At the end, a function called blackjack() bringing all together.
This code is a little clumsy and doesn't have input validation so be careful!
// BlackJack.cpp : Created by Chubak Bidpaa at 11/18/2018
//
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <algorithm>
#include <random>
#include <array>
#include <numeric>
struct Card
{
std::string name;
int score;
Card(std::string card_name, int card_score) : name(card_name), score(card_score) {}
};
typedef std::vector<Card> card_vec;
card_vec deck()
{
card_vec return_deck({ Card("Ace of Clubs", 11), Card("Ace of Diamods", 11),
Card("Ace of Hearts", 11), Card("Ace of Spades", 11),
Card("Two of Clubs", 2), Card("Two of Diamonds", 2),
Card("Two of Hearts", 2), Card("Two of Spades", 2),
Card("Three of Clubs", 3), Card("Three of Diamonds", 3),
Card("Three of Hearts", 3), Card("Three of Spades", 3),
Card("Four of Clubs", 4), Card("Four of Diamonds", 4),
Card("Four of Hearts", 4), Card("Four of Spades", 4),
Card("Five of Clubs", 5), Card("Five of Diamonds", 5),
Card("Five of Hearts", 5), Card("Five of Spades", 5),
Card("Six of Clubs", 6), Card("Six of Diamonds", 6),
Card("Six of Hearts", 6), Card("Six of Spades", 6),
Card("Seven of Clubs", 7), Card("Seven of Diamonds", 7),
Card("Seven of Hearts", 7), Card("Seven of Spades", 7),
Card("Eight of Clubs", 8), Card("Eight of Diamonds", 8),
Card("Eight of Hearts", 8), Card("Eight of Spades", 8),
Card("Nine of Clubs", 9), Card("Nine of Diamonds", 9),
Card("Nine of Hearts", 9), Card("Nine of Spades", 9),
Card("Ten of Clubs", 10), Card("Ten of Diamonds", 10),
Card("Ten of Hearts", 10), Card("Ten of Spades", 10),
Card("Jack of Clubs", 10), Card("Jack of Diamonds", 10),
Card("Jack of Hearts", 10), Card("Jack of Spades", 10),
Card("Queen of Clubs", 10), Card("Queen of Diamonds", 10),
Card("Queen of Hearts", 10), Card("Queen of Spades", 10),
Card("King of Clubs", 10), Card("King of Diamonds", 10),
Card("King of Hearts", 10), Card("King of Spades", 10) });
return return_deck;
}
int random(int min, int max)
{
auto seed = std::time(NULL);
std::mt19937 engine(seed);
std::uniform_int_distribution<int> dist(min, max);
return dist(engine);
}
void shuffle(card_vec &adeck)
{
std::random_shuffle(adeck.begin(), adeck.end());
}
Card draw(card_vec &adeck)
{
if (adeck.size() > 1)
{
shuffle(adeck);
}
int index = random(0, adeck.size() - 1);
Card return_card = adeck[index];
adeck.erase(adeck.begin() + index);
return return_card;
}
void deal(card_vec &adeck, card_vec &dealers_cards, card_vec &player_cards)
{
if (dealers_cards.size() == 0 && player_cards.size() == 0)
{
Card dealer_1 = draw(adeck);
dealers_cards.push_back(dealer_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card dealer_2 = draw(adeck);
dealers_cards.push_back(dealer_2);
Card player_1 = draw(adeck);
player_cards.push_back(player_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card player_2 = draw(adeck);
player_cards.push_back(player_2);
}
else
{
Card dealer_3 = draw(adeck);
dealers_cards.push_back(dealer_3);
}
}
std::string blackjack()
{
card_vec player_cards;
card_vec dealer_cards;
card_vec adeck = deck();
std::vector<int> player_scores;
std::vector<int> dealer_scores;
int input;
deal(adeck, dealer_cards, player_cards);
for (int i = 0; i < 2; ++i)
{
player_scores.push_back(player_cards[i].score);
dealer_scores.push_back(dealer_cards[i].score);
}
auto player_card_1 = player_cards[0].name;
auto player_card_2 = player_cards[1].name;
auto dealer_card_1 = dealer_cards[0].name;
auto dealer_card_2 = dealer_cards[1].name;
std::cout << "Your cards are: " << player_card_1 << " and " << player_card_2 << std::endl;
std::cout << "The dealer reveals: " << dealer_card_1 << std::endl;
std::cout << "Press 1 to Hit or Press 2 to Stay" << std::endl;
std::cin >> input;
while (std::accumulate(player_scores.begin(), player_scores.end(), 0) <= 21)
{
if (input == 1)
{
Card new_card = draw(adeck);
std::cout << "You were dealt a " << new_card.name << std::endl;
player_scores.push_back(new_card.score);
std::cin >> input;
}
else if (input == 2)
{
break;
}
}
if (std::accumulate(player_scores.begin(), player_scores.end(), 0) > 21)
return "You're busted!";
else if (std::accumulate(player_scores.begin(), player_scores.end(), 0) == 21)
return "Perfect win!";
std::cout << "The dealer reveals: " << dealer_card_2 << std::endl;
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) > 17)
{
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
else
{
while (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) <= 17)
{
Card new_card = draw(adeck);
std::cout << "Dealer reveals: " << new_card.name << std::endl;
dealer_scores.push_back(new_card.score);
}
}
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
int main()
{
std::cout << blackjack() << std::endl;
return 0;
}
c++ c++14 playing-cards
New contributor
add a comment |
up vote
3
down vote
favorite
Bist-o-yek (21) is a Persian card game very similar to blackjack, except it doesn't have things like double down and split. I did, though, change it a little. For example, added dealer dealing to 17.
First, there's a class called Cards that carries each card's name and score. Then, some functions for drawing, shuffling and dealing. At the end, a function called blackjack() bringing all together.
This code is a little clumsy and doesn't have input validation so be careful!
// BlackJack.cpp : Created by Chubak Bidpaa at 11/18/2018
//
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <algorithm>
#include <random>
#include <array>
#include <numeric>
struct Card
{
std::string name;
int score;
Card(std::string card_name, int card_score) : name(card_name), score(card_score) {}
};
typedef std::vector<Card> card_vec;
card_vec deck()
{
card_vec return_deck({ Card("Ace of Clubs", 11), Card("Ace of Diamods", 11),
Card("Ace of Hearts", 11), Card("Ace of Spades", 11),
Card("Two of Clubs", 2), Card("Two of Diamonds", 2),
Card("Two of Hearts", 2), Card("Two of Spades", 2),
Card("Three of Clubs", 3), Card("Three of Diamonds", 3),
Card("Three of Hearts", 3), Card("Three of Spades", 3),
Card("Four of Clubs", 4), Card("Four of Diamonds", 4),
Card("Four of Hearts", 4), Card("Four of Spades", 4),
Card("Five of Clubs", 5), Card("Five of Diamonds", 5),
Card("Five of Hearts", 5), Card("Five of Spades", 5),
Card("Six of Clubs", 6), Card("Six of Diamonds", 6),
Card("Six of Hearts", 6), Card("Six of Spades", 6),
Card("Seven of Clubs", 7), Card("Seven of Diamonds", 7),
Card("Seven of Hearts", 7), Card("Seven of Spades", 7),
Card("Eight of Clubs", 8), Card("Eight of Diamonds", 8),
Card("Eight of Hearts", 8), Card("Eight of Spades", 8),
Card("Nine of Clubs", 9), Card("Nine of Diamonds", 9),
Card("Nine of Hearts", 9), Card("Nine of Spades", 9),
Card("Ten of Clubs", 10), Card("Ten of Diamonds", 10),
Card("Ten of Hearts", 10), Card("Ten of Spades", 10),
Card("Jack of Clubs", 10), Card("Jack of Diamonds", 10),
Card("Jack of Hearts", 10), Card("Jack of Spades", 10),
Card("Queen of Clubs", 10), Card("Queen of Diamonds", 10),
Card("Queen of Hearts", 10), Card("Queen of Spades", 10),
Card("King of Clubs", 10), Card("King of Diamonds", 10),
Card("King of Hearts", 10), Card("King of Spades", 10) });
return return_deck;
}
int random(int min, int max)
{
auto seed = std::time(NULL);
std::mt19937 engine(seed);
std::uniform_int_distribution<int> dist(min, max);
return dist(engine);
}
void shuffle(card_vec &adeck)
{
std::random_shuffle(adeck.begin(), adeck.end());
}
Card draw(card_vec &adeck)
{
if (adeck.size() > 1)
{
shuffle(adeck);
}
int index = random(0, adeck.size() - 1);
Card return_card = adeck[index];
adeck.erase(adeck.begin() + index);
return return_card;
}
void deal(card_vec &adeck, card_vec &dealers_cards, card_vec &player_cards)
{
if (dealers_cards.size() == 0 && player_cards.size() == 0)
{
Card dealer_1 = draw(adeck);
dealers_cards.push_back(dealer_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card dealer_2 = draw(adeck);
dealers_cards.push_back(dealer_2);
Card player_1 = draw(adeck);
player_cards.push_back(player_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card player_2 = draw(adeck);
player_cards.push_back(player_2);
}
else
{
Card dealer_3 = draw(adeck);
dealers_cards.push_back(dealer_3);
}
}
std::string blackjack()
{
card_vec player_cards;
card_vec dealer_cards;
card_vec adeck = deck();
std::vector<int> player_scores;
std::vector<int> dealer_scores;
int input;
deal(adeck, dealer_cards, player_cards);
for (int i = 0; i < 2; ++i)
{
player_scores.push_back(player_cards[i].score);
dealer_scores.push_back(dealer_cards[i].score);
}
auto player_card_1 = player_cards[0].name;
auto player_card_2 = player_cards[1].name;
auto dealer_card_1 = dealer_cards[0].name;
auto dealer_card_2 = dealer_cards[1].name;
std::cout << "Your cards are: " << player_card_1 << " and " << player_card_2 << std::endl;
std::cout << "The dealer reveals: " << dealer_card_1 << std::endl;
std::cout << "Press 1 to Hit or Press 2 to Stay" << std::endl;
std::cin >> input;
while (std::accumulate(player_scores.begin(), player_scores.end(), 0) <= 21)
{
if (input == 1)
{
Card new_card = draw(adeck);
std::cout << "You were dealt a " << new_card.name << std::endl;
player_scores.push_back(new_card.score);
std::cin >> input;
}
else if (input == 2)
{
break;
}
}
if (std::accumulate(player_scores.begin(), player_scores.end(), 0) > 21)
return "You're busted!";
else if (std::accumulate(player_scores.begin(), player_scores.end(), 0) == 21)
return "Perfect win!";
std::cout << "The dealer reveals: " << dealer_card_2 << std::endl;
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) > 17)
{
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
else
{
while (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) <= 17)
{
Card new_card = draw(adeck);
std::cout << "Dealer reveals: " << new_card.name << std::endl;
dealer_scores.push_back(new_card.score);
}
}
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
int main()
{
std::cout << blackjack() << std::endl;
return 0;
}
c++ c++14 playing-cards
New contributor
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
Bist-o-yek (21) is a Persian card game very similar to blackjack, except it doesn't have things like double down and split. I did, though, change it a little. For example, added dealer dealing to 17.
First, there's a class called Cards that carries each card's name and score. Then, some functions for drawing, shuffling and dealing. At the end, a function called blackjack() bringing all together.
This code is a little clumsy and doesn't have input validation so be careful!
// BlackJack.cpp : Created by Chubak Bidpaa at 11/18/2018
//
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <algorithm>
#include <random>
#include <array>
#include <numeric>
struct Card
{
std::string name;
int score;
Card(std::string card_name, int card_score) : name(card_name), score(card_score) {}
};
typedef std::vector<Card> card_vec;
card_vec deck()
{
card_vec return_deck({ Card("Ace of Clubs", 11), Card("Ace of Diamods", 11),
Card("Ace of Hearts", 11), Card("Ace of Spades", 11),
Card("Two of Clubs", 2), Card("Two of Diamonds", 2),
Card("Two of Hearts", 2), Card("Two of Spades", 2),
Card("Three of Clubs", 3), Card("Three of Diamonds", 3),
Card("Three of Hearts", 3), Card("Three of Spades", 3),
Card("Four of Clubs", 4), Card("Four of Diamonds", 4),
Card("Four of Hearts", 4), Card("Four of Spades", 4),
Card("Five of Clubs", 5), Card("Five of Diamonds", 5),
Card("Five of Hearts", 5), Card("Five of Spades", 5),
Card("Six of Clubs", 6), Card("Six of Diamonds", 6),
Card("Six of Hearts", 6), Card("Six of Spades", 6),
Card("Seven of Clubs", 7), Card("Seven of Diamonds", 7),
Card("Seven of Hearts", 7), Card("Seven of Spades", 7),
Card("Eight of Clubs", 8), Card("Eight of Diamonds", 8),
Card("Eight of Hearts", 8), Card("Eight of Spades", 8),
Card("Nine of Clubs", 9), Card("Nine of Diamonds", 9),
Card("Nine of Hearts", 9), Card("Nine of Spades", 9),
Card("Ten of Clubs", 10), Card("Ten of Diamonds", 10),
Card("Ten of Hearts", 10), Card("Ten of Spades", 10),
Card("Jack of Clubs", 10), Card("Jack of Diamonds", 10),
Card("Jack of Hearts", 10), Card("Jack of Spades", 10),
Card("Queen of Clubs", 10), Card("Queen of Diamonds", 10),
Card("Queen of Hearts", 10), Card("Queen of Spades", 10),
Card("King of Clubs", 10), Card("King of Diamonds", 10),
Card("King of Hearts", 10), Card("King of Spades", 10) });
return return_deck;
}
int random(int min, int max)
{
auto seed = std::time(NULL);
std::mt19937 engine(seed);
std::uniform_int_distribution<int> dist(min, max);
return dist(engine);
}
void shuffle(card_vec &adeck)
{
std::random_shuffle(adeck.begin(), adeck.end());
}
Card draw(card_vec &adeck)
{
if (adeck.size() > 1)
{
shuffle(adeck);
}
int index = random(0, adeck.size() - 1);
Card return_card = adeck[index];
adeck.erase(adeck.begin() + index);
return return_card;
}
void deal(card_vec &adeck, card_vec &dealers_cards, card_vec &player_cards)
{
if (dealers_cards.size() == 0 && player_cards.size() == 0)
{
Card dealer_1 = draw(adeck);
dealers_cards.push_back(dealer_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card dealer_2 = draw(adeck);
dealers_cards.push_back(dealer_2);
Card player_1 = draw(adeck);
player_cards.push_back(player_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card player_2 = draw(adeck);
player_cards.push_back(player_2);
}
else
{
Card dealer_3 = draw(adeck);
dealers_cards.push_back(dealer_3);
}
}
std::string blackjack()
{
card_vec player_cards;
card_vec dealer_cards;
card_vec adeck = deck();
std::vector<int> player_scores;
std::vector<int> dealer_scores;
int input;
deal(adeck, dealer_cards, player_cards);
for (int i = 0; i < 2; ++i)
{
player_scores.push_back(player_cards[i].score);
dealer_scores.push_back(dealer_cards[i].score);
}
auto player_card_1 = player_cards[0].name;
auto player_card_2 = player_cards[1].name;
auto dealer_card_1 = dealer_cards[0].name;
auto dealer_card_2 = dealer_cards[1].name;
std::cout << "Your cards are: " << player_card_1 << " and " << player_card_2 << std::endl;
std::cout << "The dealer reveals: " << dealer_card_1 << std::endl;
std::cout << "Press 1 to Hit or Press 2 to Stay" << std::endl;
std::cin >> input;
while (std::accumulate(player_scores.begin(), player_scores.end(), 0) <= 21)
{
if (input == 1)
{
Card new_card = draw(adeck);
std::cout << "You were dealt a " << new_card.name << std::endl;
player_scores.push_back(new_card.score);
std::cin >> input;
}
else if (input == 2)
{
break;
}
}
if (std::accumulate(player_scores.begin(), player_scores.end(), 0) > 21)
return "You're busted!";
else if (std::accumulate(player_scores.begin(), player_scores.end(), 0) == 21)
return "Perfect win!";
std::cout << "The dealer reveals: " << dealer_card_2 << std::endl;
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) > 17)
{
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
else
{
while (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) <= 17)
{
Card new_card = draw(adeck);
std::cout << "Dealer reveals: " << new_card.name << std::endl;
dealer_scores.push_back(new_card.score);
}
}
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
int main()
{
std::cout << blackjack() << std::endl;
return 0;
}
c++ c++14 playing-cards
New contributor
Bist-o-yek (21) is a Persian card game very similar to blackjack, except it doesn't have things like double down and split. I did, though, change it a little. For example, added dealer dealing to 17.
First, there's a class called Cards that carries each card's name and score. Then, some functions for drawing, shuffling and dealing. At the end, a function called blackjack() bringing all together.
This code is a little clumsy and doesn't have input validation so be careful!
// BlackJack.cpp : Created by Chubak Bidpaa at 11/18/2018
//
#include <iostream>
#include <vector>
#include <string>
#include <ctime>
#include <algorithm>
#include <random>
#include <array>
#include <numeric>
struct Card
{
std::string name;
int score;
Card(std::string card_name, int card_score) : name(card_name), score(card_score) {}
};
typedef std::vector<Card> card_vec;
card_vec deck()
{
card_vec return_deck({ Card("Ace of Clubs", 11), Card("Ace of Diamods", 11),
Card("Ace of Hearts", 11), Card("Ace of Spades", 11),
Card("Two of Clubs", 2), Card("Two of Diamonds", 2),
Card("Two of Hearts", 2), Card("Two of Spades", 2),
Card("Three of Clubs", 3), Card("Three of Diamonds", 3),
Card("Three of Hearts", 3), Card("Three of Spades", 3),
Card("Four of Clubs", 4), Card("Four of Diamonds", 4),
Card("Four of Hearts", 4), Card("Four of Spades", 4),
Card("Five of Clubs", 5), Card("Five of Diamonds", 5),
Card("Five of Hearts", 5), Card("Five of Spades", 5),
Card("Six of Clubs", 6), Card("Six of Diamonds", 6),
Card("Six of Hearts", 6), Card("Six of Spades", 6),
Card("Seven of Clubs", 7), Card("Seven of Diamonds", 7),
Card("Seven of Hearts", 7), Card("Seven of Spades", 7),
Card("Eight of Clubs", 8), Card("Eight of Diamonds", 8),
Card("Eight of Hearts", 8), Card("Eight of Spades", 8),
Card("Nine of Clubs", 9), Card("Nine of Diamonds", 9),
Card("Nine of Hearts", 9), Card("Nine of Spades", 9),
Card("Ten of Clubs", 10), Card("Ten of Diamonds", 10),
Card("Ten of Hearts", 10), Card("Ten of Spades", 10),
Card("Jack of Clubs", 10), Card("Jack of Diamonds", 10),
Card("Jack of Hearts", 10), Card("Jack of Spades", 10),
Card("Queen of Clubs", 10), Card("Queen of Diamonds", 10),
Card("Queen of Hearts", 10), Card("Queen of Spades", 10),
Card("King of Clubs", 10), Card("King of Diamonds", 10),
Card("King of Hearts", 10), Card("King of Spades", 10) });
return return_deck;
}
int random(int min, int max)
{
auto seed = std::time(NULL);
std::mt19937 engine(seed);
std::uniform_int_distribution<int> dist(min, max);
return dist(engine);
}
void shuffle(card_vec &adeck)
{
std::random_shuffle(adeck.begin(), adeck.end());
}
Card draw(card_vec &adeck)
{
if (adeck.size() > 1)
{
shuffle(adeck);
}
int index = random(0, adeck.size() - 1);
Card return_card = adeck[index];
adeck.erase(adeck.begin() + index);
return return_card;
}
void deal(card_vec &adeck, card_vec &dealers_cards, card_vec &player_cards)
{
if (dealers_cards.size() == 0 && player_cards.size() == 0)
{
Card dealer_1 = draw(adeck);
dealers_cards.push_back(dealer_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card dealer_2 = draw(adeck);
dealers_cards.push_back(dealer_2);
Card player_1 = draw(adeck);
player_cards.push_back(player_1);
std::random_shuffle(adeck.begin(), adeck.end());
Card player_2 = draw(adeck);
player_cards.push_back(player_2);
}
else
{
Card dealer_3 = draw(adeck);
dealers_cards.push_back(dealer_3);
}
}
std::string blackjack()
{
card_vec player_cards;
card_vec dealer_cards;
card_vec adeck = deck();
std::vector<int> player_scores;
std::vector<int> dealer_scores;
int input;
deal(adeck, dealer_cards, player_cards);
for (int i = 0; i < 2; ++i)
{
player_scores.push_back(player_cards[i].score);
dealer_scores.push_back(dealer_cards[i].score);
}
auto player_card_1 = player_cards[0].name;
auto player_card_2 = player_cards[1].name;
auto dealer_card_1 = dealer_cards[0].name;
auto dealer_card_2 = dealer_cards[1].name;
std::cout << "Your cards are: " << player_card_1 << " and " << player_card_2 << std::endl;
std::cout << "The dealer reveals: " << dealer_card_1 << std::endl;
std::cout << "Press 1 to Hit or Press 2 to Stay" << std::endl;
std::cin >> input;
while (std::accumulate(player_scores.begin(), player_scores.end(), 0) <= 21)
{
if (input == 1)
{
Card new_card = draw(adeck);
std::cout << "You were dealt a " << new_card.name << std::endl;
player_scores.push_back(new_card.score);
std::cin >> input;
}
else if (input == 2)
{
break;
}
}
if (std::accumulate(player_scores.begin(), player_scores.end(), 0) > 21)
return "You're busted!";
else if (std::accumulate(player_scores.begin(), player_scores.end(), 0) == 21)
return "Perfect win!";
std::cout << "The dealer reveals: " << dealer_card_2 << std::endl;
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) > 17)
{
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
else
{
while (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) <= 17)
{
Card new_card = draw(adeck);
std::cout << "Dealer reveals: " << new_card.name << std::endl;
dealer_scores.push_back(new_card.score);
}
}
if (std::accumulate(dealer_scores.begin(), dealer_scores.end(), 0) >
std::accumulate(player_scores.begin(), player_scores.end(), 0))
{
return "You lose!";
}
else
{
return "You win!";
}
}
int main()
{
std::cout << blackjack() << std::endl;
return 0;
}
c++ c++14 playing-cards
c++ c++14 playing-cards
New contributor
New contributor
edited 2 days ago
200_success
127k15148410
127k15148410
New contributor
asked 2 days ago
ChubakBidpaa
12217
12217
New contributor
New contributor
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
2
down vote
Being consistent
You have inconsistency between Description, filename and function name.
- in your title and in your description, you talk about Bist-o-yek a card game similar to Blackjack
- your main function and your file are just named Blackjack.
Try to be consistent between all your parts or you might lose users because of conflicting information. People can have to deal with unexpected behaviors because they might think that's a regular BlackJack.
Coding idiomatically
Prefer
using
overtypedef</u>
:
- the Standard recommended way.
- more consistent with variables assignment (name on the left of the equa signl, attributes on the right)
- more consistent with case where you make template aliases
- make going from type alias to template alias easier.
But, we'll see later that this alias is not even necessary
Try to don't use deprecated function :
The
std::random_shuffle
is deprecated in C++14 and even removed in C++17. Instead you should usestd::shuffle
. (and if possible, with a good seeding, like explained here)
Consider inputs ill-formed
Even if you said you knew it, you should always check the inputs as ill-formed. Especially that it's easy to check.
Avoid
std::endl;
It send the character
'n'
to the stream and thenflush
the stream. If you want a flush, do it explicitly :.... << 'n' << std::flush;
.
Going lazy for more efficiency
You do a lot of things for nothing:
- Why shuffling each times the deck when drawing a card? Since the deck is already shuffled, just take the last card. Plus bonus, it's cheaper to remove the last element in a vector than a random one.
- Why re-shuffling again two times in the
deal()
method - Give directly the
draw()
result topush_back
, it will be cleaner and avoid temporaries. - You
std::accumulate
many many times even whenplayer_score
ordealer_score
didn't change.
Defining et rethinking entities
Card
What's a Card?
A card is a set of two things:
- the Suit, a value among a enumeration of four possibilities (Club, Diamond, Heart, Spade)
- the Rank, depending on how you imagine it:
- a value in the range of 1 to 13
- a value among a enumeration of thirteen possibilities (As, Two, ..., Queen, King)
Displaying
A card may be displayed it in many ways:
Rank: full names (As, Two, Three, ..., Queen, King) or short names (A, 2, 3, ..., Q, K)
Suits : full names (Club, Diamond, Heart, Spade), first letter (C, D, H, S) or unicode symbols.
Card: Combination of theses possibilities, with maybe some decoration (Queen of Hearts, [1 **'s ♤], ...)
In your current code, a card isn't really a card. It's just a string with a value associated and if you want to change to display of a card, you have to change a lot of things in your code. Making it more generic can make it less painful and more explicit.
struct Card {
enum class Suit {
Heart, Club, Spade, Diamond, INVALID
};
enum class Rank {
Ace = 1, Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, INVALID
};
constexpr Card() : rank(Rank::INVALID), suit{Suit::INVALID} {}
constexpr Card(Rank rank, Suit suit) : rank{rank}, suit{suit} {}
bool valid() { return rank != Rank::INVALID && suit != Suit::INVALID; }
Rank rank;
Suit suit;
};
std::string to_string(Card::Rank rank) {
switch (rank) {
case Card::Rank::Ace: return "A";
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
case Card::Rank::Ten:
using std::to_string;
return to_string(static_cast<std::underlying_type_t<Card::Rank>>(rank));
case Card::Rank::Jack: return "J";
case Card::Rank::Queen: return "Q";
case Card::Rank::King: return "K";
default: throw std::range_error("Rank is out of range");
}
}
std::string to_string(Card::Suit suit) {
switch (suit) {
case Card::Suit::Heart: return "u2665";
case Card::Suit::Club: return "u2667";
case Card::Suit::Spade: return "u2664";
case Card::Suit::Diamond: return "u2666";
default: throw std::range_error("Suit is out of range");
}
}
std::string to_string(Card card) {
return to_string(card.rank) + to_string(card.suit);
}
Here, the two INVALID
enum values and the `valid() method is just for convenience.
Deck
What's a Deck?
Some bunch of cards, with all cards possibles at beginning. Then, we draw cards from this deck, one by one, until no more. If it's not empty, we can also shuffle cards. We can also reset the deck to get a new complete one, shuffled.
Here, advantages are that if later, you want to do more rounds, without restarting the program, you don't have to rebuild the Deck, you just copy the static one, compile time computed, and shuffle it.
class Deck {
public:
Deck()
: cards{new_deck.begin(), new_deck.end()}
{
shuffle();
}
void reset() {
cards = {new_deck.begin(), new_deck.end()};
shuffle();
}
bool empty() const {
return cards.empty();
}
Card draw() {
if (empty()) return {Card::Rank::INVALID, Card::Suit::INVALID};
Card last = cards.back();
cards.pop_back();
return last;
}
void shuffle() {
if (empty()) return;
// from https://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
std::shuffle(cards.begin(), cards.end(), () {
std::mt19937::result_type seeds[std::mt19937::state_size];
std::random_device device;
std::uniform_int_distribution<typename std::mt19937::result_type> dist;
std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
std::seed_seq seq(std::begin(seeds), std::end(seeds));
return std::mt19937(seq);
}());
}
private:
using R = Card::Rank;
using S = Card::Suit;
static constexpr std::array<Card, 52> new_deck {{
{R::Ace, S::Heart}, {R::Ace, S::Club}, {R::Ace, S::Spade}, {R::Ace, S::Diamond},
{R::Two, S::Heart}, {R::Two, S::Club}, {R::Two, S::Spade}, {R::Two, S::Diamond},
{R::Three, S::Heart}, {R::Three, S::Club}, {R::Three, S::Spade}, {R::Three, S::Diamond},
{R::Four, S::Heart}, {R::Four, S::Club}, {R::Four, S::Spade}, {R::Four, S::Diamond},
{R::Five, S::Heart}, {R::Five, S::Club}, {R::Five, S::Spade}, {R::Five, S::Diamond},
{R::Six, S::Heart}, {R::Six, S::Club}, {R::Six, S::Spade}, {R::Six, S::Diamond},
{R::Seven, S::Heart}, {R::Seven, S::Club}, {R::Seven, S::Spade}, {R::Seven, S::Diamond},
{R::Eight, S::Heart}, {R::Eight, S::Club}, {R::Eight, S::Spade}, {R::Eight, S::Diamond},
{R::Nine, S::Heart}, {R::Nine, S::Club}, {R::Nine, S::Spade}, {R::Nine, S::Diamond},
{R::Ten, S::Heart}, {R::Ten, S::Club}, {R::Ten, S::Spade}, {R::Ten, S::Diamond},
{R::Jack, S::Heart}, {R::Jack, S::Club}, {R::Jack, S::Spade}, {R::Jack, S::Diamond},
{R::Queen, S::Heart}, {R::Queen, S::Club}, {R::Queen, S::Spade}, {R::Queen, S::Diamond},
{R::King, S::Heart}, {R::King, S::Club}, {R::King, S::Spade}, {R::King, S::Diamond},
}};
std::vector<Card> cards;
};
constexpr std::array<Card, 52> Deck::new_deck;
Hand
Both dealer and player have a bunch of card called a hand. Each times they take a new card drawing the deck, the points of this card being added to the score of their hand.
struct Hand {
void take(Card card)
{
switch (card.rank) {
case Card::Rank::Ace:
score += 11;
break;
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
score += static_cast<std::underlying_type_t<Card::Rank>>(card.rank);
break;
case Card::Rank::Ten:
case Card::Rank::Jack:
case Card::Rank::Queen:
case Card::Rank::King:
score += 10;
break;
default: throw std::range_error("Hand::take() - Rank is out of range");
}
cards.push_back(card);
}
int score{};
std::vector<Card> cards{};
};
Example of usage:
auto deck = Deck{};
Hand dealer;
Hand player;
dealer.take(deck.draw());
player.take(deck.draw());
player.take(deck.draw());
std::cout << "You got: " ;
for(auto card : player.cards) {
std::cout << to_string(card) << ' ';
}
std::cout << "(score: " << player.score <<")";
dealer.take(deck.draw());
//....
End Words
Try to don't return the final string to the main. Instead display it from your function. Or Even better, write a outputting function, and you pass it all output instead of calling explicitly std::cout << ..
everywhere in your code, so, if you have to change output method, you only have to do in one place.
I wasn't exhaustive, but I tried to talk about most important things.
If you go on C++17 you can benefit of some features:
Returning
std::optional<Card>
the thedraw()
function, making the return type more explicit.You can simplify the
new_deck
definition:
.
static constexpr auto new_deck = {
constexpr auto suits = std::array {
Card::Suit::Heart, Card::Suit::Club, Card::Suit::Spade, Card::Suit::Diamond
};
constexpr auto ranks = std::array {
Card::Rank::Ace, Card::Rank::Two, Card::Rank::Three, Card::Rank::Four, Card::Rank::Five,
Card::Rank::Six, Card::Rank::Seven, Card::Rank::Eight, Card::Rank::Nine, Card::Rank::Ten,
Card::Rank::Jack, Card::Rank::Queen, Card::Rank::King
};
std::array<Card, suits.size() * ranks.size()> cards{};
for (std::size_t i = 0; i < cards.size(); ++i) {
cards[i] = {ranks[i % ranks.size()], suits[i % suits.size()]};
}
return cards;
}();
What's next?
- Sanitize inputs
- Maybe try to implement the full game
- With multiples rounds
- Allowing bets
- With multi-player
- Also, I searched on google and didn't found talk relating this variant. Maybe a way to display the rules to users can be helpful.
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
Being consistent
You have inconsistency between Description, filename and function name.
- in your title and in your description, you talk about Bist-o-yek a card game similar to Blackjack
- your main function and your file are just named Blackjack.
Try to be consistent between all your parts or you might lose users because of conflicting information. People can have to deal with unexpected behaviors because they might think that's a regular BlackJack.
Coding idiomatically
Prefer
using
overtypedef</u>
:
- the Standard recommended way.
- more consistent with variables assignment (name on the left of the equa signl, attributes on the right)
- more consistent with case where you make template aliases
- make going from type alias to template alias easier.
But, we'll see later that this alias is not even necessary
Try to don't use deprecated function :
The
std::random_shuffle
is deprecated in C++14 and even removed in C++17. Instead you should usestd::shuffle
. (and if possible, with a good seeding, like explained here)
Consider inputs ill-formed
Even if you said you knew it, you should always check the inputs as ill-formed. Especially that it's easy to check.
Avoid
std::endl;
It send the character
'n'
to the stream and thenflush
the stream. If you want a flush, do it explicitly :.... << 'n' << std::flush;
.
Going lazy for more efficiency
You do a lot of things for nothing:
- Why shuffling each times the deck when drawing a card? Since the deck is already shuffled, just take the last card. Plus bonus, it's cheaper to remove the last element in a vector than a random one.
- Why re-shuffling again two times in the
deal()
method - Give directly the
draw()
result topush_back
, it will be cleaner and avoid temporaries. - You
std::accumulate
many many times even whenplayer_score
ordealer_score
didn't change.
Defining et rethinking entities
Card
What's a Card?
A card is a set of two things:
- the Suit, a value among a enumeration of four possibilities (Club, Diamond, Heart, Spade)
- the Rank, depending on how you imagine it:
- a value in the range of 1 to 13
- a value among a enumeration of thirteen possibilities (As, Two, ..., Queen, King)
Displaying
A card may be displayed it in many ways:
Rank: full names (As, Two, Three, ..., Queen, King) or short names (A, 2, 3, ..., Q, K)
Suits : full names (Club, Diamond, Heart, Spade), first letter (C, D, H, S) or unicode symbols.
Card: Combination of theses possibilities, with maybe some decoration (Queen of Hearts, [1 **'s ♤], ...)
In your current code, a card isn't really a card. It's just a string with a value associated and if you want to change to display of a card, you have to change a lot of things in your code. Making it more generic can make it less painful and more explicit.
struct Card {
enum class Suit {
Heart, Club, Spade, Diamond, INVALID
};
enum class Rank {
Ace = 1, Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, INVALID
};
constexpr Card() : rank(Rank::INVALID), suit{Suit::INVALID} {}
constexpr Card(Rank rank, Suit suit) : rank{rank}, suit{suit} {}
bool valid() { return rank != Rank::INVALID && suit != Suit::INVALID; }
Rank rank;
Suit suit;
};
std::string to_string(Card::Rank rank) {
switch (rank) {
case Card::Rank::Ace: return "A";
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
case Card::Rank::Ten:
using std::to_string;
return to_string(static_cast<std::underlying_type_t<Card::Rank>>(rank));
case Card::Rank::Jack: return "J";
case Card::Rank::Queen: return "Q";
case Card::Rank::King: return "K";
default: throw std::range_error("Rank is out of range");
}
}
std::string to_string(Card::Suit suit) {
switch (suit) {
case Card::Suit::Heart: return "u2665";
case Card::Suit::Club: return "u2667";
case Card::Suit::Spade: return "u2664";
case Card::Suit::Diamond: return "u2666";
default: throw std::range_error("Suit is out of range");
}
}
std::string to_string(Card card) {
return to_string(card.rank) + to_string(card.suit);
}
Here, the two INVALID
enum values and the `valid() method is just for convenience.
Deck
What's a Deck?
Some bunch of cards, with all cards possibles at beginning. Then, we draw cards from this deck, one by one, until no more. If it's not empty, we can also shuffle cards. We can also reset the deck to get a new complete one, shuffled.
Here, advantages are that if later, you want to do more rounds, without restarting the program, you don't have to rebuild the Deck, you just copy the static one, compile time computed, and shuffle it.
class Deck {
public:
Deck()
: cards{new_deck.begin(), new_deck.end()}
{
shuffle();
}
void reset() {
cards = {new_deck.begin(), new_deck.end()};
shuffle();
}
bool empty() const {
return cards.empty();
}
Card draw() {
if (empty()) return {Card::Rank::INVALID, Card::Suit::INVALID};
Card last = cards.back();
cards.pop_back();
return last;
}
void shuffle() {
if (empty()) return;
// from https://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
std::shuffle(cards.begin(), cards.end(), () {
std::mt19937::result_type seeds[std::mt19937::state_size];
std::random_device device;
std::uniform_int_distribution<typename std::mt19937::result_type> dist;
std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
std::seed_seq seq(std::begin(seeds), std::end(seeds));
return std::mt19937(seq);
}());
}
private:
using R = Card::Rank;
using S = Card::Suit;
static constexpr std::array<Card, 52> new_deck {{
{R::Ace, S::Heart}, {R::Ace, S::Club}, {R::Ace, S::Spade}, {R::Ace, S::Diamond},
{R::Two, S::Heart}, {R::Two, S::Club}, {R::Two, S::Spade}, {R::Two, S::Diamond},
{R::Three, S::Heart}, {R::Three, S::Club}, {R::Three, S::Spade}, {R::Three, S::Diamond},
{R::Four, S::Heart}, {R::Four, S::Club}, {R::Four, S::Spade}, {R::Four, S::Diamond},
{R::Five, S::Heart}, {R::Five, S::Club}, {R::Five, S::Spade}, {R::Five, S::Diamond},
{R::Six, S::Heart}, {R::Six, S::Club}, {R::Six, S::Spade}, {R::Six, S::Diamond},
{R::Seven, S::Heart}, {R::Seven, S::Club}, {R::Seven, S::Spade}, {R::Seven, S::Diamond},
{R::Eight, S::Heart}, {R::Eight, S::Club}, {R::Eight, S::Spade}, {R::Eight, S::Diamond},
{R::Nine, S::Heart}, {R::Nine, S::Club}, {R::Nine, S::Spade}, {R::Nine, S::Diamond},
{R::Ten, S::Heart}, {R::Ten, S::Club}, {R::Ten, S::Spade}, {R::Ten, S::Diamond},
{R::Jack, S::Heart}, {R::Jack, S::Club}, {R::Jack, S::Spade}, {R::Jack, S::Diamond},
{R::Queen, S::Heart}, {R::Queen, S::Club}, {R::Queen, S::Spade}, {R::Queen, S::Diamond},
{R::King, S::Heart}, {R::King, S::Club}, {R::King, S::Spade}, {R::King, S::Diamond},
}};
std::vector<Card> cards;
};
constexpr std::array<Card, 52> Deck::new_deck;
Hand
Both dealer and player have a bunch of card called a hand. Each times they take a new card drawing the deck, the points of this card being added to the score of their hand.
struct Hand {
void take(Card card)
{
switch (card.rank) {
case Card::Rank::Ace:
score += 11;
break;
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
score += static_cast<std::underlying_type_t<Card::Rank>>(card.rank);
break;
case Card::Rank::Ten:
case Card::Rank::Jack:
case Card::Rank::Queen:
case Card::Rank::King:
score += 10;
break;
default: throw std::range_error("Hand::take() - Rank is out of range");
}
cards.push_back(card);
}
int score{};
std::vector<Card> cards{};
};
Example of usage:
auto deck = Deck{};
Hand dealer;
Hand player;
dealer.take(deck.draw());
player.take(deck.draw());
player.take(deck.draw());
std::cout << "You got: " ;
for(auto card : player.cards) {
std::cout << to_string(card) << ' ';
}
std::cout << "(score: " << player.score <<")";
dealer.take(deck.draw());
//....
End Words
Try to don't return the final string to the main. Instead display it from your function. Or Even better, write a outputting function, and you pass it all output instead of calling explicitly std::cout << ..
everywhere in your code, so, if you have to change output method, you only have to do in one place.
I wasn't exhaustive, but I tried to talk about most important things.
If you go on C++17 you can benefit of some features:
Returning
std::optional<Card>
the thedraw()
function, making the return type more explicit.You can simplify the
new_deck
definition:
.
static constexpr auto new_deck = {
constexpr auto suits = std::array {
Card::Suit::Heart, Card::Suit::Club, Card::Suit::Spade, Card::Suit::Diamond
};
constexpr auto ranks = std::array {
Card::Rank::Ace, Card::Rank::Two, Card::Rank::Three, Card::Rank::Four, Card::Rank::Five,
Card::Rank::Six, Card::Rank::Seven, Card::Rank::Eight, Card::Rank::Nine, Card::Rank::Ten,
Card::Rank::Jack, Card::Rank::Queen, Card::Rank::King
};
std::array<Card, suits.size() * ranks.size()> cards{};
for (std::size_t i = 0; i < cards.size(); ++i) {
cards[i] = {ranks[i % ranks.size()], suits[i % suits.size()]};
}
return cards;
}();
What's next?
- Sanitize inputs
- Maybe try to implement the full game
- With multiples rounds
- Allowing bets
- With multi-player
- Also, I searched on google and didn't found talk relating this variant. Maybe a way to display the rules to users can be helpful.
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
add a comment |
up vote
2
down vote
Being consistent
You have inconsistency between Description, filename and function name.
- in your title and in your description, you talk about Bist-o-yek a card game similar to Blackjack
- your main function and your file are just named Blackjack.
Try to be consistent between all your parts or you might lose users because of conflicting information. People can have to deal with unexpected behaviors because they might think that's a regular BlackJack.
Coding idiomatically
Prefer
using
overtypedef</u>
:
- the Standard recommended way.
- more consistent with variables assignment (name on the left of the equa signl, attributes on the right)
- more consistent with case where you make template aliases
- make going from type alias to template alias easier.
But, we'll see later that this alias is not even necessary
Try to don't use deprecated function :
The
std::random_shuffle
is deprecated in C++14 and even removed in C++17. Instead you should usestd::shuffle
. (and if possible, with a good seeding, like explained here)
Consider inputs ill-formed
Even if you said you knew it, you should always check the inputs as ill-formed. Especially that it's easy to check.
Avoid
std::endl;
It send the character
'n'
to the stream and thenflush
the stream. If you want a flush, do it explicitly :.... << 'n' << std::flush;
.
Going lazy for more efficiency
You do a lot of things for nothing:
- Why shuffling each times the deck when drawing a card? Since the deck is already shuffled, just take the last card. Plus bonus, it's cheaper to remove the last element in a vector than a random one.
- Why re-shuffling again two times in the
deal()
method - Give directly the
draw()
result topush_back
, it will be cleaner and avoid temporaries. - You
std::accumulate
many many times even whenplayer_score
ordealer_score
didn't change.
Defining et rethinking entities
Card
What's a Card?
A card is a set of two things:
- the Suit, a value among a enumeration of four possibilities (Club, Diamond, Heart, Spade)
- the Rank, depending on how you imagine it:
- a value in the range of 1 to 13
- a value among a enumeration of thirteen possibilities (As, Two, ..., Queen, King)
Displaying
A card may be displayed it in many ways:
Rank: full names (As, Two, Three, ..., Queen, King) or short names (A, 2, 3, ..., Q, K)
Suits : full names (Club, Diamond, Heart, Spade), first letter (C, D, H, S) or unicode symbols.
Card: Combination of theses possibilities, with maybe some decoration (Queen of Hearts, [1 **'s ♤], ...)
In your current code, a card isn't really a card. It's just a string with a value associated and if you want to change to display of a card, you have to change a lot of things in your code. Making it more generic can make it less painful and more explicit.
struct Card {
enum class Suit {
Heart, Club, Spade, Diamond, INVALID
};
enum class Rank {
Ace = 1, Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, INVALID
};
constexpr Card() : rank(Rank::INVALID), suit{Suit::INVALID} {}
constexpr Card(Rank rank, Suit suit) : rank{rank}, suit{suit} {}
bool valid() { return rank != Rank::INVALID && suit != Suit::INVALID; }
Rank rank;
Suit suit;
};
std::string to_string(Card::Rank rank) {
switch (rank) {
case Card::Rank::Ace: return "A";
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
case Card::Rank::Ten:
using std::to_string;
return to_string(static_cast<std::underlying_type_t<Card::Rank>>(rank));
case Card::Rank::Jack: return "J";
case Card::Rank::Queen: return "Q";
case Card::Rank::King: return "K";
default: throw std::range_error("Rank is out of range");
}
}
std::string to_string(Card::Suit suit) {
switch (suit) {
case Card::Suit::Heart: return "u2665";
case Card::Suit::Club: return "u2667";
case Card::Suit::Spade: return "u2664";
case Card::Suit::Diamond: return "u2666";
default: throw std::range_error("Suit is out of range");
}
}
std::string to_string(Card card) {
return to_string(card.rank) + to_string(card.suit);
}
Here, the two INVALID
enum values and the `valid() method is just for convenience.
Deck
What's a Deck?
Some bunch of cards, with all cards possibles at beginning. Then, we draw cards from this deck, one by one, until no more. If it's not empty, we can also shuffle cards. We can also reset the deck to get a new complete one, shuffled.
Here, advantages are that if later, you want to do more rounds, without restarting the program, you don't have to rebuild the Deck, you just copy the static one, compile time computed, and shuffle it.
class Deck {
public:
Deck()
: cards{new_deck.begin(), new_deck.end()}
{
shuffle();
}
void reset() {
cards = {new_deck.begin(), new_deck.end()};
shuffle();
}
bool empty() const {
return cards.empty();
}
Card draw() {
if (empty()) return {Card::Rank::INVALID, Card::Suit::INVALID};
Card last = cards.back();
cards.pop_back();
return last;
}
void shuffle() {
if (empty()) return;
// from https://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
std::shuffle(cards.begin(), cards.end(), () {
std::mt19937::result_type seeds[std::mt19937::state_size];
std::random_device device;
std::uniform_int_distribution<typename std::mt19937::result_type> dist;
std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
std::seed_seq seq(std::begin(seeds), std::end(seeds));
return std::mt19937(seq);
}());
}
private:
using R = Card::Rank;
using S = Card::Suit;
static constexpr std::array<Card, 52> new_deck {{
{R::Ace, S::Heart}, {R::Ace, S::Club}, {R::Ace, S::Spade}, {R::Ace, S::Diamond},
{R::Two, S::Heart}, {R::Two, S::Club}, {R::Two, S::Spade}, {R::Two, S::Diamond},
{R::Three, S::Heart}, {R::Three, S::Club}, {R::Three, S::Spade}, {R::Three, S::Diamond},
{R::Four, S::Heart}, {R::Four, S::Club}, {R::Four, S::Spade}, {R::Four, S::Diamond},
{R::Five, S::Heart}, {R::Five, S::Club}, {R::Five, S::Spade}, {R::Five, S::Diamond},
{R::Six, S::Heart}, {R::Six, S::Club}, {R::Six, S::Spade}, {R::Six, S::Diamond},
{R::Seven, S::Heart}, {R::Seven, S::Club}, {R::Seven, S::Spade}, {R::Seven, S::Diamond},
{R::Eight, S::Heart}, {R::Eight, S::Club}, {R::Eight, S::Spade}, {R::Eight, S::Diamond},
{R::Nine, S::Heart}, {R::Nine, S::Club}, {R::Nine, S::Spade}, {R::Nine, S::Diamond},
{R::Ten, S::Heart}, {R::Ten, S::Club}, {R::Ten, S::Spade}, {R::Ten, S::Diamond},
{R::Jack, S::Heart}, {R::Jack, S::Club}, {R::Jack, S::Spade}, {R::Jack, S::Diamond},
{R::Queen, S::Heart}, {R::Queen, S::Club}, {R::Queen, S::Spade}, {R::Queen, S::Diamond},
{R::King, S::Heart}, {R::King, S::Club}, {R::King, S::Spade}, {R::King, S::Diamond},
}};
std::vector<Card> cards;
};
constexpr std::array<Card, 52> Deck::new_deck;
Hand
Both dealer and player have a bunch of card called a hand. Each times they take a new card drawing the deck, the points of this card being added to the score of their hand.
struct Hand {
void take(Card card)
{
switch (card.rank) {
case Card::Rank::Ace:
score += 11;
break;
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
score += static_cast<std::underlying_type_t<Card::Rank>>(card.rank);
break;
case Card::Rank::Ten:
case Card::Rank::Jack:
case Card::Rank::Queen:
case Card::Rank::King:
score += 10;
break;
default: throw std::range_error("Hand::take() - Rank is out of range");
}
cards.push_back(card);
}
int score{};
std::vector<Card> cards{};
};
Example of usage:
auto deck = Deck{};
Hand dealer;
Hand player;
dealer.take(deck.draw());
player.take(deck.draw());
player.take(deck.draw());
std::cout << "You got: " ;
for(auto card : player.cards) {
std::cout << to_string(card) << ' ';
}
std::cout << "(score: " << player.score <<")";
dealer.take(deck.draw());
//....
End Words
Try to don't return the final string to the main. Instead display it from your function. Or Even better, write a outputting function, and you pass it all output instead of calling explicitly std::cout << ..
everywhere in your code, so, if you have to change output method, you only have to do in one place.
I wasn't exhaustive, but I tried to talk about most important things.
If you go on C++17 you can benefit of some features:
Returning
std::optional<Card>
the thedraw()
function, making the return type more explicit.You can simplify the
new_deck
definition:
.
static constexpr auto new_deck = {
constexpr auto suits = std::array {
Card::Suit::Heart, Card::Suit::Club, Card::Suit::Spade, Card::Suit::Diamond
};
constexpr auto ranks = std::array {
Card::Rank::Ace, Card::Rank::Two, Card::Rank::Three, Card::Rank::Four, Card::Rank::Five,
Card::Rank::Six, Card::Rank::Seven, Card::Rank::Eight, Card::Rank::Nine, Card::Rank::Ten,
Card::Rank::Jack, Card::Rank::Queen, Card::Rank::King
};
std::array<Card, suits.size() * ranks.size()> cards{};
for (std::size_t i = 0; i < cards.size(); ++i) {
cards[i] = {ranks[i % ranks.size()], suits[i % suits.size()]};
}
return cards;
}();
What's next?
- Sanitize inputs
- Maybe try to implement the full game
- With multiples rounds
- Allowing bets
- With multi-player
- Also, I searched on google and didn't found talk relating this variant. Maybe a way to display the rules to users can be helpful.
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
add a comment |
up vote
2
down vote
up vote
2
down vote
Being consistent
You have inconsistency between Description, filename and function name.
- in your title and in your description, you talk about Bist-o-yek a card game similar to Blackjack
- your main function and your file are just named Blackjack.
Try to be consistent between all your parts or you might lose users because of conflicting information. People can have to deal with unexpected behaviors because they might think that's a regular BlackJack.
Coding idiomatically
Prefer
using
overtypedef</u>
:
- the Standard recommended way.
- more consistent with variables assignment (name on the left of the equa signl, attributes on the right)
- more consistent with case where you make template aliases
- make going from type alias to template alias easier.
But, we'll see later that this alias is not even necessary
Try to don't use deprecated function :
The
std::random_shuffle
is deprecated in C++14 and even removed in C++17. Instead you should usestd::shuffle
. (and if possible, with a good seeding, like explained here)
Consider inputs ill-formed
Even if you said you knew it, you should always check the inputs as ill-formed. Especially that it's easy to check.
Avoid
std::endl;
It send the character
'n'
to the stream and thenflush
the stream. If you want a flush, do it explicitly :.... << 'n' << std::flush;
.
Going lazy for more efficiency
You do a lot of things for nothing:
- Why shuffling each times the deck when drawing a card? Since the deck is already shuffled, just take the last card. Plus bonus, it's cheaper to remove the last element in a vector than a random one.
- Why re-shuffling again two times in the
deal()
method - Give directly the
draw()
result topush_back
, it will be cleaner and avoid temporaries. - You
std::accumulate
many many times even whenplayer_score
ordealer_score
didn't change.
Defining et rethinking entities
Card
What's a Card?
A card is a set of two things:
- the Suit, a value among a enumeration of four possibilities (Club, Diamond, Heart, Spade)
- the Rank, depending on how you imagine it:
- a value in the range of 1 to 13
- a value among a enumeration of thirteen possibilities (As, Two, ..., Queen, King)
Displaying
A card may be displayed it in many ways:
Rank: full names (As, Two, Three, ..., Queen, King) or short names (A, 2, 3, ..., Q, K)
Suits : full names (Club, Diamond, Heart, Spade), first letter (C, D, H, S) or unicode symbols.
Card: Combination of theses possibilities, with maybe some decoration (Queen of Hearts, [1 **'s ♤], ...)
In your current code, a card isn't really a card. It's just a string with a value associated and if you want to change to display of a card, you have to change a lot of things in your code. Making it more generic can make it less painful and more explicit.
struct Card {
enum class Suit {
Heart, Club, Spade, Diamond, INVALID
};
enum class Rank {
Ace = 1, Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, INVALID
};
constexpr Card() : rank(Rank::INVALID), suit{Suit::INVALID} {}
constexpr Card(Rank rank, Suit suit) : rank{rank}, suit{suit} {}
bool valid() { return rank != Rank::INVALID && suit != Suit::INVALID; }
Rank rank;
Suit suit;
};
std::string to_string(Card::Rank rank) {
switch (rank) {
case Card::Rank::Ace: return "A";
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
case Card::Rank::Ten:
using std::to_string;
return to_string(static_cast<std::underlying_type_t<Card::Rank>>(rank));
case Card::Rank::Jack: return "J";
case Card::Rank::Queen: return "Q";
case Card::Rank::King: return "K";
default: throw std::range_error("Rank is out of range");
}
}
std::string to_string(Card::Suit suit) {
switch (suit) {
case Card::Suit::Heart: return "u2665";
case Card::Suit::Club: return "u2667";
case Card::Suit::Spade: return "u2664";
case Card::Suit::Diamond: return "u2666";
default: throw std::range_error("Suit is out of range");
}
}
std::string to_string(Card card) {
return to_string(card.rank) + to_string(card.suit);
}
Here, the two INVALID
enum values and the `valid() method is just for convenience.
Deck
What's a Deck?
Some bunch of cards, with all cards possibles at beginning. Then, we draw cards from this deck, one by one, until no more. If it's not empty, we can also shuffle cards. We can also reset the deck to get a new complete one, shuffled.
Here, advantages are that if later, you want to do more rounds, without restarting the program, you don't have to rebuild the Deck, you just copy the static one, compile time computed, and shuffle it.
class Deck {
public:
Deck()
: cards{new_deck.begin(), new_deck.end()}
{
shuffle();
}
void reset() {
cards = {new_deck.begin(), new_deck.end()};
shuffle();
}
bool empty() const {
return cards.empty();
}
Card draw() {
if (empty()) return {Card::Rank::INVALID, Card::Suit::INVALID};
Card last = cards.back();
cards.pop_back();
return last;
}
void shuffle() {
if (empty()) return;
// from https://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
std::shuffle(cards.begin(), cards.end(), () {
std::mt19937::result_type seeds[std::mt19937::state_size];
std::random_device device;
std::uniform_int_distribution<typename std::mt19937::result_type> dist;
std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
std::seed_seq seq(std::begin(seeds), std::end(seeds));
return std::mt19937(seq);
}());
}
private:
using R = Card::Rank;
using S = Card::Suit;
static constexpr std::array<Card, 52> new_deck {{
{R::Ace, S::Heart}, {R::Ace, S::Club}, {R::Ace, S::Spade}, {R::Ace, S::Diamond},
{R::Two, S::Heart}, {R::Two, S::Club}, {R::Two, S::Spade}, {R::Two, S::Diamond},
{R::Three, S::Heart}, {R::Three, S::Club}, {R::Three, S::Spade}, {R::Three, S::Diamond},
{R::Four, S::Heart}, {R::Four, S::Club}, {R::Four, S::Spade}, {R::Four, S::Diamond},
{R::Five, S::Heart}, {R::Five, S::Club}, {R::Five, S::Spade}, {R::Five, S::Diamond},
{R::Six, S::Heart}, {R::Six, S::Club}, {R::Six, S::Spade}, {R::Six, S::Diamond},
{R::Seven, S::Heart}, {R::Seven, S::Club}, {R::Seven, S::Spade}, {R::Seven, S::Diamond},
{R::Eight, S::Heart}, {R::Eight, S::Club}, {R::Eight, S::Spade}, {R::Eight, S::Diamond},
{R::Nine, S::Heart}, {R::Nine, S::Club}, {R::Nine, S::Spade}, {R::Nine, S::Diamond},
{R::Ten, S::Heart}, {R::Ten, S::Club}, {R::Ten, S::Spade}, {R::Ten, S::Diamond},
{R::Jack, S::Heart}, {R::Jack, S::Club}, {R::Jack, S::Spade}, {R::Jack, S::Diamond},
{R::Queen, S::Heart}, {R::Queen, S::Club}, {R::Queen, S::Spade}, {R::Queen, S::Diamond},
{R::King, S::Heart}, {R::King, S::Club}, {R::King, S::Spade}, {R::King, S::Diamond},
}};
std::vector<Card> cards;
};
constexpr std::array<Card, 52> Deck::new_deck;
Hand
Both dealer and player have a bunch of card called a hand. Each times they take a new card drawing the deck, the points of this card being added to the score of their hand.
struct Hand {
void take(Card card)
{
switch (card.rank) {
case Card::Rank::Ace:
score += 11;
break;
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
score += static_cast<std::underlying_type_t<Card::Rank>>(card.rank);
break;
case Card::Rank::Ten:
case Card::Rank::Jack:
case Card::Rank::Queen:
case Card::Rank::King:
score += 10;
break;
default: throw std::range_error("Hand::take() - Rank is out of range");
}
cards.push_back(card);
}
int score{};
std::vector<Card> cards{};
};
Example of usage:
auto deck = Deck{};
Hand dealer;
Hand player;
dealer.take(deck.draw());
player.take(deck.draw());
player.take(deck.draw());
std::cout << "You got: " ;
for(auto card : player.cards) {
std::cout << to_string(card) << ' ';
}
std::cout << "(score: " << player.score <<")";
dealer.take(deck.draw());
//....
End Words
Try to don't return the final string to the main. Instead display it from your function. Or Even better, write a outputting function, and you pass it all output instead of calling explicitly std::cout << ..
everywhere in your code, so, if you have to change output method, you only have to do in one place.
I wasn't exhaustive, but I tried to talk about most important things.
If you go on C++17 you can benefit of some features:
Returning
std::optional<Card>
the thedraw()
function, making the return type more explicit.You can simplify the
new_deck
definition:
.
static constexpr auto new_deck = {
constexpr auto suits = std::array {
Card::Suit::Heart, Card::Suit::Club, Card::Suit::Spade, Card::Suit::Diamond
};
constexpr auto ranks = std::array {
Card::Rank::Ace, Card::Rank::Two, Card::Rank::Three, Card::Rank::Four, Card::Rank::Five,
Card::Rank::Six, Card::Rank::Seven, Card::Rank::Eight, Card::Rank::Nine, Card::Rank::Ten,
Card::Rank::Jack, Card::Rank::Queen, Card::Rank::King
};
std::array<Card, suits.size() * ranks.size()> cards{};
for (std::size_t i = 0; i < cards.size(); ++i) {
cards[i] = {ranks[i % ranks.size()], suits[i % suits.size()]};
}
return cards;
}();
What's next?
- Sanitize inputs
- Maybe try to implement the full game
- With multiples rounds
- Allowing bets
- With multi-player
- Also, I searched on google and didn't found talk relating this variant. Maybe a way to display the rules to users can be helpful.
Being consistent
You have inconsistency between Description, filename and function name.
- in your title and in your description, you talk about Bist-o-yek a card game similar to Blackjack
- your main function and your file are just named Blackjack.
Try to be consistent between all your parts or you might lose users because of conflicting information. People can have to deal with unexpected behaviors because they might think that's a regular BlackJack.
Coding idiomatically
Prefer
using
overtypedef</u>
:
- the Standard recommended way.
- more consistent with variables assignment (name on the left of the equa signl, attributes on the right)
- more consistent with case where you make template aliases
- make going from type alias to template alias easier.
But, we'll see later that this alias is not even necessary
Try to don't use deprecated function :
The
std::random_shuffle
is deprecated in C++14 and even removed in C++17. Instead you should usestd::shuffle
. (and if possible, with a good seeding, like explained here)
Consider inputs ill-formed
Even if you said you knew it, you should always check the inputs as ill-formed. Especially that it's easy to check.
Avoid
std::endl;
It send the character
'n'
to the stream and thenflush
the stream. If you want a flush, do it explicitly :.... << 'n' << std::flush;
.
Going lazy for more efficiency
You do a lot of things for nothing:
- Why shuffling each times the deck when drawing a card? Since the deck is already shuffled, just take the last card. Plus bonus, it's cheaper to remove the last element in a vector than a random one.
- Why re-shuffling again two times in the
deal()
method - Give directly the
draw()
result topush_back
, it will be cleaner and avoid temporaries. - You
std::accumulate
many many times even whenplayer_score
ordealer_score
didn't change.
Defining et rethinking entities
Card
What's a Card?
A card is a set of two things:
- the Suit, a value among a enumeration of four possibilities (Club, Diamond, Heart, Spade)
- the Rank, depending on how you imagine it:
- a value in the range of 1 to 13
- a value among a enumeration of thirteen possibilities (As, Two, ..., Queen, King)
Displaying
A card may be displayed it in many ways:
Rank: full names (As, Two, Three, ..., Queen, King) or short names (A, 2, 3, ..., Q, K)
Suits : full names (Club, Diamond, Heart, Spade), first letter (C, D, H, S) or unicode symbols.
Card: Combination of theses possibilities, with maybe some decoration (Queen of Hearts, [1 **'s ♤], ...)
In your current code, a card isn't really a card. It's just a string with a value associated and if you want to change to display of a card, you have to change a lot of things in your code. Making it more generic can make it less painful and more explicit.
struct Card {
enum class Suit {
Heart, Club, Spade, Diamond, INVALID
};
enum class Rank {
Ace = 1, Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, INVALID
};
constexpr Card() : rank(Rank::INVALID), suit{Suit::INVALID} {}
constexpr Card(Rank rank, Suit suit) : rank{rank}, suit{suit} {}
bool valid() { return rank != Rank::INVALID && suit != Suit::INVALID; }
Rank rank;
Suit suit;
};
std::string to_string(Card::Rank rank) {
switch (rank) {
case Card::Rank::Ace: return "A";
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
case Card::Rank::Ten:
using std::to_string;
return to_string(static_cast<std::underlying_type_t<Card::Rank>>(rank));
case Card::Rank::Jack: return "J";
case Card::Rank::Queen: return "Q";
case Card::Rank::King: return "K";
default: throw std::range_error("Rank is out of range");
}
}
std::string to_string(Card::Suit suit) {
switch (suit) {
case Card::Suit::Heart: return "u2665";
case Card::Suit::Club: return "u2667";
case Card::Suit::Spade: return "u2664";
case Card::Suit::Diamond: return "u2666";
default: throw std::range_error("Suit is out of range");
}
}
std::string to_string(Card card) {
return to_string(card.rank) + to_string(card.suit);
}
Here, the two INVALID
enum values and the `valid() method is just for convenience.
Deck
What's a Deck?
Some bunch of cards, with all cards possibles at beginning. Then, we draw cards from this deck, one by one, until no more. If it's not empty, we can also shuffle cards. We can also reset the deck to get a new complete one, shuffled.
Here, advantages are that if later, you want to do more rounds, without restarting the program, you don't have to rebuild the Deck, you just copy the static one, compile time computed, and shuffle it.
class Deck {
public:
Deck()
: cards{new_deck.begin(), new_deck.end()}
{
shuffle();
}
void reset() {
cards = {new_deck.begin(), new_deck.end()};
shuffle();
}
bool empty() const {
return cards.empty();
}
Card draw() {
if (empty()) return {Card::Rank::INVALID, Card::Suit::INVALID};
Card last = cards.back();
cards.pop_back();
return last;
}
void shuffle() {
if (empty()) return;
// from https://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html
std::shuffle(cards.begin(), cards.end(), () {
std::mt19937::result_type seeds[std::mt19937::state_size];
std::random_device device;
std::uniform_int_distribution<typename std::mt19937::result_type> dist;
std::generate(std::begin(seeds), std::end(seeds), [&] { return dist(device); });
std::seed_seq seq(std::begin(seeds), std::end(seeds));
return std::mt19937(seq);
}());
}
private:
using R = Card::Rank;
using S = Card::Suit;
static constexpr std::array<Card, 52> new_deck {{
{R::Ace, S::Heart}, {R::Ace, S::Club}, {R::Ace, S::Spade}, {R::Ace, S::Diamond},
{R::Two, S::Heart}, {R::Two, S::Club}, {R::Two, S::Spade}, {R::Two, S::Diamond},
{R::Three, S::Heart}, {R::Three, S::Club}, {R::Three, S::Spade}, {R::Three, S::Diamond},
{R::Four, S::Heart}, {R::Four, S::Club}, {R::Four, S::Spade}, {R::Four, S::Diamond},
{R::Five, S::Heart}, {R::Five, S::Club}, {R::Five, S::Spade}, {R::Five, S::Diamond},
{R::Six, S::Heart}, {R::Six, S::Club}, {R::Six, S::Spade}, {R::Six, S::Diamond},
{R::Seven, S::Heart}, {R::Seven, S::Club}, {R::Seven, S::Spade}, {R::Seven, S::Diamond},
{R::Eight, S::Heart}, {R::Eight, S::Club}, {R::Eight, S::Spade}, {R::Eight, S::Diamond},
{R::Nine, S::Heart}, {R::Nine, S::Club}, {R::Nine, S::Spade}, {R::Nine, S::Diamond},
{R::Ten, S::Heart}, {R::Ten, S::Club}, {R::Ten, S::Spade}, {R::Ten, S::Diamond},
{R::Jack, S::Heart}, {R::Jack, S::Club}, {R::Jack, S::Spade}, {R::Jack, S::Diamond},
{R::Queen, S::Heart}, {R::Queen, S::Club}, {R::Queen, S::Spade}, {R::Queen, S::Diamond},
{R::King, S::Heart}, {R::King, S::Club}, {R::King, S::Spade}, {R::King, S::Diamond},
}};
std::vector<Card> cards;
};
constexpr std::array<Card, 52> Deck::new_deck;
Hand
Both dealer and player have a bunch of card called a hand. Each times they take a new card drawing the deck, the points of this card being added to the score of their hand.
struct Hand {
void take(Card card)
{
switch (card.rank) {
case Card::Rank::Ace:
score += 11;
break;
case Card::Rank::Two:
case Card::Rank::Three:
case Card::Rank::Four:
case Card::Rank::Five:
case Card::Rank::Six:
case Card::Rank::Seven:
case Card::Rank::Eight:
case Card::Rank::Nine:
score += static_cast<std::underlying_type_t<Card::Rank>>(card.rank);
break;
case Card::Rank::Ten:
case Card::Rank::Jack:
case Card::Rank::Queen:
case Card::Rank::King:
score += 10;
break;
default: throw std::range_error("Hand::take() - Rank is out of range");
}
cards.push_back(card);
}
int score{};
std::vector<Card> cards{};
};
Example of usage:
auto deck = Deck{};
Hand dealer;
Hand player;
dealer.take(deck.draw());
player.take(deck.draw());
player.take(deck.draw());
std::cout << "You got: " ;
for(auto card : player.cards) {
std::cout << to_string(card) << ' ';
}
std::cout << "(score: " << player.score <<")";
dealer.take(deck.draw());
//....
End Words
Try to don't return the final string to the main. Instead display it from your function. Or Even better, write a outputting function, and you pass it all output instead of calling explicitly std::cout << ..
everywhere in your code, so, if you have to change output method, you only have to do in one place.
I wasn't exhaustive, but I tried to talk about most important things.
If you go on C++17 you can benefit of some features:
Returning
std::optional<Card>
the thedraw()
function, making the return type more explicit.You can simplify the
new_deck
definition:
.
static constexpr auto new_deck = {
constexpr auto suits = std::array {
Card::Suit::Heart, Card::Suit::Club, Card::Suit::Spade, Card::Suit::Diamond
};
constexpr auto ranks = std::array {
Card::Rank::Ace, Card::Rank::Two, Card::Rank::Three, Card::Rank::Four, Card::Rank::Five,
Card::Rank::Six, Card::Rank::Seven, Card::Rank::Eight, Card::Rank::Nine, Card::Rank::Ten,
Card::Rank::Jack, Card::Rank::Queen, Card::Rank::King
};
std::array<Card, suits.size() * ranks.size()> cards{};
for (std::size_t i = 0; i < cards.size(); ++i) {
cards[i] = {ranks[i % ranks.size()], suits[i % suits.size()]};
}
return cards;
}();
What's next?
- Sanitize inputs
- Maybe try to implement the full game
- With multiples rounds
- Allowing bets
- With multi-player
- Also, I searched on google and didn't found talk relating this variant. Maybe a way to display the rules to users can be helpful.
answered 2 days ago
Calak
1,606112
1,606112
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
add a comment |
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
– ChubakBidpaa
yesterday
add a comment |
ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.
ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.
ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.
ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207895%2fbist-o-yek-a-card-game-similar-to-blackjack%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown