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;
}









share|improve this question









New contributor




ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
























    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;
    }









    share|improve this question









    New contributor




    ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      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;
      }









      share|improve this question









      New contributor




      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      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






      share|improve this question









      New contributor




      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 2 days ago









      200_success

      127k15148410




      127k15148410






      New contributor




      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 2 days ago









      ChubakBidpaa

      12217




      12217




      New contributor




      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      ChubakBidpaa is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          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 usingover typedef</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 use std::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 then flush 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 to push_back, it will be cleaner and avoid temporaries.

          • You std::accumulate many many times even when player_score or dealer_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 the draw() 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.






          share|improve this answer





















          • Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
            – ChubakBidpaa
            yesterday











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.










           

          draft saved


          draft discarded


















          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

























          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 usingover typedef</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 use std::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 then flush 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 to push_back, it will be cleaner and avoid temporaries.

          • You std::accumulate many many times even when player_score or dealer_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 the draw() 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.






          share|improve this answer





















          • Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
            – ChubakBidpaa
            yesterday















          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 usingover typedef</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 use std::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 then flush 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 to push_back, it will be cleaner and avoid temporaries.

          • You std::accumulate many many times even when player_score or dealer_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 the draw() 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.






          share|improve this answer





















          • Thank you. My father taught me this game, I'm not sure maybe it was one of his concoctions?
            – ChubakBidpaa
            yesterday













          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 usingover typedef</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 use std::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 then flush 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 to push_back, it will be cleaner and avoid temporaries.

          • You std::accumulate many many times even when player_score or dealer_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 the draw() 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.






          share|improve this answer












          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 usingover typedef</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 use std::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 then flush 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 to push_back, it will be cleaner and avoid temporaries.

          • You std::accumulate many many times even when player_score or dealer_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 the draw() 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.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          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


















          • 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










          ChubakBidpaa is a new contributor. Be nice, and check out our Code of Conduct.










           

          draft saved


          draft discarded


















          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.















           


          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Quarter-circle Tiles

          build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

          Mont Emei