今回は、どの山からいくつ取ったかを一手ごとに記録して
勝敗がついたら、これを表示する機能を付けます。
では、早速プログラムを見てみましょう。
// game35704.cpp
#include <windows.h>
#include <time.h>
#include <conio.h>
class Mountain
{
HANDLE hOut, hIn;
struct _mt{
int mt[15];
int st[15];
}mtst;
int te;
int mt[3];
int sente, order;
int judge();
int show_stone();
int init();
int take_stone();
int comp_take();
int no_of_0();
int locate(int, int);
int print(char *);
int input(char *, int);
int show_list();
int cls();
public:
Mountain();
int play();
};
Mountainクラスにmtst構造体が増えました。これに、
記録を残していくようにします。teメンバも増えました。これは、現在何手目かを示します(第n手の時n-1)。
show_listメンバ関数は、勝敗がついたらそれまでの手を表示します。
clsメンバ関数は画面を全消去します。
Mountain, show_stone, judgeの各メンバ関数に変更はありません。
int Mountain::take_stone()
{
char ans[8];
int i, stone, mtorder;
for (i = 4; i <= 5; i++) {
locate(0, i);
print(" ");
}
if (sente != order) {
comp_take();
if (judge() == 0) {
for (i = 4; i < 6; i++) {
locate(0, i);
print(" ");
}
locate(0, 7);
print("コンピュータの勝ちです");
show_list();
_getch();
return 1;
}
if (order == 1)
order = 0;
else
order = 1;
te++;
return 0;
}
while (1) {
locate(0, 6);
print(" ");
locate(0, 4);
print("どの山からとりますか(A,B,C)---");
if (input(ans, 8) == -1) {
locate(0, 6);
print("内部エラーです");
_getch();
exit(-1);
}
if (strcmp(ans, "A") != 0 && strcmp(ans, "B") != 0 && strcmp(ans, "C") != 0 &&
strcmp(ans, "a") != 0 && strcmp(ans, "b") != 0 && strcmp(ans, "c") != 0) {
for (i = 4; i <= 5; i++) {
locate(0, i);
print(" ");
}
locate(0, 6);
print("山の指定が正しくありません");
_getch();
continue;
} else {
ans[0] = toupper(ans[0]);
mtorder = ans[0] - 'A';
if (mt[mtorder] == 0) {
for (i = 4; i <= 5; i++) {
locate(0, i);
print(" ");
}
locate(0, 6);
print("その山にはもう石はありません");
_getch();
continue;
}
break;
}
}
while (1) {
locate(0, 6);
print(" ");
locate(0, 5);
print( "いくつとりますか---");
if (input(ans, 8) == -1) {
locate(0, 6);
print("内部エラーです");
_getch();
exit(-1);
}
stone = atoi(ans);
mt[mtorder] -= stone;
if (mt[0] + mt[1] + mt[2] == 0) {
locate(0, 5);
print(" ");
locate(0, 6);
print("その取り方では山の石が全部0になります");
_getch();
mt[mtorder] += stone;
continue;
}
mt[mtorder] += stone;
if (mt[mtorder] - stone < 0 || stone <= 0) {
locate(0, 5);
print(" ");
locate(0, 6);
print("取る石の数が不正です");
_getch();
continue;
} else {
break;
}
}
mt[mtorder] -= stone;
show_stone();
mtst.mt[te] = mtorder;
mtst.st[te] = stone;
if (judge() == 0) {
for (i = 4; i <= 5; i++) {
locate(0, i);
print(" ");
}
locate(0, 7);
print("あなたの勝ちです");
show_list();
return 1;
}
if (order == 1)
order = 0;
else
order = 1;
te++;
return 0;
}
勝敗がついたらshow_listメンバ関数を呼んで、それまでの経過を表示させます。人間が1手指すと(山から石を取ると)それをmtst構造体に記録します。
どちらかが1手終わる毎にteの数を1増やします。
int Mountain::init()
{
char ans[8];
mt[0] = 3;
mt[1] = 5;
mt[2] = 7;
memset(&mtst, 0, sizeof(mtst));
te = 0;
cls();
locate(0, 0);
print("あなたが先手になりますか(Y/N)---");
if (input(ans, 8) == -1) {
locate(0, 6);
print("内部エラーです");
_getch();
exit(-1);
}
if (ans[0] == 'y' || ans[0] == 'Y') {
sente = 1;
} else {
sente = 0;
}
order = 1;
return 0;
}
ゲームの初期化関数です。構造体を全部0で埋めます。teも0に戻します。 clsメンバ関数を使って画面を消去しています。
その後、どちらが先手になるかを決めています。
int Mountain::comp_take()
{
int mtorder, stone;
char mtname, szBuf[64];
int jump = 0, i;
srand((unsigned)time(NULL));
if (no_of_0() == 0) { //どの山も0ではない
//2-4-6パターンにする
if (mt[0] == 3 && mt[1] == 4 && mt[2] == 6) {
mtorder = 0;
stone = 1;
mt[0] = 2;
goto end;
}
if (mt[1] == 5 && mt[0] == 2 && mt[2] == 6) {
mtorder = 1;
stone = 1;
mt[1] = 4;
goto end;
}
if (mt[2] == 7 && mt[0] == 2 && mt[1] == 4) {
mtorder = 2;
stone = 1;
mt[2] = 6;
goto end;
}
//1-4-5パターンにする
if (mt[0] > 1 && mt[1] + mt[2] == 9 && mt[1] * mt[2] == 20) {
mtorder = 0;
stone = mt[0] - 1;
mt[0] = 1;
goto end;
}
if (mt[1] > 4 && mt[0] == 1 && mt[2] == 5) {
mtorder = 1;
stone = mt[1] - 4;
mt[1] = 4;
goto end;
}
if (mt[2] > 4 && mt[0] == 1 && mt[1] == 5) {
mtorder = 2;
stone = mt[2] - 4;
mt[2] = 4;
goto end;
}
if (mt[2] > 5 && mt[0] == 1 && mt[1] == 4) {
mtorder = 2;
stone = mt[2] - 4;
mt[2] = 4;
goto end;
}
//1-2-3パターンにする
if (mt[0] > 1 && mt[1] + mt[2] == 5 && mt[1] * mt[2] == 6) {
mtorder = 0;
stone = mt[0] - 1;
mt[0] = 1;
goto end;
}
if (mt[0] > 2 && mt[1] + mt[2] == 4 && mt[1] * mt[2] == 3) {
mtorder = 0;
stone = mt[0] - 2;
mt[0] = 2;
goto end;
}
if (mt[0] == 3 && mt[1] + mt[2] == 3 && mt[1] * mt[2] == 2) {
mtorder = 0;
stone = mt[0] - 3;
mt[0] = 3;
goto end;
}
if (mt[1] > 1 && mt[0] + mt[2] == 5 && mt[0] * mt[2] == 6) {
mtorder = 1;
stone = mt[1] - 1;
mt[1] = 1;
goto end;
}
if (mt[1] > 2 && mt[0] + mt[2] == 4 && mt[0] * mt[2] == 3) {
mtorder = 1;
stone = mt[1] - 2;
mt[1] = 2;
goto end;
}
if (mt[1] > 3 && mt[0] + mt[2] == 3 && mt[0] * mt[2] == 2) {
mtorder = 1;
stone = mt[1] - 3;
mt[1] = 3;
goto end;
}
if (mt[2] > 1 && mt[0] + mt[1] == 5 && mt[0] * mt[1] == 6) {
mtorder = 2;
stone = mt[2] - 1;
mt[2] = 1;
goto end;
}
if (mt[2] > 2 && mt[0] + mt[1] == 4 && mt[0] * mt[1] == 3) {
mtorder = 2;
stone = mt[2] - 2;
mt[2] = 2;
goto end;
}
if (mt[2] > 3 && mt[0] + mt[1] == 3 && mt[0] * mt[1] == 2) {
mtorder = 2;
stone = mt[2] - 3;
mt[2] = 3;
goto end;
}
//1-1-1パターンにする
if (mt[0] == mt[1] && mt[0] == 1 && mt[2] > 1) {
mtorder = 2;
stone = mt[2] - 1;
mt[2] = 1;
goto end;
}
if (mt[1] == mt[2] && mt[1] == 1 && mt[0] > 1) {
mtorder = 0;
stone = mt[0] - 1;
mt[0] = 1;
goto end;
}
if (mt[0] == mt[2] && mt[0] == 1 && mt[1] > 1) {
mtorder = 1;
stone = mt[1] - 1;
mt[1] = 1;
goto end;
}
if (mt[0] == mt[1]) {
mtorder = 2;
stone = mt[2];
mt[mtorder] = 0;
goto end;;
}
if (mt[1] == mt[2]) {
mtorder = 0;
stone = mt[0];
mt[mtorder] = 0;
goto end;;
}
if (mt[2] == mt[0]) {
mtorder = 1;
stone = mt[1];
mt[mtorder] = 0;
goto end;;
}
}
//0の山が1つだけである
if (no_of_0() == 1) {
if (mt[0] == 0) {
if (mt[1] == 1) {
mtorder = 2;
stone = mt[2];
mt[2] = 0;
goto end;
}
if (mt[2] == 1) {
mtorder = 1;
stone = mt[1];
mt[1] = 0;
goto end;
}
if (mt[1] > mt[2]) {
mtorder = 1;
stone = mt[1] - mt[2];
mt[mtorder] -= stone;
goto end;
}
if (mt[2] > mt[1]) {
mtorder = 2;
stone = mt[2] - mt[1];
mt[mtorder] -= stone;
goto end;
}
if (mt[2] == mt[1]){
mtorder = 1;
stone = 1;
mt[mtorder] -= stone;
goto end;
}
}
if (mt[1] == 0) {
if (mt[0] == 1) {
mtorder = 2;
stone = mt[2];
mt[2] = 0;
goto end;
}
if (mt[2] == 1) {
mtorder = 0;
stone = mt[0];
mt[0] = 0;
goto end;
}
if (mt[0] > mt[2]) {
mtorder = 0;
stone = mt[0] - mt[2];
mt[mtorder] -= stone;
goto end;
}
if (mt[2] > mt[0]) {
mtorder = 2;
stone = mt[2] - mt[0];
mt[mtorder] -= stone;
goto end;
}
if (mt[0] == mt[2]) {
mtorder = 2;
stone = 1;
mt[mtorder] -= stone;
goto end;
}
}
if (mt[2] == 0) {
if (mt[1] == 1) {
mtorder = 0;
stone = mt[0];
mt[0] = 0;
goto end;
}
if (mt[0] == 1) {
mtorder = 1;
stone = mt[1];
mt[1] = 0;
goto end;
}
if (mt[0] > mt[1]) {
mtorder = 0;
stone = mt[0] - mt[1];
mt[mtorder] -= stone;
goto end;
}
if (mt[1] > mt[0]) {
mtorder = 1;
stone = mt[1] - mt[0];
mt[mtorder] -= stone;
goto end;
}
if (mt[1] == mt[0]) {
mtorder = 0;
stone = 1;
mt[mtorder] -= 1;
goto end;
}
}
}
if (no_of_0() == 2) {
for (i = 0; i < 3; i++) {
if (mt[i] != 0) {
stone = mt[i] - 1;
mtorder = i;
mt[i] = 1;
goto end;
}
}
}
while (1) {
mtorder = rand() % 3;
if (mt[mtorder] == 0)
continue;
else
break;
}
while (1) {
stone = 1;
mt[mtorder] -= stone;
if (mt[0] + mt[1] + mt[2] == 0) {
mt[mtorder] += stone;
continue;
} else {
break;
}
}
end:
mtst.mt[te] = mtorder;
mtst.st[te] = stone;
mtname = mtorder + 'A';
locate(0, 4);
wsprintf(szBuf, "コンピュータは%cから%d個取ります", mtname, stone);
print(szBuf);
_getch();
show_stone();
return 0;
}
変更点は、コンピュータの取る石が決まったら、mtst構造体に記録している点だけです。
int Mountain::play()
{
int ret;
char ans[8];
while (1) {
init();
show_stone();
while (1) {
ret = take_stone();
if (ret == 1)
break;
}
print("\nもう一度やりますか(Y/N) ");
if (input(ans, 8) == -1) {
print("\n内部エラーです");
_getch();
exit(-1);
}
if (ans[0] == 'y' || ans[0] == 'Y') {
continue;
} else {
cls();
break;
}
}
return 0;
}
画面消去にclsメンバ関数を使っています。
no_of_0, locate, print, inputの各メンバ関数に変更はありません。
int Mountain::show_list()
{
int i;
char szBuf[64], szSashite[8];
print("\n\n");
print("*** 今回の勝負 ***\n");
for (i = 0; i < 15; i++) {
if (mtst.st[i] == 0)
break;
if ((sente == 1 && i % 2 == 0) || (sente == 0 && i % 2 != 0))
strcpy(szSashite, "You");
else
strcpy(szSashite, "Com");
wsprintf(szBuf, "第%0d手 %s %cより%d個\n", i + 1, szSashite, mtst.mt[i] + 'A', mtst.st[i]);
print(szBuf);
}
return 0;
}
手をmtst構造体から読み出して表示しています。
int Mountain::cls()
{
COORD coset;
DWORD dwWritten;
CONSOLE_SCREEN_BUFFER_INFO cinf;
GetConsoleScreenBufferInfo(hOut, &cinf);
coset.X = 0;
coset.Y = 0;
if (FillConsoleOutputCharacter(hOut, ' ', cinf.dwSize.X * cinf.dwSize.Y, coset, &dwWritten) ==0)
return -1;
return 0;
}
画面消去関数です。
main関数に変更はありません。今回は簡単でした。記録した手順を再現する機能を作ってみてください。
Update Jun/23/2002 By Y.Kumei