Home > Blockchain >  Declaring a value to int in arrays
Declaring a value to int in arrays

Time:12-09

I'm trying to make a deck of cards with only using array and no classes.

How do I declare a value to each and every card? It seems very inefficient trying to write it like this, and then trying to give a value to each index position:

int deckOfcards[52]{ 1,2,3,4,5,6,7,8,9,10.......... };

Also I will then draw 2 random cards and declare a winner. Is it possible to use rand() function in arrays?

CodePudding user response:

You can create a loop to populate your array for you..

int deckOfCards[52]{};
for (int i = 0; i < 52; i  )
{
    deckOfCards[i] = i 1;
}

That works just fine for this particular instance, but you may want to use std::size(deckOfCards) in your loop because the size of the array may not always be known.

int deckOfCards[52]{};
for (int i = 0; i < std::size(deckOfCards); i  )
{
    deckOfCards[i] = i 1;
}

Remember that array index's start at 0, so i will go from 0 to 51. That's why we are setting deckOfCards[i] equal to i 1

CodePudding user response:

There is imo even a nicer way to introduce randomness to cards, use std::shuffle. By using this function you get code that kind of explains itself. It will also introduce the deck of cards you are looking for.

#include <algorithm>
#include <array>
#include <random>
#include <iostream>

//-----------------------------------------------------------------------------

struct card_t
{
    // each new instance gets a number which is then increased
    //    at the end is important.
    card_t() :
        number{ g_card_number   }   
    {
    }

    std::size_t number;
    static std::size_t g_card_number;
};

std::size_t card_t::g_card_number = 1;

//-----------------------------------------------------------------------------

int main()
{
    // setup random generation c   style
    std::random_device rd;
    std::default_random_engine random_generator{ rd() };

    // create a deck of 52 cards
    // this will call the constructor for each of them so they all get
    // a unique number
    std::array<card_t, 52> cards;

    // shuffle the cards using the random generator
    std::shuffle(cards.begin(), cards.end(), random_generator);

    std::cout << "first card has number : " << cards[0].number << "\n";
    std::cout << "second card has number : " << cards[1].number << "\n";

    return 0;
}

CodePudding user response:

The requirements are that you want to emulate a standard deck of playing cards, and comments indicate that you want to track the suit and the value. You also claim that you want to do this with just an array of integers.

It is possible, but probably not what you're really after. Simpler solutions have already been posted as answers, but I will attempt to provide an answer that meets the stated requirements.

I'll just say up front that this is likely an XY problem, meaning the problem you stated is not the real problem you're having. You'll see as much with the code.

To uniquely encode two pieces of information into a single int, you'll need a way to encode and decode. The simplest way to do this is with prime number multiplication. This is because the only two dividends can be the prime numbers. Just for kicks, this is also the basis of a lot of modern cryptography.

You'll need 17 prime numbers (4 suits and 13 values). I'm choosing the 'first' 18, starting from 3. They are: 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, and 61.

I will arbitrarily use the last 4 to represent the suits. So for me, clubs is 47, spades is 53, then hearts then diamonds.

So for example, a 3 of clubs would have a value of 235 (5 * 47). A 3 of hearts would have a value of 295 (5 * 59). Every card is uniquely identifiable, and you can know the value and the suit.

You could probably get away with just prime numbers for the suits, but I know that if we use two primes, the uniqueness is guaranteed.

To randomly pick two cards, you'll actually shuffle the entire deck and just look at the first two elements of the array. This is because if you try to just pick two random numbers in the range [0, 51], (the [] means it's inclusive), there is the possibility that you pick the same number twice, which is impossible in a real deck.

Here's the code, which I tried to keep as simple as possible (i.e., trying to keep my Standard Library use to a minimum with sanity exceptions)

#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>

void create_deck(int deck[], int deckSize) {
  //          cl  sp  he  di
  int suits[]{47, 53, 59, 61};

  //           2  3  4   5   6   7   8   9  10   J   Q   K   A
  int values[]{3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43};

  int idx = 0;
  for (std::size_t s = 0; s < sizeof(suits) / sizeof(suits[0]);   s) {
    for (std::size_t v = 0;
         v < sizeof(values) / sizeof(values[0]) && idx < deckSize;   v) {
      deck[idx] = suits[s] * values[v];
        idx;
    }
  }
}

// Prints the name of the card and returns the value
int decode_card(int val) {
  //          cl  sp  he  di
  int suits[]{47, 53, 59, 61};
  std::string suitNames[]{"clubs", "spades", "hearts", "diamonds"};

  //           2  3  4   5   6   7   8   9  10   J   Q   K   A
  int values[]{3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43};
  std::string valueNames[]{"two",   "three", "four", "five", "six",
                           "seven", "eight", "nine", "ten",  "jack",
                           "queen", "king",  "ace"};
  int realValues[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};

  std::string suit;
  std::string value;
  for (std::size_t i = 0; i < sizeof(suits) / sizeof(suits[0]);   i) {
    if (val % suits[i] == 0) {
      suit = suitNames[i];
      val /= suits[i];
      for (std::size_t v = 0; v < sizeof(values) / sizeof(values[0]);   v) {
        if (values[v] == val) {
          value = valueNames[v];

          std::cout << value << " of " << suit << ".\n";
          return realValues[v];
        }
      }
    }
  }

  return -1;
}

int main() {
  const int deckSize = 52;
  int deck[deckSize];

  create_deck(deck, deckSize);
  std::shuffle(std::begin(deck), std::end(deck),
               std::mt19937(std::random_device{}()));

  int playerOneDraw = deck[0];
  int playerTwoDraw = deck[1];

  std::cout << "Player 1: ";
  int playerOneValue = decode_card(playerOneDraw);
  std::cout << "Player 2: ";
  int playerTwoValue = decode_card(playerTwoDraw);

  if (playerOneValue > playerTwoValue) {
    std::cout << "Player 1 wins.\n";
  } else if (playerOneValue == playerTwoValue) {
    std::cout << "It's a draw.\n";
  } else {
    std::cout << "Player Two wins.\n";
  }
}

One run's output:

Player 1: ace of spades.
Player 2: three of diamonds.
Player 1 wins.

Right away, I hope you see that is code a lot longer and a lot more complex than the other solutions that use classes. That makes this code harder to maintain in the long run.

This is exactly because the requirements you've given are making the task harder than it needs to be. I opted to not use global variables because you really shouldn't, but I also opted out of a namespace because I'm assuming if you don't want classes you probably don't want a namespace.

CodePudding user response:

Here is one possibility

#include <cstdint>
#include <array>
#include <algorithm>
#include <chrono>
#include <random>

enum Figure : uint8_t {
    ACE = 0,
    TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING
};

enum Suit : uint8_t {
    CLUBS = 0,
    HEARTS = 1,
    SPADE = 2,
    DIAMONDS = 3
};

struct Card {
    uint8_t figure : 4;
    uint8_t suite : 2;
};


using Deck = std::array<Card,52>;

int main() {
    Deck deck;
    unsigned k=0;
    for ( uint8_t f = ACE; f <= KING;   f ) {
        for ( uint8_t s = CLUBS; s <= DIAMONDS;   s ) {
            deck[k  ] = {f,s};
        }
    }

    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::shuffle (deck.begin(), deck.end(), std::default_random_engine(seed));
}

  • Related