-2

I am trying to get a head start on my class next semester so I made this basic version of Blackjack to start understanding the basics of C and I would love any thoughts you have that could help me gain a better understanding of C and its normal coding practices.

A lot of the things in C are new to me as I am coming from a background in JAVA so if I made a mistake in function declaration, in my use of pointers, or if I was thinking about how to approach the problem incorrectly and should have done things a completely different way please let me know.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

const int handSize = 2;

int randCard(int *isAce);

int sumCards(int cards[], int *hasAce[2]);

int main() {
    srand(time(NULL));

    int playGame = 0;

    int dealerIsAce[handSize];
    int *dealerAcePointers[handSize];
    int playerIsAce[handSize];
    int *playerAcePointers[handSize];

    for (int i = 0; i < handSize; i++) {
        dealerIsAce[i] = 0;
        playerIsAce[i] = 0;

        dealerAcePointers[i] = &dealerIsAce[0];
        playerAcePointers[i] = &playerIsAce[0];
    }

    int dealerCards[] = {randCard(dealerAcePointers[0]), randCard(dealerAcePointers[1])};
    int playerCards[] = {randCard(playerAcePointers[0]), randCard(playerAcePointers[1])};

    int dealerSum;
    int playerSum;
    do {
        printf("The dealer:\n? + %d\n\n", dealerCards[1]);

        dealerSum = sumCards(dealerCards, dealerAcePointers);
        if (dealerSum > 17) {
            dealerCards[0] = dealerSum;
            dealerCards[1] = randCard(dealerAcePointers[1]);
        }

        playerSum = sumCards(playerCards, playerAcePointers);
        printf("You:\n%d + %d = %d", playerCards[0], playerCards[1], playerSum);
        if (playerSum > 21) {
            printf(" BUSTED");
            playGame = 1;
        } else {
            printf("\nWould you like to \"hit\" or \"stand\"?\n");
        }

        if (playGame == 0) {
            char stream[10];
            if (strcmp(gets(stream), "hit") == 0) {
                playerCards[0] = playerSum;
                playerCards[1] = randCard(playerAcePointers[1]);
            } else {
                playGame = 1;
            }
        }
    } while (playGame == 0);

    if (playerSum > 21) {
        if (dealerSum > 21) {
            printf("\nTie!");
        } else {
            printf("\nDealer Wins!");
        }
    } else {
        if (playerSum > dealerSum) {
            printf("\nPlayer Wins!");
        } else if (playerSum == dealerSum) {
            printf("\nTie!");
        } else if (playerSum < dealerSum) {
            printf("\nDealer Wins!");
        }
    }
    return 0;
}

int randCard(int *isAce) {
    int card = rand() % 13 + 2;
    if (card > 11) {
        card = 10;
    } else if (card == 11) {
        *isAce = 1;
    }
    return card;
}

int sumCards(int cards[], int *hasAce[2]) {
    int sum = cards[0] + cards[1];
    if (sum > 21 && *hasAce[0] == 1) {
        sum -= 10;
        *hasAce[0] = *hasAce[1];
        if (*hasAce[1] == 1) {
            *hasAce = 0;
        }
    }
    return sum;
}
  • 4
    Hello. It's better to try other communities for this type of questions like [codereview](codereview.stackexchange.com/). – Mr Alihoseiny Jan 01 '20 at 07:48

1 Answers1

0

As mentioned by a commenter, this could be better asked elsewhere, however I'm going to offer some opinions anyway. These are all opinions, and everyone will probably disagree with something I've said.

Incidentally, I'm entirely ignoring the rules of BlackJack and assuming that all your logic is correct.

First and foremost, there aren't any comments in the code. You mention this being for a class, therefore commenting is even more important as some poor person has to decipher a load of these to work out what they do. (Commenting code is important anyway incidentally, I always use the "Will I work out what this does in a months time" approach)

Having that much stuff in main() is unusual. I would personally break it out into a different function. You could then also consider putting it in a separate file, with a header file for the function declarations.

handSize is being used as a constant, you could probably make this a preprocessor macro instead: #define HAND_SIZE 2

The do-while loop could be replaced with a while(true) loop, then using the 'break' keyword to escape when you're done (Where you are currently setting playGame = 1. This also has the advantage of not having the if(playGame == 0) conditional. Also, in C, a boolean variable is 1 for true and 0 for false, so it would be more normal to have int playGame = 1; and then do { } while(playGame) and playGame = 0; when you're done with the loop. This case is a special in that you actually want to break out, rather than run to the end of the loop.

gets() was removed in C11 for security reasons (Implicit declaration of 'gets')

On a more whole-program points. These are even more subjective, and are mostly just how I would have solved the problem:

I personally would make dealerCards and playerCards large enough to hold the maximum possible number of cards (which I think is 5 in blackjack?) and initialise them to 0. Currently you are assigning the sum of the current cards to the first element of the dealerCards array, meaning that the values are not actual cards.

Rather than use separate arrays to track whether or not cards are aces, I would have made an enum for {EMPTY_SLOT, ACE, TWO, ..., JACK, QUEEN, KING} and then stored that in my Cards arrays. randCard can then just return a member of the enum, and take no arguments, and sumCards just iterates across the array and sums it. This also means that you can display the user's actual hand to them, rather than just the total.

For reference purposes, I've modified your code to how I would do it. The logic may not be perfect (or the exact same version of blackjack) but this is the sort of thing I would submit for a "program blackjack in C" homework. N.B. This could also do with a few more comments, particularly a block one at the top explaining what the general structure is.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define HAND_SIZE 5

typedef enum
{
  // Technically I didn't need to set the values, as they are the defaults but
  // it's good to be explicit when you're using the order for something.
  EMPTY = 0,
  ACE = 1,
  TWO = 2,
  THREE,
  FOUR,
  FIVE,
  SIX,
  SEVEN,
  EIGHT,
  NINE,
  TEN,
  JACK,
  QUEEN,
  KING
} card_t; // Types you typedef generally end _t as a convention.


// These should be in a separate header, but I'm keeping this in 1 file for StackOverflow
card_t randCard();
int sumCards(card_t cards[]);
void play();

int main()
{
    srand(time(NULL));

    play();

    return 0;
}

card_t randCard()
{
    int card = rand() % 13 + 1;
    return (card_t)card;
}

int sumCards(card_t cards[])
{
  int total = 0;
  int num_aces = 0;

  for (int i = 0; i < HAND_SIZE; i++) {
    switch(cards[i]) {
      case ACE:
        num_aces++;
        total += 11;
        break;
      case JACK:
      case QUEEN:
      case KING:
        total += 10;
        break;
      default:
        total += (int)cards[i]; // Relying here on the fact that the cards are in the correct order.
        break;
    }
  }

  while (num_aces > 0 && total > 10) {
    total -= 10;
    num_aces--;
  }

  return total;
}

void play()
{
  card_t playerCards[HAND_SIZE];
  card_t dealerCards[HAND_SIZE];
  card_t dealerKnown[HAND_SIZE]; // Equivalent to dealer cards, but with first 2 elements blank

  for (int i = 0; i < HAND_SIZE; i++) {
    playerCards[i] = EMPTY;
    dealerCards[i] = EMPTY;
    dealerKnown[i] = EMPTY;
  }

  playerCards[0] = randCard();
  playerCards[1] = randCard();
  dealerCards[0] = randCard();
  dealerCards[1] = randCard();

  int num_cards = 2;

  while(num_cards <= HAND_SIZE) {
    printf("The dealer: ? + %d\n\n", sumCards(dealerKnown));

    if (sumCards(dealerCards) > 17) {
      dealerCards[num_cards] = randCard();
    }

    int playerSum = sumCards(playerCards);
    printf("Your total: %d\n", playerSum);
    if (playerSum > 21) {
      printf("BUSTED\n");
      break;
    } else {
      printf("Would you like to \"hit\" or \"stand\"?\n");
    }

    char stream[10];
    if (strcmp(fgets(stream, sizeof(stream), stdin), "hit\n") != 0) {
      break;
    }

    playerCards[num_cards] = randCard();

    num_cards++;
  }

  printf("\n"); // Printing the new line separately rather than at the beginning of all the strings below

  int playerSum = sumCards(playerCards);
  int dealerSum = sumCards(dealerCards);

  if (playerSum > 21) {
    if (dealerSum > 21) {
      printf("Tie!");
    } else {
      printf("Dealer Wins!");
    }
  } else {
    if (playerSum > dealerSum) {
      printf("Player Wins!");
    } else if (playerSum == dealerSum) {
      printf("Tie!");
    } else if (playerSum < dealerSum) {
      printf("Dealer Wins!");
    }
  }

  printf("\n");
}
R Baish
  • 57
  • 5