第65章 勝敗を判定する


今回は前章で作ったプログラムに勝敗を判定する機能を付け加えます。 縦、横、斜めいずれか1列に自分の石を並べると勝ちです。



左の図のように、勝者が出るとその旨表示してゲームを終了します。

(と、いっても先手が間違えなければ必ず勝つことになっていますが・・・)



勝敗の判定はどのようにすればよいのでしょうか。

いろいろな考えがあると思いますが、簡単な方法は縦、横、対角線の それぞれについてban[x][y]の和と積を求めます。何も置かれていないと 0、先手が置かれていると1、後手だと2が代入されています。 すべて1が代入されていると和は3となります。すべて2が代入 されていると6となります。和だけで判定すると0,1,2のような場合 和は3となり先手の勝ちと誤判定されてしまいます。そこで積を 調べて0になればまだ、置かれていない場所があるとわかります。 積が0でなくて和が3であれば先手、積が0でなくて和が6であれば 後手の勝ちとなります。

こうしておくとマス目の数が増えても応用できそうですね。

では、プログラムを見てみましょう。

// game02.c #include <windows.h> #include <stdio.h> int banshow(HANDLE); int Locate(HANDLE, int, int); int check_location(int, int); //すでに駒がおかれていないかどうか調べる int judge(); int ban[3][3]; int main() { HANDLE hOut; BOOL bOrd = TRUE; //FALSE:後手 TRUE:先手 int i, row =0, col=0, jud; char location[8]; //位置指定 A2, B1,など char *sente = "先手", *gote = "後手"; char order[8], hantei[16]; hOut = GetStdHandle(STD_OUTPUT_HANDLE); banshow(hOut); for (i = 0; i < 9; i++) { if (bOrd) strcpy(order, sente); else strcpy(order, gote); INP: Locate(hOut, 28, 5); printf(" "); Locate(hOut, 0, 5); printf("位置を指定してください(%s)", order); gets(location); if (location[0] == 'A' || location[0] == 'a') row = 0; else if (location[0] == 'B' || location[0] == 'b') row = 1; else if (location[0] == 'C' || location[0] == 'c') row = 2; else if (location[0] == 'Q' || location[0] == 'q') break; else { Locate(hOut, 0, 6); printf("指定が違います"); goto INP; } if (location[1] == '1') col = 0; else if (location[1] == '2') col = 1; else if (location[1] == '3') col = 2; else { Locate(hOut, 0, 6); printf("指定が違います"); goto INP; } if (check_location(row, col) != 0) { Locate(hOut, 0, 6); printf("そこには置けません!"); goto INP; } if (bOrd) ban[row][col] = 1; else ban[row][col] = 2; bOrd = !bOrd; banshow(hOut); Locate(hOut, 0, 6); printf(" "); jud = judge(); switch (jud) { case 0: strcpy(hantei, ""); break; case 1: strcpy(hantei, "先手の勝ち"); break; case 2: strcpy(hantei, "後手の勝ち"); break; default: strcpy(hantei, "内部エラー"); break; } Locate(hOut, 0, 7); printf(hantei); if (jud != 0) break; } if (jud == 0) { printf("引き分けです"); } printf("\n\n"); return 0; }

main関数の最後の方のjud = judge();以下が増えました。

judの値によって勝者の表示を変えます。0ならまだ勝敗が決まっていません。

int banshow(HANDLE hStdOut) { int i, j; Locate(hStdOut, 0, 0); printf(" [1][2][3]\n"); printf("[A]\n"); printf("[B]\n"); printf("[C]\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (ban[i][j] == 1) { Locate(hStdOut, j * 4 + 4, i + 1); printf("○"); } if (ban[i][j] == 2) { Locate(hStdOut, j * 4 + 4, i + 1); printf("×"); } } } return 0; } int Locate(HANDLE hOut, int x, int y) { COORD dwPos; dwPos.X = (SHORT)x; dwPos.Y = (SHORT)y; if (SetConsoleCursorPosition(hOut, dwPos) == 0) return -1; else return 0; } int check_location(int row, int col) { if (ban[row][col] == 0) return 0; else return -1; }

この部分は前章と同じです。

int judge() //戻り値 1:先手の勝ち 2:後手の勝ち 0:勝敗はまだ { int i, j, rseki[3], rwa[3], cseki[3], cwa[3]; int cross1seki = 1, cross1wa = 0, cross2seki = 1, cross2wa = 0; // 配列の初期化 for (i = 0; i < 3; i++) { rseki[i] = 1; rwa[i] = 0; cseki[i] = 1; cwa[i] = 0; } for (i = 0; i < 3; i++) { for (j = 0; j < 3; 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[2 - i][i]; cross2wa = cross2wa + ban[2 - i][i]; } for (i = 0; i < 3; i++) { if (rseki[i] != 0 && rwa[i] == 3) return 1; if (rseki[i] != 0 && rwa[i] == 6) return 2; if (cseki[i] != 0 && cwa[i] == 3) return 1; if (cseki[i] != 0 && cwa[i] == 6) return 2; } if (cross1seki != 0 && cross1wa == 3) return 1; if (cross1seki != 0 && cross1wa == 6) return 2; if (cross2seki != 0 && cross2wa == 3) return 1; if (cross2seki != 0 && cross2wa == 6) return 2; return 0; }

ちょっとごちゃごちゃしていますが、iに0, 1, 2を代入して考えてみるとわかりやすいです。

i = 0の時

rseki[0] = ban[0][0] * ban[0][1] * ban[0][2]
rwa[0] = ban[0][0] + ban[0][1] + ban[0][2]
cseki = ban[[0][0] * ban[1][0] * ban[2][0]
cwa = ban[[0][0] * ban[1][0] * ban[2][0]

となります。このように考えていくとわかると思います。

さて、碁盤が3*3ではおもしろくないので、拡張してみてください。 また、判定も非常に能率の悪い方法です。改良してみてください。


[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Apr/14/2001 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。