LoginSignup
0
1

More than 3 years have passed since last update.

ブラックジャック

Last updated at Posted at 2020-08-08

初めに

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1