Suggestions/improvements 在我简单的二十一点程序上

Suggestions/improvements on my simple Blackjack program

我想在我的 class 下学期取得领先,所以我制作了这个基本版本的 Blackjack 以开始了解 C 的基础知识,我希望你有任何可以帮助我获得的想法更好地理解 C 及其正常的编码实践。

C 中的很多东西对我来说都是新的,因为我有 JAVA 的背景,所以如果我在函数声明、指针的使用中犯了错误,或者我在想关于如何错误地处理问题以及应该以完全不同的方式做事,请告诉我。

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

正如一位评论者所提到的,最好在其他地方提出这个问题,但是我还是要提供一些意见。以上都是个人观点,我说的可能大家不同意。

顺便说一下,我完全忽略了 BlackJack 的规则并假设您的所有逻辑都是正确的。

首先,代码中没有任何注释。您提到这是针对 class,因此评论更为重要,因为一些穷人必须破译大量这些内容才能弄清楚他们在做什么。 (无论如何,注释代码很重要,我总是使用 "Will I work out what this does in a months time" 方法)

main() 里有那么多东西很不寻常。我个人会把它分解成一个不同的功能。然后,您还可以考虑将它放在一个单独的文件中,并带有一个用于函数声明的头文件。

handSize 被用作常量,您可以将其改为预处理器宏:#define HAND_SIZE 2

do-while 循环可以替换为 while(true) 循环,然后在完成后使用 'break' 关键字进行转义(当前设置 playGame = 1。这也有没有 if(playGame == 0) 条件的优点。此外,在 C 中,布尔变量为 1 表示真,0 表示假,因此 int playGame = 1; 更正常,然后do { } while(playGame)playGame = 0; 当你完成循环时。这种情况的特殊之处在于你实际上想要跳出,而不是 运行 循环结束。

出于安全原因,

gets() 在 C11 中被删除 ()

关于更全的节目要点。这些甚至更主观,而且大部分都是我解决问题的方法:

我个人会让 dealerCards 和 playerCards 足够大以容纳最大可能数量的牌(我认为在 blackjack 中是 5 张?)并将它们初始化为 0。目前您正在将当前牌的总和分配给dealerCards 数组的第一个元素,这意味着这些值不是实际的卡片。

与其使用单独的数组来跟踪纸牌是否为 A,不如为 {EMPTY_SLOT、ACE、TWO、...、JACK、QUEEN、KING} 进行枚举,然后存储在我的卡片数组中。 randCard 然后可以只是 return 枚举的一个成员,并且不带任何参数,并且 sumCards 只是遍历数组并对它求和。这也意味着您可以向他们显示用户的实际手数,而不仅仅是总数。

出于参考目的,我已将您的代码修改为我的操作方式。逻辑可能不完美(或完全相同的二十一点版本),但这是我要提交给 "program blackjack in C" 作业的那种东西。 N.B。这也可以用更多的评论来做,特别是在顶部的第一块解释一般结构是什么。

#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 Whosebug
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");
}