ドロー・ポーカーの C 言語プログラム

ドロー・ポーカーの C 言語プログラム

以下は、C 言語によるドロー・ポーカーのプログラムの一例です。


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

/* 定数 */
#define IMAX  52/* 1 組 52 枚のカード */
#define NDECK 1 /* 実際のカジノでは、6 デックを 1 スタックとすることが多い
                   (ブラックジャックの場合) */
#define M     5 /* 手札の枚数 */
#define N     5 /* 交換可能な枚数 */

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

/* 関数プロトタイプ宣言 */
void shuffle(int *stack);
void calc(int index, int *s, int *n);
void display(int player[M]);
void change(int player[M], int *stack, int *next);
int check(int player[M]);

/* カードを混ぜる */
void shuffle(int *stack) {
  int i;
  int *flag;/* フラグ(0:未使用 1: 使用済) */

  /* 動的領域を確保する */
  flag = (int *)malloc(sizeof(int) * IMAX * NDECK);
  if (flag == NULL) {
    printf("Memory Allocation Error!\n");
    exit(1);/* 異常終了 */
  }

  /* 配列を初期化する */
  for (i = 0; i < IMAX * NDECK; i++) flag[i] = 0;

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

  /* カードを混ぜる */
  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 (flag[index] != 0);

    /* カードを設定する */
    stack[i] = index;

    /* フラグを使用済にする */
    flag[index] = 1;
  }

  /* 動的領域を解放する */
  free(flag);
}

/* 番号をカードに換算する */
void calc(int index, int *s, int *n) {
  *s = (int)((index % IMAX) / 13);
  *n = (index % IMAX) % 13;
}

/* カードを画面に表示する */
void display(int player[M]) {
  int  i;
  char *suits[] = {/* カードの印 */
    "S",/* spade */
    "H",/* heart */
    "D",/* diamond */
    "C" /* club */
  };

  for (i = 0; i < M; i++) {
    int s, n;/* カードの印と数字 */

    /* 番号をカードに換算する */
    calc(player[i], &s, &n);

    /* カードを画面に表示する */
    printf("%s%02d", suits[s], n + 1);
    if (i != M - 1) printf(" ");
  }
  printf("\n");
}

/* カードを交換する */
void change(int player[M], int *stack, int *next) {
  int i;
  int nflag;  /* 真の flag の数 */
  int flag[M];/* カードの交換フラグ */

  /* 配列を初期化する */
  nflag = 0;
  for (i = 0; i < M; i++) flag[i] = 0;

  /* 交換するカードを決定する */
  while (1) {
    char str[2];/* 入力文字列 */

    printf("Please select the card(s) you want to change (1 - 5). ");
    printf("To finish, input 0.\n");
    str[0] = (char)getchar();/* getchar の戻り値は int */
    /* バッファの最後に移動(2 文字目以降や改行文字を無視) */
    fseek(stdin, 0, SEEK_END);/* rewind(stdin) は、コンパイラによっては先頭に戻る */

    if (('0' <= str[0]) && (str[0] <= '5')) {/* 文字コードで比較 */
      str[1] = '\0';
      i      = atoi(str);
      if        ((1 <= i) && (i <= 5)) {
        if (flag[i - 1]) continue;
        else             flag[i - 1] = 1;

        if (++nflag == N) break;
      } else if  (i == 0) {
        break;
      }
    } else {
      printf("Input Error!\n");
    }
  } 

  /* カードを交換する */
  for (i = 0; i < M; i++) if (flag[i]) player[i] = stack[++(*next)];;
}

/* 役を確認する */
int check(int player[M]) {
  int i;
  int npair; /* ペアの数 */
  int flag_f;/* フラッシュの確認フラグ */
  int flag_s;/* ストレートの確認フラグ */
  int flag_3;/* スリーカードの確認フラグ */
  int s[4];  /* 印毎の枚数 */
  int n[13]; /* 数字毎の枚数 */

  /* 配列を初期化する */
  for (i = 0; i <  4; i++) s[i] = 0;
  for (i = 0; i < 13; i++) n[i] = 0;

  for (i = 0; i < M; i++) {
    int s0, n0;/* カードの印と数字 */

    /* 番号をカードに換算する */
    calc(player[i], &s0, &n0);

    /* 換算したカードの印と数字の枚数を追加する */
    s[s0]++;
    n[n0]++;
  }

  /* フラッシュ系 */
  flag_f = 0;
  for (i = 0; i < 4; i++) {
    if (s[i] == M) {
      flag_f = 1;
      break;
    }
  }

  /* ストレート系 */
  for (i = 0; i < 10; i++) {/* ストレートの低位の数字は 1 から 10 まで */
    int j;

    flag_s = 1;

    for (j = 0; j < M; j++) {
      if (n[(i + j) % 13] != 1) {/* 13 は 1 と連なる */
        flag_s = 0;
        break;
      }
    }

    if (flag_s) {
      if (flag_f) {
        if (i == 9) {
          return(9);/* ロイヤル・ストレート・フラッシュ */
        } else {
          return(8);/* ストレート・フラッシュ */
        }
      } else {
        return(4);/* ストレート */
      }
      break;
    }
  }
  if (flag_f) return(5);/* フラッシュ */

  /* ペア系 */
  flag_3 = 0;
  npair  = 0;
  for (i = 0; i < 13; i++) {
    if      (n[i] == 4) return(7);/* フォーカード */
    else if (n[i] == 3) flag_3 = 1;
    else if (n[i] == 2) npair++;
  }
  if (flag_3) {
    if (npair == 1) return(6);/* フルハウス */
    else            return(3);/* スリーカード */
  } else {
    if      (npair == 2) return(2);/* ツーペア */
    else if (npair == 1) return(1);/* ワンペア */
  }
  return(0);/* ノーペア */
}

main () {
  int  *next;      /* 次に配るカード */
  int  *stack;     /* カードの山 */
  int  player[M];  /* プレーヤーの手札 */
  char *hands[] = {/* 役の種類 */
    "No Pair",
    "One Pair",
    "Two Pair",
    "Three of a Kind",
    "Straight",
    "Flush",
    "Full House",
    "Four of a Kind",
    "Straight Flush",
    "Royal Straight Flush"
  };

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

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

  /* カードを配る */
  for (*next = 0; *next < M; (*next)++) player[*next] = stack[*next];

  /* カードを画面に表示する */
  display(player);

  /* カードを交換する */
  change(player, stack, next);

  /* カードを画面に表示する */
  display(player);

  /* 役を確認する */
  printf("%s\n", hands[check(player)]);

  /* 動的領域を解放する */
  free(stack);

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

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