🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

3回答

5530閲覧

Cでのブラックジャックについて

rinrin200011

総合スコア8

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2021/01/13 08:19

C言語で、ブラックジャックを作っているのですが、ディーラーが絶対に勝つようにカスタマイズしたいのですが、できません。。
ソースコードは以下のようになります。どうかよろしくお願いします。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5int hit_card(int); 6 7main() { 8 int total[2]; //カードの合計 9 char y_n; //カードを引くか引かないかの答え 10 11 srand(time(NULL)); 12 printf("【ブラックジャック】\n"); 13 14 //ディーラーが引く 15 hit_card(0); 16 total[0] = hit_card(0); 17 //プレイヤーが引く 18 hit_card(1); 19 total[1] = hit_card(1); 20 21 //プレイヤー3枚目以降 22 while (total[1] < 21) { 23 printf("もう1枚引きますか?(y/n) > "); 24 scanf("%c" , &y_n); 25 while (getchar() != '\n') { } 26 if (y_n == 'y') { 27 total[1] = hit_card(1); 28 } else if (y_n == 'n') { 29 break; 30 } 31 } 32 33 //ディーラー3枚目以降 34 while (total[0] < 17) { 35 total[0] = hit_card(0); 36 } 37 38 printf("\nディーラー:%d点 プレイヤー:%d点\n", total[0], total[1]); 39 40 //勝敗の判定 41 if ((total[0] < 22 && total[0] > total[1]) || total[1] > 21) { 42 printf("ディーラーの勝ち!\n"); 43 } else if (total[0] == total[1]) { 44 printf("引き分け\n"); 45 } else { 46 printf("プレイヤーの勝ち!\n"); 47 } 48} 49 50/*カードを引く関数 51引数 tern :ターンフラグ(ディーラー時は0、プレイヤー時は1) 52戻り値 total:引いたカードの合計点数 53*/ 54int hit_card(int tern) { 55 static char name[2][11] = { "ディーラー", "プレイヤー" }; 56 static char draw_mark[4][11] = { "ハート", "ダイヤ", "スペード", "クローバー" }; 57 static char draw_digit[13][3] = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" }; 58 static int score[13] = { 11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 }; 59 static int card[4][13]; //使用カード履歴 60 static int total[2] = { 0, 0 }; //引いたカードの合計点数 61 static int cnt[2] = { 0, 0 }; //引いたカードの枚数 62 static int a[2] = { 0, 0 }; //引いたAの枚数 63 static int hole_mark, hole_digit; //伏せたカードのマークと数 64 int mark, digit; //引いたカードのマークと数 65 66 //引くカード決め 67 do { 68 mark = rand() % 4; 69 digit = rand() % 13; 70 } while (card[mark][digit]); 71 card[mark][digit] = 1; 72 cnt[tern]++; 73 if (digit == 0) { 74 a[tern]++; 75 } 76 77 //引いたカード表示 78 if (tern == 0 && cnt[tern] == 3) { 79 printf("%s%d枚目:%sの%s(伏せカード)\n", name[tern], cnt[tern]-1, draw_mark[hole_mark], 80 draw_digit[hole_digit]); 81 } 82 if (tern == 0 && cnt[tern] == 2) { 83 printf("%s%d枚目:(伏せ)\n", name[tern], cnt[tern]); 84 hole_mark = mark; 85 hole_digit = digit; 86 } else { 87 printf("%s%d枚目:%sの%s\n", name[tern], cnt[tern], draw_mark[mark], draw_digit[digit]); 88 } 89 90 //合計点数計算 91 total[tern] += score[digit]; 92 if (total[tern] > 21 && a[tern] > 0) { 93 total[tern] -= 10; 94 a[tern]--; 95 } 96 97 return total[tern]; 98} 99

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

epistemeさんが書いている通り、ブラックジャックは本来ディーラーには選択権の無いゲームなので
ランダムにカードを引く限り、ディーラーを必ず勝つようにすることは出来ません。
従って、引くカードに任意性を持たせる必要があります。

一例ですが、プレイヤーは必ずバーストかトータル20以下に、ディーラーは必ずプレイヤーの
トータル+1なるようにデッキを操作するとかしないと無理ですね。

いきなりプログラムでの実装を考えるのではなく、どうすればディーラーが必ず勝てるいかさまが必要か
考えてみたら?

投稿2021/01/13 08:53

kaina

総合スコア418

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ブラックジャックのルールでは
「ディーラーは、自分の手が17以上になるまでカードを引かなければならず、17以上になったら、その後は追加のカードを引くことはできない。」
ですから、ディーラーは選択の余地がないはずです。

できるイカサマとしては、ディーラーに"プレイヤーに勝てるカード"を引かせること。それがお望みですか?
であるなら、場に出ていないカードの中からプレイヤーに勝てるカードを引かせるように台札(デッキ)を操作することになろうかと。

[追記] なにがなんでもディーラーに勝たせたいなら、ディーラーの二枚のドローで常に21となるよう
デッキを操作すればいい。それじゃイカサマがバレバレですが、それがお望みでしょうか。

ゲームとして成立(?)させるには、何度も繰り返したときにトータルでディーラーが"ほんのり"勝ってるように仕込むことになります。それがお望みでしょうか。

投稿2021/01/13 08:29

編集2021/01/13 10:48
episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

簡素な方法として:

プログラム開始時に,
まず,ゲームを実際に(何も表示とかせずに処理だけを)試行して,プレイヤが絶対に勝てない(途中でカードを配るのをやめたら負けるし,配りすぎるとバーストする)パターンを見つける(見つかるまで繰り返し試行する).

あとは,今まさにプログラムが始まったかのようにプレイヤとのゲームを開始してみせるが,実際には単に先に発見した勝ちパターンを再現してみせるだけである.
(プレイヤーがプレイする段階では,既に,ディーラー側のカード内容も,プレイヤーには何枚目に何のカードが配られるのかも確定している.)


実装してみた.

C

1//カードのスコア. 2//※面倒なので,Aのスコアは常に11点としている 3unsigned char ScoreOfCard( unsigned char CardID ) 4{ 5 static const unsigned char SCORE[] = { 11,2,3,4,5,6,7,8,9,10,10,10,10 }; 6 return SCORE[ CardID % 13 ]; 7} 8 9//カードの表示用 10void PrintCard( unsigned char CardID ) 11{ 12 printf( "%c%c", "SHDC"[ CardID/13 ], "A23456789TJQK"[ CardID%13 ] ); 13} 14 15//デック 16typedef struct Deck{ unsigned char Card[52]; } Deck; 17 18//デックを初期化 19void InitDeck( Deck *pDeck ) 20{ 21 int i; 22 for( i=0; i<52; ++i ){ pDeck->Card[i]=i; } 23} 24 25//デックをシャッフルする 26void ShuffleDeck( Deck *pDeck ) 27{ 28 int i,j; 29 for( i=52; i>=1; --i ) 30 { 31 j = rand() % i; 32 unsigned char tmp = pDeck->Card[i-1]; 33 pDeck->Card[i-1] = pDeck->Card[j]; 34 pDeck->Card[j] = tmp; 35 } 36} 37 38//ディーラーが勝利するようにデックをセットアップする. 39//イカサマ方法として,ディーラーに対してカードを配る際には常にボトムディールすることとする 40//(すなわち,ディーラーに配る用のカード群はデックのボトム側に仕込まれる). 41// 42//引数: 43// pDeck : デック.処理が成功すると仕込まれた状態になる. 44// pND : ディーラーに配る用にボトム側から仕込んだカードの枚数を返す用. 45// pNP : プレイヤーに配る用にトップ側から仕込んだカードの枚数を返す用. 46// 47//戻り値: 48// 成功時(うまく仕込めた時)には非0,失敗時は0を返す. 49int SetupGame( Deck *pDeck, int *pND, int *pNP ) 50{ 51 unsigned char DealerScore = 0; 52 unsigned char PlayerScore = 0; 53 const unsigned char *pCard; 54 55 //デックをシャッフル 56 ShuffleDeck( pDeck ); 57 58 //ディーラーの手をチェック 59 pCard = pDeck->Card + 51; //ボトム 60 *pND = 0; 61 while( DealerScore<17 ) 62 { 63 DealerScore += ScoreOfCard( *pCard ); 64 ++*pND; 65 //※面倒なのでディーラーがバーストするパターンは棄却する 66 if( DealerScore > 21 )return 0; 67 --pCard; 68 } 69 70 //プレイヤーの手をチェック 71 pCard = pDeck->Card; //トップ 72 *pNP = 0; 73 while( 1 ) 74 { 75 PlayerScore += ScoreOfCard( *pCard ); 76 ++*pNP; 77 78 if( PlayerScore > 21 )break; 79 if( PlayerScore >= DealerScore )return 0; 80 ++pCard; 81 } 82 return 1; 83} 84 85//やってみる 86void Test() 87{ 88 int i; 89 Deck TheDeck; 90 int ND, NP; 91 unsigned char Score; 92 const unsigned char *pCard; 93 94 //デックを初期化 95 InitDeck( &TheDeck ); 96 //ディーラーの勝ちパターンを仕込む 97 while( !SetupGame( &TheDeck, &ND, &NP ) ){} 98 99 //以下,仕込んだ結果を表示してみる 100 101 //ディーラー側の手 102 Score = 0; 103 pCard = TheDeck.Card + 51; //※ボトム 104 printf( "Dealer : " ); 105 for( i=0; i<ND; ++i, --pCard ) 106 { 107 PrintCard( *pCard ); 108 Score += ScoreOfCard( *pCard ); 109 printf( "(%2d) ", (int)Score ); 110 } 111 printf( "\n" ); 112 113 //プレイヤー側(カードを配り続けてバーストするところまで) 114 Score = 0; 115 pCard = TheDeck.Card; //※トップ 116 printf( "Player : " ); 117 for( i=0; i<NP; ++i, ++pCard ) 118 { 119 PrintCard( *pCard ); 120 Score += ScoreOfCard( *pCard ); 121 printf( "(%2d) ", (int)Score ); 122 } 123 printf( "\n" ); 124} 125 126//main 127int main(void) 128{ 129 int i; 130 srand( time(NULL) ); 131 for( i=0; i<5; ++i ) 132 { 133 Test(); 134 printf( "-----------\n" ); 135 } 136 return 0; 137}

結果例:

text

1Dealer : C8( 8) HQ(18) 2Player : H5( 5) CK(15) DQ(25) 3----------- 4Dealer : C2( 2) S5( 7) D2( 9) SQ(19) 5Player : C3( 3) S8(11) H4(15) HT(25) 6----------- 7Dealer : HQ(10) H8(18) 8Player : H4( 4) DT(14) ST(24) 9----------- 10Dealer : DJ(10) C9(19) 11Player : DT(10) S8(18) H6(24) 12----------- 13Dealer : H5( 5) D2( 7) H3(10) SK(20) 14Player : C4( 4) H9(13) DJ(23) 15-----------

投稿2021/01/15 03:00

編集2021/01/15 06:46
fana

総合スコア11985

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問