4人でじゃんけんをするプログラムの不具合

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
みそ油

4人でじゃんけんをするプログラムの不具合

#1

投稿記事 by みそ油 » 5年前

現在、プレイヤー1人とNPC3人の合計4人でじゃんけんをするプログラムを作成しています。プログラムの概略は下記のとおりです。
  1. 何回勝負か(何回勝利したら終了か)の入力を促す。(= n)
  2. じゃんけんをして、結果を表示する。
  3. 勝者が一人になるまでじゃんけんを繰り返す。
  4. プレイヤーとNPC1~3のいずれかがn勝したら、プレイヤーの成績(a勝b敗c分け)を表示し、プログラムを終了する。


以上の動作をするプログラムを作成するにあたり、下記のようなソースコードを書きましたが、一部の組み合わせ(後述)において、間違った勝敗の判定が表示される不具合が発生しております。
3日間不具合の発見に尽力しましたが発見できなかったため、こちらの掲示板にて質問をさせていただきました。諦めが早いようではございますが、ソースコードのどの部分に問題があるのかご教示を賜りたく存じます。

開発環境
OS:Windows7
コンパイラ:MinGW (GCC)

間違った勝敗判定がされる組み合わせ(プレイヤー NPC1 NPC2 NPC3 の順)
※括弧内は正しい判定
グー パー パー パー : 引き分け (プレイヤーのみが負け)
グー チョキ チョキ チョキ : 引き分け (プレイヤーのみが勝ち)
パー グー グー チョキ : プレイヤーとNPC2が負け (引き分け)
パー チョキ チョキ グー : プレイヤーとNPC2が勝ち (引き分け)
グー パー パー チョキ : 同上
チョキ グー グー パー : 同上

ソースコード

コード:

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

int  pc;
int  npc[3];
int  judge;
int  npc_only = 0;
int  win_no, lose_no, draw_no;
int  npc_win[3] = {0};

char  *hd[] = {"グー", "チョキ", "パー"};
char  pc_name[] = {"Player"};
char  npc_name[][5] = {"NPC1", "NPC2", "NPC3"};

void  initialize(void);
void  janken(void);
int  two_judge(int  h1, int  h2);
int  three_judge(int  h1, int  h2, int  h3);
int  four_judge(int  h1, int  h2, int  h3, int  h4);
void  count_no(int  result);
void  disp_result(int  result);
void  disp_winner(const char  *winner);
void  two_janken(	const char  *winner1, const char  *winner2, const char  *loser1, const char  *loser2,
					int  *winner_v1, int  *winner_v2 );
void  three_janken(	const char  *winner1, const char  *winner2, const char  *winner3,
					const char  *loser, int  *winner_v1, int  *winner_v2, int  *winner_v3 );
void  main_janken(void);

int  main(void)
{
	int  n;

	printf("何回勝負しますか:");
	scanf("%d", &n);

	initialize();

	do {
		main_janken();

	} while (win_no < n && npc_win[0] < n && npc_win[1] < n && npc_win[2] < n);

	printf("%d勝%d敗%d分けでした。\n", win_no, lose_no, draw_no);

	return  0;
}

void  initialize(void)
{
	win_no  = 0;
	lose_no = 0;
	draw_no = 0;

	srand(time(NULL));

	printf("じゃんけんゲーム開始!!\n");
}

void  janken(void)
{
	int  i;

	npc[0] = rand() % 3;
	npc[1] = rand() % 3;
	npc[2] = rand() % 3;

	if (!npc_only)
		do {
			printf("\n\aじゃんけんポン...");
			for (i = 0; i < 3; i++)
				printf("  (%d)%s", i, hd[i]);
			printf(":");
			scanf("%d", &pc);
		} while (pc < 0 || pc > 2);
}

int  two_judge(int  h1, int  h2)
{
	return  (h1 - h2 + 3) % 3;
}

/*	three_judge関数の返却値

	0	引き分け
	1	h1が負け
	2	h2が負け
	3	h3が負け
	4	h1が勝ち
	5	h2が勝ち
	6	h3が勝ち
*/
int  three_judge(int  h1, int  h2, int  h3)
{
	switch ((h1 + h2 + h3) % 3) {
		case  0 : break;					/* 引き分け */
		case  1 :							/* 誰か一人が負け */
			switch (two_judge(h1, h2)) {
				case  0 : return  3;
				case  1 : return  1;
				case  2 : return  2;
			}
		case  2 :							/* 誰か一人が勝ち */
			switch (two_judge(h1, h2)) {
				case  0 : return  6;
				case  1 : return  5;
				case  2 : return  4;
			}
	}
	return  0;
}

/*	four_judgeの返却値

	0	引き分け
	1	h1が負け
	2	h2が負け
	3	h3が負け
	4	h4が負け
	5	h1が勝ち
	6	h2が勝ち
	7	h3が勝ち
	8	h4が勝ち
	9	h1,h2が負け
	10	h1,h3が負け
	11	h1,h4が負け
	12	h1,h2が勝ち
	13	h1,h3が勝ち
	14	h1,h4が勝ち
*/
int  four_judge(int  h1, int  h2, int  h3, int  h4)
{
	if (h1 == h2 && h2 == h3 && h3 == h4)
		return  0;
	else if (h1 == h2 && h2 == h3) {
		if (two_judge(h3, h4) == 1)
			return  8;
		else
			return  4;
	}
	else {
		switch (three_judge(h1, h2, h3)) {
			case  0 : break;
			case  1 :
				switch (two_judge(h1, h4)) {
					case  0 : return  11;
					case  1 : return  1;
					case  2 : break;
				}
			case  2 :
				switch (two_judge(h1, h4)) {
					case  0 : return  2;
					case  1 : break;
					case  2 : return  13;
				}
			case  3 :
				switch (two_judge(h1, h4)) {
					case  0 : return  3;
					case  1 : break;
					case  2 : return  12;
				}
			case  4 :
				switch (two_judge(h1, h4)) {
					case  0 : return  14;
					case  1 : break;
					case  2 : return  5;
				}
			case  5 :
				switch (two_judge(h1, h4)) {
					case  0 : return  6;
					case  1 : return  10;
					case  2 : break;
				}
			case  6 :
				switch (two_judge(h1, h4)) {
					case  0 : return  7;
					case  1 : return  9;
					case  2 : break;
				}
		}
	}
	return  0;
}

void  count_no(int  result)
{
	switch (result) {
		case  0 : draw_no++;	break;
		case  1 : lose_no++;	break;
		case  2 : win_no++;		break;
	}
}

void  disp_result(int  result)
{
	switch (result) {
		case  0 : puts("引き分けです。");		break;
		case  1 : puts("あなたの負けです。");	break;
		case  2 : puts("あなたの勝ちです。");	break;
	}
}

void  disp_winner(const char  *winner)
{
	printf("%sが勝ちました。\n", winner);
}
 
void  two_janken(	const char  *winner1, const char  *winner2, const char  *loser1, const char  *loser2,
					int  *winner_v1, int  *winner_v2 )
{
	printf("%sと%sは負けました。%sと%sで勝負をします。\n", loser1, loser2, winner1, winner2);
	while (1) {
		janken();
		judge = two_judge(*winner_v1, *winner_v2);
		
		printf("%sは%sで、%sは%sです。\n", winner1, hd[*winner_v1], winner2, hd[*winner_v2]);
		if (judge)
			break;
		puts("あいこなのでもう一度勝負をします。");
	}
}

void  three_janken(	const char  *winner1, const char  *winner2, const char  *winner3,
					const char  *loser, int  *winner_v1, int  *winner_v2, int  *winner_v3 )
{
	printf("%sは負けました。%sと%sと%sで勝負をします。\n", loser, winner1, winner2, winner3);
	while (1) {
		janken();
		judge = three_judge(*winner_v1, *winner_v2, *winner_v3);

		printf("%sは%sで、%sは%sで、%sは%sです。\n",
			winner1, hd[*winner_v1], winner2, hd[*winner_v2], winner3, hd[*winner_v3]);
		if (judge)
			break;
		puts("あいこなのでもう一度勝負をします。");
	}
}

void  main_janken(void)
{
	judge = 0;
	npc_only = 0;
	janken();
	judge = four_judge(pc, npc[0], npc[1], npc[2]);
	printf("Playerは%sで、NPC1は%sで、NPC2は%sで、NPC3は%sです。\n", hd[pc], hd[npc[0]], hd[npc[1]], hd[npc[2]]);

	switch (judge) {
		case  0 : printf("引き分けです。\n");		count_no(0);		break;
		case  1 :
			count_no(1);
			npc_only = 1;
			three_janken(npc_name[0], npc_name[1], npc_name[2], pc_name, &npc[0], &npc[1], &npc[2]);
			switch (judge) {
				case  1 :
					two_janken(npc_name[1], npc_name[2], pc_name, npc_name[0], &npc[1], &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
						case  2 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
					}
					break;
				case  2 :
					two_janken(npc_name[0], npc_name[2], pc_name, npc_name[1], &npc[0], &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
						case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
					}
					break;
				case  3 :
					two_janken(npc_name[0], npc_name[1], pc_name, npc_name[2], &npc[0], &npc[1]);
					switch (judge) {
						case  1 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
						case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
					}
					break;
				case  4 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
				case  5 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
				case  6 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
			}
			break;
		case  2 :
			three_janken(pc_name, npc_name[1], npc_name[2], npc_name[0], &pc, &npc[1], &npc[2]);
			switch (judge) {
				case  1 :
					count_no(1);
					npc_only = 1;
					two_janken(npc_name[1], npc_name[2], pc_name, npc_name[0], &npc[1], &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
						case  2 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
					}
					break;
				case  2 :
					two_janken(pc_name, npc_name[2], npc_name[0], npc_name[1], &pc, &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;		break;
						case  2 : disp_winner(pc_name);			count_no(2);						break;
					}
					break;
				case  3 :
					two_janken(pc_name, npc_name[1], npc_name[0], npc_name[2], &pc, &npc[1]);
					switch (judge) {
						case  1 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;		break;
						case  2 : disp_winner(pc_name);			count_no(2);						break;
					}
					break;
				case  4 : disp_winner(pc_name);			count_no(2);					break;
				case  5 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;	break;
				case  6 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;	break;
			}
			break;
		case  3 :
			three_janken(pc_name, npc_name[0], npc_name[2], npc_name[1], &pc, &npc[0], &npc[2]);
			switch (judge) {
				case  1 :
					count_no(1);
					npc_only = 1;
					two_janken(npc_name[0], npc_name[2], pc_name, npc_name[1], &npc[0], &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
						case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
					}
					break;
				case  2 :
					two_janken(pc_name, npc_name[2], npc_name[0], npc_name[1], &pc, &npc[2]);
					switch (judge) {
						case  1 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;	break;
						case  2 : disp_winner(pc_name);			count_no(2);					break;
					}
					break;
				case  3 :
					two_janken(pc_name, npc_name[0], npc_name[1], npc_name[2], &pc, &npc[0]);
					switch (judge) {
						case  1 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;	break;
						case  2 : disp_winner(pc_name);			count_no(2);					break;
					}
					break;
				case  4 : disp_winner(pc_name);			count_no(2);					break;
				case  5 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;	break;
				case  6 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;	break;
			}
			break;
		case  4 :
			three_janken(pc_name, npc_name[0], npc_name[1], npc_name[2], &pc, &npc[0], &npc[1]);
			switch (judge) {
				case  1 :
					count_no(1);
					npc_only = 1;
					two_janken(npc_name[0], npc_name[1], pc_name, npc_name[2], &npc[0], &npc[1]);
					switch (judge) {
						case  1 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
						case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
					}
					break;
				case  2 :
					two_janken(pc_name, npc_name[1], npc_name[0], npc_name[2], &pc, &npc[1]);
					switch (judge) {
						case  1 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;	break;
						case  2 : disp_winner(pc_name);			count_no(2);					break;
					}
					break;
				case  3 :
					two_janken(pc_name, npc_name[0], npc_name[1], npc_name[2], &pc, &npc[0]);
					switch (judge) {
						case  1 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;	break;
						case  2 : disp_winner(pc_name);			count_no(2);					break;
					}
					break;
				case  4 : disp_winner(pc_name);			count_no(2);					break;
				case  5 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;	break;
				case  6 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;	break;
			}
			break;

		case  5 : disp_winner(pc_name);			count_no(2);						break;
		case  6 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;		break;
		case  7 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;		break;
		case  8 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;		break;

		case  9 :
			count_no(1);
			npc_only = 1;
			two_janken(npc_name[1], npc_name[2], pc_name, npc_name[0], &npc[1], &npc[2]);
			switch (judge) {
				case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
				case  2 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
			}
			break;
		case  10 :
			count_no(1);
			npc_only = 1;
			two_janken(npc_name[0], npc_name[2], pc_name, npc_name[1], &npc[0], &npc[2]);
			switch (judge) {
				case  1 : disp_winner(npc_name[2]);		npc_win[2]++;		break;
				case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
			}
			break;
		case  11 :
			count_no(1);
			npc_only = 1;
			two_janken(npc_name[0], npc_name[1], pc_name, npc_name[2], &npc[0], &npc[1]);
			switch (judge) {
				case  1 : disp_winner(npc_name[1]);		npc_win[1]++;		break;
				case  2 : disp_winner(npc_name[0]);		npc_win[0]++;		break;
			}
			break;
		case  12 :
			two_janken(pc_name, npc_name[0], npc_name[1], npc_name[2], &pc, &npc[0]);
			switch (judge) {
				case  1 : disp_winner(npc_name[0]);		count_no(1);	npc_win[0]++;		break;
				case  2 : disp_winner(pc_name);			count_no(2);						break;
			}
			break;
		case  13 :
			two_janken(pc_name, npc_name[1], npc_name[0], npc_name[2], &pc, &npc[1]);
			switch (judge) {
				case  1 : disp_winner(npc_name[1]);		count_no(1);	npc_win[1]++;		break;
				case  2 : disp_winner(pc_name);			count_no(2);						break;
			}
			break;
		case  14 :
			two_janken(pc_name, npc_name[2], npc_name[0], npc_name[1], &pc, &npc[2]);
			switch (judge) {
				case  1 : disp_winner(npc_name[2]);		count_no(1);	npc_win[2]++;		break;
				case  2 : disp_winner(pc_name);			count_no(2);						break;
			}
			break;
	}
}


みそ油

訂正

#2

投稿記事 by みそ油 » 5年前

ソースコードに不要な関数があったため訂正いたします。

対象の関数:disp_result
訂正内容:削除

box
記事: 1737
登録日時: 8年前

Re: 4人でじゃんけんをするプログラムの不具合

#3

投稿記事 by box » 5年前

みそ油 さんが書きました: 間違った勝敗判定がされる組み合わせ(プレイヤー NPC1 NPC2 NPC3 の順)
※括弧内は正しい判定
グー パー パー パー : 引き分け (プレイヤーのみが負け)
グー チョキ チョキ チョキ : 引き分け (プレイヤーのみが勝ち)
パー グー グー チョキ : プレイヤーとNPC2が負け (引き分け)
パー チョキ チョキ グー : プレイヤーとNPC2が勝ち (引き分け)
グー パー パー チョキ : 同上
チョキ グー グー パー : 同上
このような誤判定があるということは、
「全員の出した手がグー、チョキ、パーのうち2種類だけならば勝負が付いた。
それ以外ならばあいこ。」というロジックになっていないことが想像できます。

というわけで、まずは、勝負が付いたのかどうか(全員の出した手が2種類かどうか)を
判定し、勝負が付いたのであれば「グーはチョキにに勝つ。チョキはパーに勝つ。パーはグーに勝つ」という
ジャンケンの大原則に基づいて勝者を判定すればよいと思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

みそ油

Re: box様

#4

投稿記事 by みそ油 » 5年前

ご回答ありがとうございます。
おしゃられた判定については、ソースコード141行目からの

コード:

else {
        switch (three_judge(h1, h2, h3)) {
            case  0 : break;
という部分で実行しているつもりです。(この部分より前に全員の手が同じかどうかを判定しているため、three_judge関数の返却値が0であるときは、必ず3種類の手が含まれていることになります)

ISLe
記事: 2645
登録日時: 9年前
連絡を取る:

Re: 4人でじゃんけんをするプログラムの不具合

#5

投稿記事 by ISLe » 5年前

boxさんの書かれた判定方法は、何人でじゃんけんするか関係ありません。
じゃんけんの勝敗を判定する関数はひとつにまとめられます。

じゃんけんの勝敗ではなくて誰が勝ち残ったかを処理する部分の問題なのでは?

box
記事: 1737
登録日時: 8年前

Re: 4人でじゃんけんをするプログラムの不具合

#6

投稿記事 by box » 5年前

まあ確かに、勝敗を判定する関数は1個にまとめられそうな気がします。
今はたまたまプレイヤーが4人だから400行ほどで収まっていますが、
何かの拍子に5人、6人、...と人数を多くしようとしたとき、
今の設計の考え方では破綻しそうです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

box
記事: 1737
登録日時: 8年前

Re: 4人でじゃんけんをするプログラムの不具合

#7

投稿記事 by box » 5年前

勝敗を判定する関数の仕様を
1)初期値:全員あいこ
2)全員の手が2種類かどうか判定
3)2種類でなければそのまま戻る
4)2種類のとき、
4-1)グーとチョキに分かれていれば、グーに勝者フラグを立て、チョキに敗者フラグを立てる
4-2)チョキとパーに分かれていれば、チョキに勝者フラグを立て、パーに敗者フラグを立てる
4-3)パーとグーに分かれていれば、パーに勝者フラグを立て、グーに敗者フラグを立てる
というような具合にすると、プレイヤーが2人以上何人であっても対応可能であるような気がします。

勝敗を判定する関数から戻った時点では、
1)全員あいこ
2)勝者と敗者とに二分
のいずれかになるはずです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

taketoshi
記事: 221
登録日時: 9年前
住所: 日本国

Re: 4人でじゃんけんをするプログラムの不具合

#8

投稿記事 by taketoshi » 5年前

four_judge関数にダイレクトに引数を指定して動かしてみました

コード:

/*  four_judgeの返却値
 
    0   引き分け
    1   h1が負け
    2   h2が負け
    3   h3が負け
    4   h4が負け
    5   h1が勝ち
    6   h2が勝ち
    7   h3が勝ち
    8   h4が勝ち
    9   h1,h2が負け
    10  h1,h3が負け
    11  h1,h4が負け
    12  h1,h2が勝ち
    13  h1,h3が勝ち
    14  h1,h4が勝ち
*/
    judge = four_judge(2, 0, 0, 1);//パー グー グー チョキ : プレイヤーとNPC2が負け (引き分け)
戻り値は10です。プレイヤーとNPC2が負けています。
for_judge関数内部の処理は意図したものなのでしょうか。

ジャンケンは以下の簡単なコードで二者の勝ち負けを判定できます
私はSRPGの武器同士の相性を判定する三すくみでこのコードを使用しています。

私が作るならばboxさんのおっしゃる通り最初にアイコの判定をしてから、
あとは総当たりでこのコードで判定をして負けたキャラクタから生存フラグをバキバキ折って最後の一人が残るまで続けるように作ります。

コード:

const int tyoki = 0;
const int par = 1;
const int goo = 2;
//武器の三すくみの決定
//戻り値(3すくみで実施する場合)
//0...引き分け
//1...後者の勝ち
//2...前者の勝ち
int compatible(int x,int y){
	return (x-y+3) % 3;
}

みそ油

Re:ご回答いただいた皆様

#9

投稿記事 by みそ油 » 5年前

皆様、ご回答ありがとうございます。返信が遅くなり、申し訳ございません。
皆様のご回答をもとにアルゴリズムを見直し、ソースコードを大幅に改変しました。ところが、新しいプログラムでも不具合が発生しており、現在原因を探っているところです。修正でき次第、フォーラムルールに則り改変後のソースコードを記そうと思っております。
親切にご指導いただきまして、誠にありがとうございました。

たいちう
記事: 418
登録日時: 9年前

Re: 4人でじゃんけんをするプログラムの不具合

#10

投稿記事 by たいちう » 5年前

設計を見直すべきというのは同意ですが、デバッグの技術を高めることも重要です。
おそらく乱数が絡んだので難しかったのだと思いますが、taketoshiさんの方法や、
次のようにjanken()を直接書き換えて、問題のあるパターンを検証する方法もあります。

コード:

void  janken(void)
{
	pc = 2;
    npc[0] = 0;
    npc[1] = 0;
    npc[2] = 1;
}
ちょっと追いかけてみると、four_judge()の外側のswitch文にbreakがないことが判るでしょう。
他にも問題があるかもしれませんが。

みそ油

Re: たいちう様

#11

投稿記事 by みそ油 » 5年前

おっしゃるとおりです。デバッグ技術はもとより、アルゴリズム組み方その他の技術に関して、さらなる学習と訓練が必要であることを痛感しております。
さて、four_judge関数についてのご指摘、ありがとうございました。three_judge関数の内部も、同様にbreak文が欠落していたようです。これにより、間違った判定がされる不具合の原因がわかりました。

コード:

            case  1 :
                switch (two_judge(h1, h4)) {
                    case  0 : return  11;
                    case  1 : return  1;
                    case  2 : break;
                }
            case  2 :
                switch (two_judge(h1, h4)) {
                    case  0 : return  2;
                    case  1 : break;
                    case  2 : return  13;
                }
144行目からの、外側のcase(以下case外)2までを例に挙げると、引き分けであった場合はcase外1の内側のcase(以下case内)2が実行されて、break文により内側のswitch文を脱出します。
しかし外側のbreak文がないため外側のswitch文を脱出できず、case外2のcase内0にあるreturn文によって関数ごとswitch文を脱出するため、返却値が間違ったものとなるようです。また、four_judge関数内でthree_judge関数を使用しているため、さらにthree_judge関数内のbreak文の欠落も絡んできます。

必要な場所にbreak文を加えたところ、正常に動作しました。つきましては、当問題は解決といたします。なお、改変したプログラムについては、作成を続行します。
ご回答いただいた皆様、ありがとうございました。


修正後のソースコード(一部)

コード:

            case  1 :
                switch (two_judge(h1, h4)) {
                    case  0 : return  11;
                    case  1 : return  1;
                    case  2 : break;
                }
                break;
            case  2 :
                switch (two_judge(h1, h4)) {
                    case  0 : return  2;
                    case  1 : break;
                    case  2 : return  13;
                }
                break;
[/size]

みそ油

Re: 4人でじゃんけんをするプログラムの不具合

#12

投稿記事 by みそ油 » 5年前

皆様のご回答をもとに設計をしなおしたプログラムが完成しましたので、予告通り公開いたします。

コード:

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

#define  NUM  4

int  plyrs[NUM];
int  win_no, lose_no;
int  npc_win[3] = {0};

char  *hd[] = {"グー", "チョキ", "パー"};
char  pc_name[] = {"Player"};
char  npc_name[][5] = {"NPC1", "NPC2", "NPC3"};

void  initialize(void);
void  janken(void);
int  judge(int  plyr1, int  plyr2, int  plyr3, int  plyr4, int  cnt);
void  count_no(int  result);
void  disp_hand(int  plyr1, int  plyr2, int  plyr3, int  plyr4);
void  disp_winner(const char  *winner);
void  disp_loser(int  plyr1, int  plyr2, int  plyr3, int  plyr4, int  cnt);
void  reset(void);

int  main(void)
{
	int  n;
	int  i;
	int  cnt = -1;

	printf("何回勝負しますか:");
	scanf("%d", &n);

	initialize();

	do {
		janken();
		disp_hand(plyrs[0], plyrs[1], plyrs[2], plyrs[3]);

		switch (judge(plyrs[0], plyrs[1], plyrs[2], plyrs[3], cnt)) {
			case  0 : puts("引き分けです。");		break;
			case  1 : 
				for (i = 0; i < NUM; i++) {
					if (plyrs[i] >= 0) {
						if (!i) {
							disp_winner(pc_name);
							count_no(2);
							reset();
							cnt = -1;
							break;
						}
						else {
							disp_winner(npc_name[i - 1]);
							count_no(1);
							npc_win[i - 1]++;
							reset();
							cnt = -1;
							break;
						}
					}
				}
				break;
			default :
				disp_loser(plyrs[0], plyrs[1], plyrs[2], plyrs[3], cnt);
				cnt--;
				break;
		}

	} while (win_no < n && npc_win[0] < n && npc_win[1] < n && npc_win[2] < n);

	printf("\n%d勝%d敗でした。", win_no, lose_no);
	if (win_no == n)
		printf("%sの勝ちです。\n", pc_name);
	else
		for (i = 0; i < NUM - 1; i++)
			if (npc_win[i] == n)
				printf("%sの勝ちです。", npc_name[i]);

	return  0;
}

void  initialize(void)
{
	win_no  = 0;
	lose_no = 0;

	srand(time(NULL));

	printf("じゃんけんゲーム開始!!\n");
}

void  janken(void)
{
	int  i;

	if (plyrs[1] >= 0)		plyrs[1] = rand() % 3;
	if (plyrs[2] >= 0)		plyrs[2] = rand() % 3;
	if (plyrs[3] >= 0)		plyrs[3] = rand() % 3;

	if (plyrs[0] >= 0)
		do {
			printf("\n\aじゃんけんポン...");
			for (i = 0; i < 3; i++)
				printf("  (%d)%s", i, hd[i]);
			printf(":");
			scanf("%d", &plyrs[0]);
		} while (plyrs[0] < 0 || plyrs[0] > 2);
}

int  judge(int  plyr1, int  plyr2, int  plyr3, int  plyr4, int  cnt)
{
	int  i;
	int  hand[NUM] = {plyr1, plyr2, plyr3, plyr4};
	int  count[3] = {0};
	int  win_hd;
	int  flag = 0;

	for (i = 0; i < NUM; i++) {
		switch (hand[i]) {
			case  0  : count[0]++;		break;
			case  1  : count[1]++;		break;
			case  2  : count[2]++;		break;
		}
	}

	if (count[0] && count[1] && count[2])
		return  0;
	else {
		for (i = 0; i < 3; i++) {
			if (!count[i]) {
				win_hd = (i + 1) % 3;	/* iに負ける手の値を代入 */
				flag++;
			}
		}
		if (flag == 2)
			return  0;

		for (i = 0; i < NUM; i++) {
			if (hand[i] == win_hd)
				plyrs[i] = hand[i];
			else if (hand[i] >= 0)
				plyrs[i] = cnt;
		}
	}
	return  count[win_hd];		/* 勝った人数を返却 */
}

void  count_no(int  result)
{
	switch (result) {
		case  1 : lose_no++;	break;
		case  2 : win_no++;		break;
	}
}

void  disp_hand(int  plyr1, int  plyr2, int  plyr3, int  plyr4)
{
	int  i;
	int  plyr[NUM] = {plyr1, plyr2, plyr3, plyr4};

	if (plyrs[0] >= 0) {
		printf("%sは%sで、", pc_name, hd[plyr[0]]);
	}
	for (i = 1; i < NUM; i++) {
		if (plyr[i] >= 0)
			printf("%sは%sで、", npc_name[i - 1], hd[plyr[i]]);
	}
	printf("\bす。\n");
	fflush(stdout);
}

void  disp_winner(const char  *winner)
{
	printf("%sが勝ちました。\n", winner);
}

void  disp_loser(int  plyr1, int  plyr2, int  plyr3, int  plyr4, int  cnt)
{
	int  i;

	if (plyrs[0] == cnt)
		printf("%sと", pc_name);
	
	for (i = 1; i < NUM; i++)
		if (plyrs[i] == cnt)
			printf("%sと", npc_name[i - 1]);
	printf("\bが負けました。");
	fflush(stdout);

	if (plyrs[0] >= 0)
		printf("%sと", pc_name);
	
	for (i = 1; i < NUM; i++) {
		if (plyrs[i] >= 0)
			printf("%sと", npc_name[i - 1]);
	}
	printf("\bで勝負を続行します。\n");
	fflush(stdout);
}

void  reset(void)
{
	int  i;

	for (i = 0; i < NUM; i++)
		plyrs[i] = 0;
}
 
[/size]

閉鎖

“C言語何でも質問掲示板” へ戻る