ブラックジャック

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

```c
/******************************************************************************/
/* 21ゲーム（ブラックジャック）                                               */
/* １．ディーラーはコンピュータ                                               */
/* ２．手持ち金額が０になる又は場の残り枚数が少なくなるまでプレーできる       */
/* 2016/08/04 n.tanaka                                                        */
/******************************************************************************/
```

# ゲーム
1. カード作り

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

```c
/******************************************************************************/
/* void set_base_card(void)                                                   */
/* 引数　なし                                                                 */
/* 戻り　なし                                                                 */
/* 概要　場のカードをセットする（プログラム中で１回やれば良い）               */
/* 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;
}

```


2. カードをシャッフルする

```c
/******************************************************************************/
/* 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));`
で乱数を初期化します。

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

```c

		// コンピュータの３枚目以後を配る
		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;
		}
```
どんな思考してるかはここでは記載しません。
ご自身で考察して下さい。

# ゲーム全体

```c
/******************************************************************************/
/* 21ゲーム（ブラックジャック）                                               */
/* １．ディーラーはコンピュータ                                               */
/* ２．手持ち金額が０になる又は場の残り枚数が少なくなるまでプレーできる       */
/* 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
};

// カードの構造体(１枚）
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)                                                   */
/* 引数　なし                                                                 */
/* 戻り　なし                                                                 */
/* 概要　場のカードをセットする（プログラム中で１回やれば良い）               */
/* 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 : メンバーの手札                                  */
/* 戻り　なし                                                                 */
/* 概要　親２枚目裏手札を表示する                                             */
/* 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 ) {
	
	    // 手札１枚目を配る
		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] );
		}
	
	    // 親２枚目を配る
		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( );

		// ユーザの２枚目以降を配る
		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;
		}

		// コンピュータの３枚目以後を配る
		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`