Article

# A very simple two-player Blackjack game in C

By , 2 Feb 2013
 Rate this:
Please Sign up or sign in to vote.

## Introduction

Here's a very simple game of blackjack, written in C. I was asked to write this as an assignment for an interview; but because I want all potentially useful code to be reused, I decided to publish it on CodeProject.

## Using the code

The code plays a basic two-player game of Blackjack. The AI is very simple, as the dealer will stop hitting at 17 unless the hand is a "soft hand".  The deck must be reshuffled at least every six rounds, as no pointer checks are performed to see if we ran out of cards. Unlike a real game of Blackjack, the player is not allowed to split cards.

Here's the header, which is probably the simplest Blackjack header one would've ever seen..

```#ifndef _BLACKJACK_H_
# define _BLACKJACK_H_

/* Total number of cards */
# define NUMBER_CARDS (NUMBER_SUITS * NUMBER_RANKS)

/* Number of rounds before shuffling. Should not be higher than 6. */
# define NUMBER_ROUNDS_SHUFFLE 6

/* Maximum of cards possible in a hand (4 aces, 4 twos, 3 threes) */
# define MAXIMUM_HAND 11

/* Suit */
typedef enum
{
/* Spade, heart, diamond and club */
SPADE = 0,
HEART,
DIAMOND,
CLUB,

/* Number of suits */
NUMBER_SUITS

} Suit;

/* Rank
*
* These ranks do not correspond to
* the actual value within the game.
*/
typedef enum
{
ACE = 0,
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
TEN,
JACK,
QUEEN,
KING,

/* Number of ranks */
NUMBER_RANKS

} Rank;

/* A card */
typedef struct
{
/* Card suit */
Suit suit;

/* Card rank */
Rank rank;

} Card;

/* Unsigned integer */
typedef unsigned int uint;

#endif /* _BLACKJACK_H_ */
```

As for the implementation itself, I've condensed the whole functionality into `main` and two helper functions..

```/* Standard C libraries */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* Local headers */
#include "blackjack.h"

/* Global variables */
static const char *suit_names[NUMBER_SUITS] = {"Spade", "Heart", "Diamond", "Club"};
static const char *rank_names[NUMBER_RANKS] = {"Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"};

/* Shuffle a deck of cards */
static inline void shuffle(Card *cards)
{
Card *aCard = cards;
const Card *cardEnd = cards + NUMBER_CARDS;

printf("Shuffling... ");

/* Shuffle the cards */
srand(time(NULL));
aCard = cards;
do
{
Card *swapPosition = cards + rand() % NUMBER_CARDS;
Card swap = *aCard;
*aCard = *swapPosition;
*swapPosition = swap;
}
while (++aCard != cardEnd);

printf("done\n");
}

/* Show a player or dealer's hand */
static inline void show_hand(Card **hand, Card **end, uint points)
{
Card **aCard = hand;

printf("Hand (%u) - %s of %s", points,
rank_names[(*aCard)->rank],
suit_names[(*aCard)->suit]);

while (++aCard != end)
{
printf(", %s of %s",
rank_names[(*aCard)->rank],
suit_names[(*aCard)->suit]);
}

printf(".\n");
}

int main(void)
{
Card cards[NUMBER_CARDS];
Card *aCard = cards;
uint roundCount = NUMBER_ROUNDS_SHUFFLE, gamesPlayed = 0, gamesWon = 0;
char buffer[80];

/* Load the cards */
uint i = 0;
do
{
uint j = 0;
do
{
aCard->suit = i;
aCard->rank = j;
++aCard;
}
while (++j < NUMBER_RANKS);
}
while (++i < NUMBER_SUITS);

/* Play */
do
{
uint aces = 0, playerPoints = 0, dealerPoints = 0;
Card *playerHand[MAXIMUM_HAND];
Card **aHandCard = playerHand;

/* Shuffle the cards after a specific number of rounds */
if (++roundCount >= NUMBER_ROUNDS_SHUFFLE)
{
shuffle(cards);
aCard = cards;
roundCount = 0;
}

/* Player plays */
do
{
/* Add the card's rank to player point */
if (aCard->rank == ACE)
{
playerPoints += 11;
++aces;
}
else if (aCard->rank < JACK)
playerPoints += aCard->rank + 1;
else
playerPoints += 10;

/* Print the new card */
printf("New Card... %s of %s\n", rank_names[aCard->rank],
suit_names[aCard->suit]);

*aHandCard = aCard;
++aCard;
assert(aCard != cards + NUMBER_CARDS);

/* Let the second card be dealt */
if (aHandCard == playerHand)
{
++aHandCard;
*buffer = 'h';
continue;
}

++aHandCard;

/* Convert Aces to 1 */
while (playerPoints > 21 && aces > 0)
{
playerPoints -= 10;
--aces;
}

/* Print the hand */
show_hand(playerHand, aHandCard, playerPoints);

/* On a bust, dealer doesn't need to play.
* This single "goto" simplifies the code.
*/
if (playerPoints > 21)
{
printf("Bust!\n");
goto done;
}

/* On Blackjack, let the dealer play */
if (playerPoints == 21)
{
printf("Blackjack!\n");
break;
}

/* Hit or stand? */
do
{
printf("Hit or stand? (h/s) : ");
scanf("%s", buffer);
}
while (*buffer != 'h' && *buffer != 'H' && *buffer != 's' && *buffer != 'S');
}
while (*buffer == 'h' || *buffer == 'H');

/* Dealer plays */
aHandCard = playerHand;
aces = 0;
printf("Dealer plays...\n");
do
{
/* Add the card's rank to dealer point */
if (aCard->rank == ACE)
{
dealerPoints += 11;
++aces;
}
else if (aCard->rank < JACK)
dealerPoints += aCard->rank + 1;
else
dealerPoints += 10;

/* Print the new card */
printf("New Card... %s of %s\n", rank_names[aCard->rank],
suit_names[aCard->suit]);

*aHandCard = aCard;
++aCard;
assert(aCard != cards + NUMBER_CARDS);

/* Let the second card be dealt */
if (aHandCard == playerHand)
{
++aHandCard;
continue;
}

++aHandCard;

/* Convert Aces to 1 */
while (dealerPoints > 21 && aces > 0)
{
dealerPoints -= 10;
--aces;
}

/* Print the hand */
show_hand(playerHand, aHandCard, dealerPoints);

if (dealerPoints > 21)
{
printf("Bust!\n");
break;
}

/* Blackjack */
if (dealerPoints == 21)
{
printf("Blackjack!\n");
break;
}

printf("Hit or stand? (h/s) : ");

/* Dealer must hit on soft 17 */
if (dealerPoints < 17 || (dealerPoints == 17 && aces))
{
printf("hit\n");
continue;
}

printf("stand\n");
break;
}
while (1);
done:

/* Keep track of win percentage for the player. */
if (playerPoints <= 21 && (playerPoints > dealerPoints || dealerPoints > 21))
{
++gamesWon;
printf("Player wins!\n");
}
else if (playerPoints <= 21 && playerPoints == dealerPoints)
printf("Tie!\n");
else
printf("Dealer wins!\n");

++gamesPlayed;

printf("Win percentage - %u%%\n", (gamesWon * 100) / gamesPlayed);

/* Ask to play again. */
do
{
printf("Play again? (y/n) : ");
scanf("%s", buffer);
}
while (*buffer != 'n' && *buffer != 'N' && *buffer != 'y' && *buffer != 'Y');
}
while (*buffer == 'y' || *buffer == 'Y');

return 0;
}   ```

## Points of Interest

One point of interest here is the length of the main function itself. If the game of Blackjack was slightly more complex, I would've considered refactoring the "player plays" and "dealer plays" parts in two separate functions.

There's also one `goto` statement in there, which I would humorously hope is not the reason why I didn't get the position . Other than that, I naturally recommend people to bring me feedback as to tell me what would've been a better way to implement this, while keeping it short, simple and not changing the functionality.

## History

01-02-2013: Initial release to CodeProject.com.

## License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

## About the Author

Software Developer
United States
No Biography provided

## Comments and Discussions

 First Prev Next
 improvements Member 10451563 7-Dec-13 8:05
 Last Visit: 31-Dec-99 18:00     Last Update: 20-Apr-14 23:33 Refresh 1

General    News    Suggestion    Question    Bug    Answer    Joke    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140415.2 | Last Updated 2 Feb 2013
Article Copyright 2013 by Remi Dufour
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid