ここ数回にわたって 定数化や if文等の判定に 複数の条件を指定する方法をお話ししてきました。
リバーシのプログラムにこれらの内容を反映し、より読みやすいプログラムへとしてみましょう。
#include <stdio.h>
/**********************************
* 定数宣言
*********************************/
// 盤面の幅
const int WIDTH = 8;
// 盤面の高さ
const int HEIGHT = 8;
// 駒の状態 無し
const int EMPTY = 0;
// 駒の状態 黒
const int BLACK = 1;
// 駒の状態 白
const int WHITE = -1;
// 関数成功判定 成功
const int OK = 0;
// 関数成功判定 失敗
const int NG = 1;
/**********************************
* グローバル変数宣言
*********************************/
// 盤面
int table[ WIDTH ][ HEIGHT ];
// 現在のターン
int turn = BLACK;
/**********************************
* 関数プロトタイプ宣言
*********************************/
void nextTurn();
int isEnd();
int put();
int turnItem( int x, int y );
void drawTurn();
void draw();
void result();
///////////////////////////
// main() 関数
// プログラム本体
///////////////////////////
int main(){
// 盤面をすべて 0(何も置かれていない) で初期化します。
for(int x=0; x<WIDTH; x++){
for(int y=0; y<HEIGHT; y++){
table[x][y] = EMPTY;
}
}
// センターの黒と白を配置します。
table[3][3] = BLACK;
table[4][4] = BLACK;
table[3][4] = WHITE;
table[4][3] = WHITE;
// ゲームが終了するまでループします。
while( isEnd() == NG ){
// 盤面を表示します。
draw();
// 現在 黒(1P)の番か白(2P)の番かを表示します。
drawTurn();
// 駒を配置する場所を選択させます。
if( put() == OK ){
// 黒(1P)と白(2P)の順番を入れ替えます。
nextTurn();
}else{
printf( "そこには置けません\nもう一度選択してください。\n" );
}
}
// 結果を表示。
result();
return 0;
}
///////////////////////////
// nextTurn() 関数
// ターンを入れ替えます
///////////////////////////
void nextTurn(){
turn = -turn;
}
///////////////////////////
// isEnd() 関数
// ゲームが終了しているかを判定します。
// ゲームが終了していれば OK を返し、
// まだ終了していなければ NG を返します。
///////////////////////////
int isEnd(){
for(int x=0; x<WIDTH; x++){
for(int y=0; y<HEIGHT; y++){
if( table[x][y] == 0 ){
return NG;
}
}
}
return OK;
}
///////////////////////////
// put() 関数
// 駒を置く位置を入力させます。
// 駒を置ける位置への入力があった場合は 0 を、
// 駒を置けない位置への入力があった場合は 1 を返します。
///////////////////////////
int put(){
int x, y;
// 駒を置くX座標の入力を受け付けます
printf( "駒を置くX座標 ... " );
scanf( "%d", &x );
if( x < 0 || x >= WIDTH ){
return NG;
}
// 駒を置くY座標の入力を受け付けます
printf( "駒を置くY座標 ... " );
scanf( "%d", &y );
if( y < 0 || y >= HEIGHT ){
return NG;
}
// table 変数を見て置こうとしている場所が 0 でなければ、『1』を返す
if( table[x][y] != EMPTY ){
return NG;
}
// turnItem() 関数に入力された位置を渡して、相手の駒をひっくり返す処理を行います。
if( turnItem( x, y ) == NG ){
// 1枚もひっくり返せなかった場合は、『1』を返す
return NG;
}
table[x][y] = turn;
return OK;
}
///////////////////////////
// turnItem() 関数
// ひっくり返す処理
///////////////////////////
int turnItem( int x, int y ){
const int PARAM_LENGTH = 8;
int returnParamX[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
int returnParamY[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int count = 0;
for(int i=0; i<PARAM_LENGTH; i++){
int tmpX = x + returnParamX[i];
int tmpY = y + returnParamY[i];
for( int j=0; tmpX >= 0 && tmpY >= 0 && tmpX < WIDTH && tmpY < HEIGHT; j++ ){
if( table[tmpX][tmpY] == -turn ){
tmpX += returnParamX[i];
tmpY += returnParamY[i];
}else{
if( table[tmpX][tmpY] == turn ){
tmpX -= returnParamX[i];
tmpY -= returnParamY[i];
while( tmpX != x || tmpY != y ){
table[tmpX][tmpY] = turn;
tmpX -= returnParamX[i];
tmpY -= returnParamY[i];
count++;
}
}
break;
}
}
}
if( count == 0 )
return NG;
return OK;
}
///////////////////////////
// drawTurn() 関数
// 現在のターンを表示します
///////////////////////////
void drawTurn(){
if( turn == BLACK ){
printf( "黒(1P)の番です。\n" );
}else if( turn == WHITE ){
printf( "白(2P)の番です。\n" );
}
}
///////////////////////////
// draw() 関数
// 画面に盤面を描画します。
///////////////////////////
void draw(){
for(int y=0; y<HEIGHT; y++){
for(int x=0; x<WIDTH; x++){
switch( table[x][y] ){
case EMPTY:
printf( "□" );
break;
case BLACK:
printf( "●" );
break;
case WHITE:
printf( "○" );
break;
}
}
printf( "\n" );
}
}
///////////////////////////
// result() 関数
// 結果表示
///////////////////////////
void result(){
int result = 0;
for(int x=0; x<WIDTH; x++){
for(int y=0; y<HEIGHT; y++){
result += table[x][y];
}
}
if( result > 0 ){
printf( "黒(1P)の勝ちです。" );
}else if( result < 0 ){
printf( "白(2P)の勝ちです。" );
}else{
printf( "引き分けです。" );
}
}