主に関係しているのは、位置指定をして文字列を表示する部分や 勝敗を判定する部分です。
左の図はマス目を5にした場合の盤面です。
多少ゲームらしくなってきました。
では、プログラムを見てみましょう。
碁盤のマス目をMASUで定義しています。この値を変えることにより いろいろなマス目の碁盤を作ることができます。// game03.cpp #define MASU 5 #include <windows.h> //GetStdHandle関数などを使うので必要 #include <iostream.h> #include <stdio.h> class Ban { int ban[MASU][MASU], nTe; //ban[x][y]石の位置種類 nTe:何手目か HANDLE hOut; BOOL bSente; //TRUE:先手 FALSE:後手 char szHantei[32]; int Locate(int, int); int checkLocation(int, int); int bandraw(); int judge(); public: Ban(); int putStone(); };
配列banの要素もMASUに依存しているのでban[MASU][MASU]としています。
コンストラクタです。ban配列の要素をすべて0にするときもMASUに依存しているので このように変更となりました。Ban::Ban() { int i, j; for (i = 0; i < MASU; i++) { for (j = 0; j < MASU; j++) { ban[i][j] = 0; } } hOut = GetStdHandle(STD_OUTPUT_HANDLE); bSente = TRUE; nTe = 1; bandraw(); }
この部分に特に変更はありません。//VC++のコンソールアプリ以外の人は、この関数を //自分の環境に合うように書き直してください int Ban::Locate(int x, int y) { COORD dwPos; dwPos.X = (SHORT)x; dwPos.Y = (SHORT)y; if (SetConsoleCursorPosition(hOut, dwPos) == 0) return -1; else return 0; }
差し手の指示によりban配列に1または2を代入します。 先手が置いた位置は1後手が置いた位置には2が代入されます。 差し手の指示する文字列を位置に変換する方法はC言語編第66章を参照してください。int Ban::putStone() { char szSashite[8], szLocation[8], cMoji, szTxt[8]; int row, col; int jud; while (1) { if (bSente) strcpy(szSashite, "先手"); else strcpy(szSashite, "後手"); Locate(28, MASU + 2); printf(" "); Locate(0, MASU + 2); printf("位置を指定してください(%s)", szSashite); gets(szLocation); if (isalpha(szLocation[0]) == 0) { Locate(0, MASU + 3); printf("指定が違います"); continue; } if (isupper(szLocation[0]) == 0) cMoji = toupper(szLocation[0]); else cMoji = szLocation[0]; row = cMoji - 'A'; if (row < 0 || row > MASU - 1) { Locate(0, MASU + 3); printf("行の指定が違います"); continue; } if (isdigit(szLocation[1]) != 0 && isdigit(szLocation[2]) != 0 && szLocation[3] == '\0') { szTxt[0] = szLocation[1]; szTxt[1] = szLocation[2]; szTxt[2] = '\0'; col = atoi(szTxt) - 1; } else if (isdigit(szLocation[1]) != 0 && szLocation[2] == '\0') { szTxt[0] = szLocation[1]; szTxt[1] = '\0'; col = atoi(szTxt) - 1; } else { Locate(0, MASU + 3); printf("列の指定が違います"); continue; } if (col < 0 || col > MASU - 1) { Locate(0, MASU + 3); printf("列の位置指定が違います"); continue; } if (checkLocation(row, col) != 0) { Locate(0, MASU + 3); printf("そこには置けません!"); continue; } if (bSente) ban[row][col] = 1; else ban[row][col] = 2; bSente = !bSente; bandraw(); Locate(0, MASU + 3); printf(" "); nTe++; if (nTe > MASU * MASU + 1) break; jud = judge(); switch (jud) { case 0: strcpy(szHantei, ""); break; case 1: strcpy(szHantei, "先手の勝ち!"); break; case 2: strcpy(szHantei, "後手の勝ち!"); break; default: strcpy(szHantei, "Error!"); break; } if (jud == 0 && nTe == MASU * MASU + 1) { strcpy(szHantei, "引き分け!"); jud = 2; } Locate(0, MASU + 4); printf("%s\n", szHantei); if (jud != 0) break; } return 0; }
差し手の指示した位置に石が置けるかどうかをチェックするメンバ関数です。int Ban::checkLocation(int x, int y) { if (ban[x][y] == 0) return 0; else return -1; }
特に変更はありません。
盤と石を描画するメンバ関数です。これは、もろにMASUに依存します。int Ban::bandraw() { int i, j; Locate(0, 0); printf(" "); for (i = 0; i < MASU; i++) printf("[%2d]", i + 1); printf("\n"); for (i = 0; i < MASU; i++) printf("[%c]\n", 'A' + i); for (i = 0; i < MASU; i++) { for (j = 0; j < MASU; j++) { if (ban[i][j] == 1) { Locate(j * 4 + 4, i + 1); printf("○"); } if (ban[i][j] == 2) { Locate(j * 4 + 4, i + 1); printf("×"); } } } return 0; }
勝敗を判定するメンバ関数です。縦、横、対角線のいずれかに 石が一列に並んだらその人の勝ちです。これも、当然MASUに依存します。 勝敗を決定する原理については前章 や、C言語編第65章を参照してください。int Ban::judge() //戻り値 1:先手の勝ち 2:後手の勝ち 0:勝敗はまだ { int i, j, rseki[MASU], rwa[MASU], cseki[MASU], cwa[MASU]; int cross1seki = 1, cross1wa = 0, cross2seki = 1, cross2wa = 0; // 配列の初期化 for (i = 0; i < MASU; i++) { rseki[i] = 1; rwa[i] = 0; cseki[i] = 1; cwa[i] = 0; } for (i = 0; i < MASU; i++) { for (j = 0; j < MASU; j++) { rseki[i] = rseki[i] * ban[i][j]; rwa[i] = rwa[i] + ban[i][j]; cseki[i] = cseki[i] * ban[j][i]; cwa[i] = cwa[i] + ban[j][i]; } cross1seki = cross1seki * ban[i][i]; cross1wa = cross1wa + ban[i][i]; cross2seki = cross2seki * ban[MASU - 1 - i][i]; cross2wa = cross2wa + ban[MASU - 1 - i][i]; } for (i = 0; i < MASU; i++) { if (rseki[i] != 0 && rwa[i] == MASU) return 1; if (rseki[i] != 0 && rwa[i] == MASU * 2) return 2; if (cseki[i] != 0 && cwa[i] == MASU) return 1; if (cseki[i] != 0 && cwa[i] == MASU * 2) return 2; } if (cross1seki != 0 && cross1wa == MASU) return 1; if (cross1seki != 0 && cross1wa == MASU * 2) return 2; if (cross2seki != 0 && cross2wa == MASU) return 1; if (cross2seki != 0 && cross2wa == MASU * 2) return 2; return 0; }
main関数に変更はありません。int main() { Ban MyBan; MyBan.putStone(); return 0; }
Update Jun/10/2001 By Y.Kumei