ブラックジャックの C 言語プログラム

ブラックジャックの C 言語プログラム

以下は、C 言語によるブラックジャックのプログラムの一例です。


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

/* 関数プロトタイプ宣言 */
void shuffle(char stack[52][4]);
int calc(int nHands, char Hands[21][4]);
void display(int flag,
             int nPlayerHands, char PlayerHands[21][4], int PlayerPoint,
             int nDealerHands, char DealerHands[21][4], int DealerPoint);
void player(int *next, char stack[52][4], 
            int *nPlayerHands, char PlayerHands[21][4], int *PlayerPoint,
            int  nDealerHands, char DealerHands[21][4], int  DealerPoint);
void dealer(int *next, char stack[52][4], int PlayerPoint,
            int *nDealerHands, char DealerHands[21][4], int *DealerPoint);

/* カードを混ぜる */
void shuffle(char stack[52][4]) {
  int i, imax;
  int index;          /* カード番号 */
  char deck[52][4] = {/* 1 組 52 枚のカード */
    "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10",
    "S11", "S12", "S13",
    "H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10",
    "H11", "H12", "H13",
    "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10",
    "D11", "D12", "D13",
    "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10",
    "C11", "C12", "C13"
  };

  /* time 関数により擬似乱数を初期化する */
  srand((unsigned)time(NULL));

  imax = 52;/* 1 組 52 枚のカード */

  /* deck から 1 枚ずつ stack に移動する */
  for (i = 0; i < imax; i++) {
    /* 未使用カードを探す */
    do {
      index = (int)((float)imax * rand() / (RAND_MAX + 1.0));
    } while (deck[index][0] == '\0');

    /* カードを設定する */
    strcpy(stack[i], deck[index]);

    /* 使用済にする */
    deck[index][0] = '\0';
  }
};

/* 合計点数を計算する */
int calc(int nHands, char Hands[21][4]) {
  int  i, n;
  int  point;      /* 合計点数 */
  int  na;         /* A の枚数 */
  int  numbers[21];
  char tmp[3];

  point = na = 0;

  /* 数字を取出す */
  for (n = 0; n < nHands; n++) {
    for (i = 0; i < 3; i++) tmp[i] = Hands[n][i + 1];
    numbers[n] = atoi(tmp);
  }

  for (n = 0; n < nHands; n++) {
    if (numbers[n] <= 10) {
      point += numbers[n];

      if (numbers[n] == 1) na++;/* A の枚数を数える */
    } else {/* 絵札は 10 点 */
      point += 10;
    }
  }

  if        (point <= 11) {/* A は 1 点としても 11 点としてもよい */
    if (na) point += 10;
  } else if (point >= 22) {/* 合計点数が 21 点を超えていたら 0 点にする */
    point = 0;
  } 

  return(point);
}

/* カードを画面に表示する */
void display(int flag,
             int nPlayerHands, char PlayerHands[21][4], int PlayerPoint,
             int nDealerHands, char DealerHands[21][4], int DealerPoint) {
  int n;

  printf("PlayerHands : ");
  for (n = 0; n < nPlayerHands; n++) {
    printf("%s", PlayerHands[n]);
    if (n != nPlayerHands - 1) printf(", ");
  }
  printf(" [%d]\n", PlayerPoint);

  if        (flag == 0) {
    printf("DealerHands : %s, ?\n", DealerHands[0]);
  } else if (flag == 1) {
    printf("DealerHands : ");
    for (n = 0; n < nDealerHands; n++) {
      printf("%s", DealerHands[n]);
      if (n != nDealerHands - 1) printf(", ");
    }
    printf(" [%d]\n", DealerPoint);

    if        (PlayerPoint == 0) {
      printf("Player Busted.\n");
    } else if (DealerPoint == 0) {
      printf("Dealer Busted.\n");
    } else if (PlayerPoint >  DealerPoint) {
      printf("Player Won.\n");
    } else if (PlayerPoint <  DealerPoint) {
      printf("Dealer Won.\n");
    } else if (PlayerPoint == DealerPoint) {
      printf("Push.\n");
    }
  }
}

/* プレーヤーの処理を行う */
void player(int *next, char stack[52][4], 
            int *nPlayerHands, char PlayerHands[21][4], int *PlayerPoint,
            int  nDealerHands, char DealerHands[21][4], int  DealerPoint) {
  int i;

  while (1) {
    /* カードを画面に表示する */
    display(0, *nPlayerHands, PlayerHands, *PlayerPoint,
                nDealerHands, DealerHands,  DealerPoint);

    /* プレーヤーの処理を行う */
    printf("  Draw(1) or Stand(2) or Quit(0)? : ");
    scanf("%d", &i);
    if        (i == 1) {/* カードを引く */
      printf("  Draw\n");
      strcpy(PlayerHands[(*nPlayerHands)++], stack[(*next)++]);
      *PlayerPoint = calc(*nPlayerHands, PlayerHands);
      if (*PlayerPoint == 0) break;
    } else if (i == 2) {/* カードを引かない */
      printf("  Stand\n");
      break;
    } else if (i == 0) {/* 終了する */
      exit(0);
    } else  {
      printf("Input Error!\n");
    }
  }
}

/* ディーラーの処理を行う */
void dealer(int *next, char stack[52][4], int PlayerPoint,
            int *nDealerHands, char DealerHands[21][4], int *DealerPoint) {
  while (PlayerPoint) {
    if (*DealerPoint >= 17) break;/* 16 でドロー(ヒット)/17 でスタンド(ステイ) */

    strcpy(DealerHands[(*nDealerHands)++], stack[(*next)++]);
    *DealerPoint = calc(*nDealerHands, DealerHands);
    if (*DealerPoint == 0) break;
  }
}

main () {
  int  n;
  int  nround;            /* ラウンド数 */
  int  next;              /* 次に配るカード */
  int  nPlayerHands,      /* プレーヤーの手札の枚数 */
       nDealerHands;      /* ディーラーの手札の枚数 */
  int  PlayerPoint,       /* プレーヤーの合計点数 */
       DealerPoint;       /* ディーラーの合計点数 */
  char PlayerHands[21][4],/* プレーヤーの手札 */
       DealerHands[21][4];/* ディーラーの手札 */
  char stack[52][4];      /* 1 組 52 枚のカード */

  /* カードを混ぜる */
  shuffle(stack);

  nround = next = 0;
  while (52 - next > 10) {
    printf("--- Round %d ---\n", ++nround);

    /* カードを配る */
    nPlayerHands = nDealerHands = 2;
    for (n = 0; n < nPlayerHands; n++) strcpy(PlayerHands[n], stack[next++]);
    for (n = 0; n < nDealerHands; n++) strcpy(DealerHands[n], stack[next++]);

    /* 合計点数を計算する */
    PlayerPoint = calc(nPlayerHands, PlayerHands);
    DealerPoint = calc(nDealerHands, DealerHands);

    /* プレーヤーの処理を行う */
    player(&next, stack, &nPlayerHands, PlayerHands, &PlayerPoint,
                          nDealerHands, DealerHands,  DealerPoint);

    /* ディーラーの処理を行う */
    dealer(&next, stack, PlayerPoint, &nDealerHands, DealerHands, &DealerPoint);

    /* カードを画面に表示する */
    display(1, nPlayerHands, PlayerHands, PlayerPoint,
               nDealerHands, DealerHands, DealerPoint);
  }

  printf("--- Dealer doesn't have enough cards to continue. ---\n");
}

各関数について、以下に説明します。