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

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

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


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

/* 定数 */
#define IMAX  52/* 1 組 52 枚のカード */
#define NDECK 1 /* 実際のカジノでは、6 デックを 1 スタックとすることが多い
                   (ブラックジャックの場合) */
#define NMAX  21/* 手札の最大枚数 */
#define CMAX  4 /* カードを印 1 文字と数字 1, 2 文字と '\0' で表現する */

/* グローバル変数 */
/* なし */

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

/* カードを混ぜる */
void shuffle(char **stack) {
  int  i, n;
  char deck[IMAX][CMAX] = {/* 1 組 52 枚のカード */
    "S01", "S02", "S03", "S04", "S05", "S06", "S07", "S08", "S09", "S10",
    "S11", "S12", "S13", /* spade */
    "H01", "H02", "H03", "H04", "H05", "H06", "H07", "H08", "H09", "H10",
    "H11", "H12", "H13", /* heart */
    "D01", "D02", "D03", "D04", "D05", "D06", "D07", "D08", "D09", "D10",
    "D11", "D12", "D13", /* diamond */
    "C01", "C02", "C03", "C04", "C05", "C06", "C07", "C08", "C09", "C10",
    "C11", "C12", "C13"  /* club */
  };
  char deckn[IMAX][CMAX];/* NDECK デックのカード */

  for (n = 0; n < NDECK; n++) {
    for (i = 0; i < IMAX; i++) {
      strcpy(deckn[n * NDECK + i], deck[i]);
    }
  }

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

  /* deckn から 1 枚ずつ stack に移動する */
  for (i = 0; i < IMAX * NDECK; i++) {
    int index;/* カード番号 */

    /* 未使用カードを探す */
    do {
      /* rand は 0 以上 RAND_MAX 以下の整数を返す */
      index = (int)((float)IMAX * NDECK * rand() / (RAND_MAX + 1.0));
    } while (deckn[index][0] == '\0');

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

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

/* 合計点数を計算する */
int calc(int nHands, char Hands[NMAX][CMAX]) {
  int  n;
  int  point;        /* 合計点数 */
  int  na;           /* A の枚数 */
  int  numbers[NMAX];/* カードの数字 */
  char tmp[3];

  /* 数字を取出す */
  for (n = 0; n < nHands; n++) {
    int i;

    /* 「アルファベットと数字」の数字部分を取出す */
    for (i = 0; i < 3; i++) tmp[i] = Hands[n][i + 1];
    numbers[n] = atoi(tmp);
  }

  point = na = 0;
  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[NMAX][CMAX], int PlayerPoint,
             int nDealerHands, char DealerHands[NMAX][CMAX], 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,
            int *nPlayerHands, char PlayerHands[NMAX][CMAX], int *PlayerPoint,
            int  nDealerHands, char DealerHands[NMAX][CMAX], int  DealerPoint) {
  while (1) {
    int c;/* getchar の戻り値は int */

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

    /* プレーヤーの処理を行う */
    printf("  Draw(D, d) or Stand(S, s) or Quit(Q, q)? : ");
    c = getchar();
    /* バッファの最後に移動(2 文字目以降や改行文字を無視) */
    fseek(stdin, 0, SEEK_END);/* rewind(stdin) は、コンパイラによっては先頭に戻る */

    if        ((c == 'D') || (c == 'd')) {/* カードを引く */
      printf("  Draw\n");
      strcpy(PlayerHands[(*nPlayerHands)++], stack[(*next)++]);
      *PlayerPoint = calc(*nPlayerHands, PlayerHands);
      if (*PlayerPoint == 0) break;
    } else if ((c == 'S') || (c == 's')) {/* カードを引かない */
      printf("  Stand\n");
      break;
    } else if ((c == 'Q') || (c == 'q')) {/* 終了する */
      exit(0);/* 正常終了 */
    } else  {
      printf("Input Error!\n");
    }
  }
}

/* ディーラーの処理を行う */
void dealer(int *next, char **stack,
            int *nDealerHands, char DealerHands[NMAX][CMAX], int *DealerPoint) {
  while (1) {
    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[NMAX][CMAX],/* プレーヤーの手札 */
       DealerHands[NMAX][CMAX];/* ディーラーの手札 */
  char **stack;                /* カードの山 */

  /* 動的領域を確保する */
  stack = (char **)malloc(sizeof(char *) * IMAX * NDECK);
  if (stack == NULL) {
    printf("Memory Allocation Error!\n");
    exit(1);/* 異常終了 */
  }
  for (n = 0; n < IMAX * NDECK; n++) {
    stack[n] = (char *)malloc(sizeof(char) * CMAX);
    if (stack[n] == NULL) {
      printf("Memory Allocation Error!\n");
      exit(1);/* 異常終了 */
    }
  }

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

  nround = next = 0;
  while (IMAX * NDECK - 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);

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

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

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

  /* 動的領域を解放する */
  for (n = 0; n < IMAX * NDECK; n++) free(stack[n]);
  free(stack);

  exit(0);/* 正常終了 */
}

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