ブラックジャック


初めに

cでゲームを作りました。第1弾としてブラックジャックです。
コンピュータの担当するディーラ役はプチAIとなっています。
汎用性はなくただプラクジャックの親役用のコードです。

/******************************************************************************/
/* 21ゲーム(ブラックジャック)                                               */
/* 1.ディーラーはコンピュータ                                               */
/* 2.手持ち金額が0になる又は場の残り枚数が少なくなるまでプレーできる       */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/

ゲーム

  1. カード作り
    // 初期化
    set_base_card( );
    kiru_card( );

/******************************************************************************/
/* void set_base_card(void)                                                   */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 場のカードをセットする(プログラム中で1回やれば良い)               */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void set_base_card(void)
{
    int i,j,k;
    int card_mai = 0;
    char now_kigo[MOJI_RYOIKI_MAX];

    for( i = 0; i < SET_MAX; i++ ) {
        for( j = 0; j < KIGO_MAX; j++ ) {
            switch( j ) {
                case 0:
                    memcpy( now_kigo, "S", CARD_KIGO_SIZE );
                    break;
                case 1:
                    memcpy( now_kigo, "M", CARD_KIGO_SIZE );
                    break;
                case 2:
                    memcpy( now_kigo, "H", CARD_KIGO_SIZE );
                    break;
                case 3:
                    memcpy( now_kigo, "D", CARD_KIGO_SIZE );
                    break;
                default:
                    break;
            }
            for( k = 0; k < SUJI_MAX; k++ ) {
                memcpy( ba[card_mai].kigo, now_kigo, CARD_KIGO_SIZE );
                switch( k ) {
                    case 0:
                        memcpy( ba[card_mai].nomber, "A", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 1;
                        break;
                    case 1:
                        memcpy( ba[card_mai].nomber, "2", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 2;
                        break;
                    case 2:
                        memcpy( ba[card_mai].nomber, "3", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 3;
                        break;
                    case 3:
                        memcpy( ba[card_mai].nomber, "4", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 4;
                        break;
                    case 4:
                        memcpy( ba[card_mai].nomber, "5", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 5;
                        break;
                    case 5:
                        memcpy( ba[card_mai].nomber, "6", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 6;
                        break;
                    case 6:
                        memcpy( ba[card_mai].nomber, "7", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 7;
                        break;
                    case 7:
                        memcpy( ba[card_mai].nomber, "8", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 8;
                        break;
                    case 8:
                        memcpy( ba[card_mai].nomber, "9", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 9;
                        break;
                    case 9:
                        memcpy( ba[card_mai].nomber, "T", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 10:
                        memcpy( ba[card_mai].nomber, "J", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 11:
                        memcpy( ba[card_mai].nomber, "Q", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 12:
                        memcpy( ba[card_mai].nomber, "K", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    default:
                        break;
                }
                card_mai++;
            }
        }
    }
    return;
}

  1. カードをシャッフルする
/******************************************************************************/
/* void kiru_card(void)                                                       */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 場のカードをシャッフルする                                           */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void kiru_card( void )
{
    int i, j, k;
    struct card work;

    srand((unsigned)time(NULL));
    for( i = 0; i < (( rand() % KIRU_KAI_MAX ) + KIRU_KAI_MIN); i++ ) {
        for( j = 0; j < CARD_MAX_MAISU; j++ ) {
            k = rand() % CARD_MAX_MAISU;
            if( k == CARD_MAX_MAISU ) k--;
            memcpy( (void *)&work, (void *)&ba[j], sizeof( struct card ));
            memcpy( (void *)&ba[j], (void *)&ba[k], sizeof( struct card ));
            memcpy( (void *)&ba[k], (void *)&work, sizeof( struct card ));
        }
    }
    return;
}

同一組み合わせにならないように…
srand((unsigned)time(NULL));
で乱数を初期化します。

  1. コンピュータの思考ルーチン

        // コンピュータの3枚目以後を配る
        while(1) {
            rc = card_disp( COM, &tefuda[COM] );
            card_disp( USER1, &tefuda[USER1] );
            if ( rc >= 17 ) break;
            memcpy( (void *)&tefuda[COM].ca[tefuda[COM].maisu], (void *)&ba[ba_cnt++],
                 sizeof(struct card ));
            tefuda[COM].maisu++;
            if ( tefuda[COM].maisu >= TEFUDA_MAX_MAISU ) break;
        }

どんな思考してるかはここでは記載しません。
ご自身で考察して下さい。

ゲーム全体

/******************************************************************************/
/* 21ゲーム(ブラックジャック)                                               */
/* 1.ディーラーはコンピュータ                                               */
/* 2.手持ち金額が0になる又は場の残り枚数が少なくなるまでプレーできる       */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/

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

// 設定最大値(基本情報)
#define SET_MAX 4
#define KIGO_MAX 4
#define SUJI_MAX 13
#define MOJI_RYOIKI_MAX 8
#define BUF_MAX 128
#define KIRU_KAI_MAX 100

// 設定値
#define NOKORI_MAISU_MIN 15
#define KIRU_KAI_MIN 10
#define CARD_KIGO_SIZE 2
#define CARD_KAZU_SIZE 2
#define CARD_MAX_MAISU SUJI_MAX*KIGO_MAX*SET_MAX
#define MAX_NINZU 2
#define TEFUDA_MAX_MAISU 10

// メンバー定義
enum  member {
    COM,
    USER1
};

// カードの構造体(1枚)
struct card {
    char kigo[MOJI_RYOIKI_MAX];
    char nomber[MOJI_RYOIKI_MAX];
    int tensu;
};

// メンバーの手札構造体
struct te_card {
    struct card ca[TEFUDA_MAX_MAISU];
    int maisu;
    int total;
};

// グローバル変数
struct card ba[CARD_MAX_MAISU]; // 場のカードの実体
struct te_card tefuda[MAX_NINZU]; // 手札の実体

long kingaku; // 手持ち金額
long bet;     // 掛け金

/******************************************************************************/
/* void set_base_card(void)                                                   */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 場のカードをセットする(プログラム中で1回やれば良い)               */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void set_base_card(void)
{
    int i,j,k;
    int card_mai = 0;
    char now_kigo[MOJI_RYOIKI_MAX];

    for( i = 0; i < SET_MAX; i++ ) {
        for( j = 0; j < KIGO_MAX; j++ ) {
            switch( j ) {
                case 0:
                    memcpy( now_kigo, "S", CARD_KIGO_SIZE );
                    break;
                case 1:
                    memcpy( now_kigo, "M", CARD_KIGO_SIZE );
                    break;
                case 2:
                    memcpy( now_kigo, "H", CARD_KIGO_SIZE );
                    break;
                case 3:
                    memcpy( now_kigo, "D", CARD_KIGO_SIZE );
                    break;
                default:
                    break;
            }
            for( k = 0; k < SUJI_MAX; k++ ) {
                memcpy( ba[card_mai].kigo, now_kigo, CARD_KIGO_SIZE );
                switch( k ) {
                    case 0:
                        memcpy( ba[card_mai].nomber, "A", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 1;
                        break;
                    case 1:
                        memcpy( ba[card_mai].nomber, "2", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 2;
                        break;
                    case 2:
                        memcpy( ba[card_mai].nomber, "3", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 3;
                        break;
                    case 3:
                        memcpy( ba[card_mai].nomber, "4", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 4;
                        break;
                    case 4:
                        memcpy( ba[card_mai].nomber, "5", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 5;
                        break;
                    case 5:
                        memcpy( ba[card_mai].nomber, "6", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 6;
                        break;
                    case 6:
                        memcpy( ba[card_mai].nomber, "7", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 7;
                        break;
                    case 7:
                        memcpy( ba[card_mai].nomber, "8", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 8;
                        break;
                    case 8:
                        memcpy( ba[card_mai].nomber, "9", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 9;
                        break;
                    case 9:
                        memcpy( ba[card_mai].nomber, "T", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 10:
                        memcpy( ba[card_mai].nomber, "J", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 11:
                        memcpy( ba[card_mai].nomber, "Q", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    case 12:
                        memcpy( ba[card_mai].nomber, "K", CARD_KAZU_SIZE );
                        ba[card_mai].tensu = 10;
                        break;
                    default:
                        break;
                }
                card_mai++;
            }
        }
    }
    return;
}

/******************************************************************************/
/* void kiru_card(void)                                                       */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 場のカードをシャッフルする                                           */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void kiru_card( void )
{
    int i, j, k;
    struct card work;

    srand((unsigned)time(NULL));
    for( i = 0; i < (( rand() % KIRU_KAI_MAX ) + KIRU_KAI_MIN); i++ ) {
        for( j = 0; j < CARD_MAX_MAISU; j++ ) {
            k = rand() % CARD_MAX_MAISU;
            if( k == CARD_MAX_MAISU ) k--;
            memcpy( (void *)&work, (void *)&ba[j], sizeof( struct card ));
            memcpy( (void *)&ba[j], (void *)&ba[k], sizeof( struct card ));
            memcpy( (void *)&ba[k], (void *)&work, sizeof( struct card ));
        }
    }
    return;
}

/******************************************************************************/
/* int card_disp(int mode, struct te_card *te )                               */
/* 引数 int mode : メンバーコード                                            */
/*       struct te_card *te : メンバーの手札                                  */
/* 戻り 手札の点数                                                           */
/* 概要 手札を表示する                                                       */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
int card_disp(int mode, struct te_card *te )
{
    int i;
    int point = 0;
    int flg = 0;

    switch( mode ) {
        case COM:
            printf( "\n コンピュータ手 " );
            break;
        case USER1:
            printf( "\n あなたの手 " );
            break;
        default:
            break;
    }
    for( i = 0; i < te[0].maisu; i++ ) {
        printf( "%s%s ", te[0].ca[i].kigo, te[0].ca[i].nomber );
        point += te[0].ca[i].tensu;
        if ( point <= 11 && te[0].ca[i].tensu == 1 ) {
            point += 10;
            flg = 1;
        }
        if ( flg && point > 21 ) {
            point -= 10;
            flg = 0;
        }
    }
    printf( "%d\n", point );
    te[0].total = point;
    return point;
}

/******************************************************************************/
/* void card_ura_disp(int mode, struct te_card *te )                          */
/* 引数 int mode : メンバーコード                                            */
/*       struct te_card *te : メンバーの手札                                  */
/* 戻り なし                                                                 */
/* 概要 親2枚目裏手札を表示する                                             */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void card_ura_disp(int mode, struct te_card *te )
{
    int i;
    int point = 0;

    switch( mode ) {
        case COM:
            printf( "\n コンピュータ手" );
            printf( "%s%s ■ ", te->ca[0].kigo, te->ca[0].nomber );
            point += te->total;
            printf( "%d\n", point );
            break;
        default:
            return;
    }
    return;
}

/******************************************************************************/
/* void calc_point( void )                                                    */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 勝負の結果を表示する                                                 */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void calc_point( void )
{
    if ((tefuda[0].total == 21 && tefuda[0].maisu == 2 ) && 
        (tefuda[1].total == 21 && tefuda[1].maisu == 2 )) {
        printf( "両者ブラックジャックの為引き分け\n" );
        kingaku += bet;
    } else if ((tefuda[0].total == 21 && tefuda[0].maisu == 2 )) {
        printf( "コンピュータがブラックジャックの為負け\n" );
    } else if ((tefuda[1].total == 21 && tefuda[1].maisu == 2 )) {
        printf( "あなたがブラックジャックの為勝\n" );
        kingaku += (bet * 2 + (int)(bet / 2));
    } else if (((tefuda[1].total > tefuda[0].total ) || tefuda[0].total > 21) && 
            tefuda[1].total <= 21 ) {
        printf( " **** あなたの勝!!!!!!! ****\n" );
        kingaku += bet * 2;
        if ( tefuda[1].maisu >= 5 ) kingaku += (int)( bet /2 );
    } else if ( tefuda[1].total == tefuda[0].total && tefuda[1].total <= 21 ) {
        printf( " **** 引き分け ****\n" );
        kingaku += bet;
    } else {
        printf( " **** あなたの負け ****\n" );
    }
    bet = 0;
    return;
}

/******************************************************************************/
/* void set_bet( void )                                                       */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 掛け金の入力                                                         */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
void set_bet( void )
{
    char buf[BUF_MAX];

    bet = 0;

    while(1) {
        printf( "手持ち %d$\n", kingaku );
        printf( "掛け金   = " );
        gets( buf );
        bet = atoi( buf );
        if ( bet < 1 || bet > kingaku ) continue;
        kingaku -= bet;
        break;
    }
    return;
}

/******************************************************************************/
/* int main()                                                                 */
/* 引数 なし                                                                 */
/* 戻り なし                                                                 */
/* 概要 メイン                                                               */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
int main()
{
    int i, rc;
    int ba_cnt = 0;
    char buf[BUF_MAX];

    // 初期化
    set_base_card( );
    kiru_card( );

    kingaku = 100L;

    // 手持ちがある場合繰り返し
    while( kingaku ) {

        // 手札1枚目を配る
        for( i = 0; i < MAX_NINZU; i++ ) {
            memcpy( (void *)&tefuda[i].ca[0], (void *)&ba[ba_cnt++], sizeof(struct card ));
            tefuda[i].maisu = 1;
            card_disp(i, &tefuda[i] );
        }

        // 親2枚目を配る
        card_ura_disp(COM, &tefuda[COM]);
        memcpy( (void *)&tefuda[COM].ca[tefuda[COM].maisu], (void *)&ba[ba_cnt++], 
            sizeof(struct card ));
        tefuda[COM].maisu++;

        // 掛け金の設定
        set_bet( );

        // ユーザの2枚目以降を配る
        while(1) {
            memcpy( (void *)&tefuda[USER1].ca[tefuda[USER1].maisu],
                 (void *)&ba[ba_cnt++], sizeof(struct card ));
            tefuda[USER1].maisu++;
            rc = card_disp( USER1, &tefuda[USER1] );
            if ( rc >= 21 || tefuda[USER1].maisu >= TEFUDA_MAX_MAISU ) break;
            printf( "もう一枚取得しますか? y/n " );
            gets( buf );
            if ( memcmp( buf, "y", 1 ) == 0 || memcmp( buf, "Y", 1 ) == 0 ) continue;
            else if ( memcmp( buf, "n", 1 ) == 0 || memcmp( buf, "N", 1 ) == 0 ) break;
            else break;
        }

        // コンピュータの3枚目以後を配る
        while(1) {
            rc = card_disp( COM, &tefuda[COM] );
            card_disp( USER1, &tefuda[USER1] );
            if ( rc >= 17 ) break;
            memcpy( (void *)&tefuda[COM].ca[tefuda[COM].maisu], (void *)&ba[ba_cnt++],
                 sizeof(struct card ));
            tefuda[COM].maisu++;
            if ( tefuda[COM].maisu >= TEFUDA_MAX_MAISU ) break;
        }

        // 勝負の結果を表示する
        calc_point( );
        if ( ba_cnt > CARD_MAX_MAISU - NOKORI_MAISU_MIN ) break;
    }

    return 0;
}

GCCコンパイル

ソース名:main.c
コンパイル:gcc -o 21Name