Search code examples
c++data-representation

Representing data types that fit in an integer


There seem to be 2 ways to represent a card in C++.

The obvious way is like:

const int numCards = 52;
const int numRanks = 13;
const int numSuits = 4;

enum Suit {
    HEARTS  = 1;
    DIAMOND = 2;
    SPADES  = 3;
    CLUBS   = 4;
}

card Class {
    private:
        const Suit suit;
        const int rank;

    public:
        /// Constructor
        Card(int rank, Suit suit)

        /// Get rank between 1 and 13
        int getRank();

        /// Get suit
        Suit getSuit();

        /// Get string representation
        std::string toString();
};

and there is another way in which the whole card is represented by a single byte.

namespace Cards {
    typedef byte Card;

    /// Constructor
    Card getCard(int rank, Suit suit); // return (rank - 1) + numRanks * (suit - 1);

    /// Validity check
    boolean isValid(Card);

    /// Get a rank between 1 and 13
    int getRank(Card); // return 1 + (card % numRanks);

    /// Get suit
    Suit getSuit(Card); // return 1 + (card // numSuits)

    /// Get string representation
    std::string toString(Card);
};
typedef Cards::Card Card;

The first one seems more obvious and the advantage is that the card has it's own type. That makes it safer, because it can't be messed up with another type. On the other hand, the second representation is memory efficient and makes some operations relatively easy. For example, creating a deck can be done by

void initializeDeck(Card[] deck) {
    // Pre: sizeof(deck) >= 52!!!

    // No need to iterate over both rank and suit!!!
    for(Card card = 0; card < numCards; card++) {
        deck[card] = card;
    }
}

Should I still use the first way or is there a way to get the advantages of both?


Solution

  • Another option would be to use a bitfield.

    struct Card {
        unsigned char suit:2;
        unsigned char rank:6;
    };
    

    You can then access the components like any other member variable.

    Card card;
    card.suit = HEARTS;
    card.rank = 5;
    

    You could also add additional methods Card struct to add things like string serialization.

    As a quick note I would number your suits from 0-3 so they can fit in 2 bits rather than 3.