おふとんガレージ

技術的なことの忘備録とか

OpenGL入門 3日目

前回までの作業内容

  • ウィンドウ、初期盤面生成
  • クリック箇所の座標読み込み、盤上の座標への変換

今回の作業内容

  • 石を置けるかの判定実装
  • 石を置いた後の反転実装

作業内容詳細

  • checkFrip()
    • 打ち込まれた点から1方向に向け石が反転可能か判定する。
  • check()
    • 全方向に向けcheckFrip()関数を実行、その場所に石が置けるかの判定を行う。
  • frip()
    • 石の反転を行った後に画面描画を実行する。

とりあえずオセロとして最低限の機能は実装できました。
現状だと石を打てる場所がない場合の判定が未実装なのでパスが出るとゲームが進行不能になるので、そのへんの効率の良い探索法を考える必要がありそうです。
あとは石を打てるか→反転までの流れがかなり無駄が多いのでそのへんのコードを一度整理する必要が。

何はともあれ、前半の山場は超えたので次回はパスの判定と処理、ゲーム終了時の結果表示及び初期盤面へのリセットを実装したいところ。がんばる。

#include <iostream>
#include <GLUT/GLUT.h>

#define BOARD_SIZE 8
#define NONE 0
#define BLACK 1
#define WHITE 2

using namespace std;
int screenWidth = 800, screenHeight = 800, turn = 0;
char board[BOARD_SIZE][BOARD_SIZE];

int dirX[] = {-1, 0, 1, -1, 1, -1, 0, 1};
int dirY[] = {-1, -1, -1, 0, 0, 1, 1, 1};

int checkFlip(int x, int y, int turn, int vec){
	int flag = 0;
    
	while(true){
        x += dirX[vec];
		y += dirY[vec];
		
            //ボード端到達時の処理
		if( x < 0 || y < 0 || x > BOARD_SIZE - 1 || y > BOARD_SIZE - 1) return 0;
            //空白マス到達時の処理
		if(board[x][y] == NONE) return 0;
		
		if(board[x][y] == (turn % 2 ? BLACK : WHITE)){
			//相手のコマが隣接→同方向へ再度探索
			flag = 1;
			continue;
		}
		
		if(flag == 1 && board[x][y] == (turn % 2 ? WHITE : BLACK)) break;
		return 0;
	}
	//同方向に相手の駒が隣接し、なおかつ石を裏返すことが出来る場合
    cout << "Frip : OK" << endl;
	return 1;
}

int check(int x, int y, int turn){
	int vec;
	//8方向へ探索し、ひっくり返せる場合に1を返す
	for(vec = 0 ; vec < 8 ; vec++){
		if(checkFlip(x, y, turn, vec) == 1) return 1;
	}
	return 0;
}



void showStone(){
    //盤面に配置された石の描画
    glPointSize(60);
    for(int i = 0; i < BOARD_SIZE; i++){
        for(int j = 0; j < BOARD_SIZE; j++){
            if(board[i][j] == BLACK){
                //黒石の描画
                glColor3d(0, 0, 0);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }else if(board[i][j] == WHITE){
                //白石の描画
                glColor3d(1, 1, 1);
                glBegin(GL_POINTS);
                glVertex2i(120 + 80 * i, 120 + 80 * j);
                glEnd();
            }
        }
    }
}

void frip(int x, int y, int color, int vec){
    while(true){
        x += dirX[vec];
        y += dirY[vec];
        
        if(board[x][y] == NONE) break;
        if( x < 0 || y < 0 || x > BOARD_SIZE - 1 || y > BOARD_SIZE - 1) break;
        
        if(color == BLACK){
            if(board[x][y] == BLACK) break;
            cout << "frip:BLACK " << x << " " << y << endl;
            board[x][y] = BLACK;
        }else{
            if(board[x][y] == WHITE) break;
            cout << "frip:WHITE " << x << " " << y << endl;
            board[x][y] = WHITE;
        }
        
        showStone();
        glFlush();
    }
}


void mouse(int button, int state, int x, int y){
    int i = 0, j = 0, flag = 0;
    cout << "turn : " << turn << endl;
    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
        
        cout << "(x, y) == (" << x << "," << y << ")" << endl;
        
        if(x < 80 || x > 720) return;
        if(y < 80 || y > 720) return;
        
        while(x > 80){
            x -= 80;
            i++;
        }
        
        while(y > 80){
            y -= 80;
            j++;
            
        }
                

        if(board[i - 1][j - 1]) return;
        
        if(turn % 2 == 1){
            if(check(i - 1, j - 1, turn)){
                cout << "turn:WHITE " << i << " " << j << endl;
                board[i - 1][j - 1] = WHITE;
                
                for(int vec = 0; vec < 8; vec++){
                    if(checkFlip(i - 1, j - 1, turn, vec)){
                        frip(i - 1, j - 1, WHITE, vec);
                    }
                }
                turn++;
            }
        }else{
            if(check(i - 1, j - 1, turn)){
                cout << "turn:BLACK " << i << " " << j << endl;
                board[i - 1][j - 1] = BLACK;
                
                for(int vec = 0; vec < 8; vec++){
                    if(checkFlip(i - 1, j - 1, turn, vec)){
                        frip(i - 1, j - 1, BLACK, vec);
                    }
                }
                turn++;
            }
        }
        
        showStone();
        glFlush();
    }
    
}

void display(){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    //盤面のマス目作成
    glColor3d(0.0, 0.0, 0.0);
    glLineWidth(3);
    glBegin(GL_LINES);
    
    for(int i = 0; i <= BOARD_SIZE; i++){
        glVertex2i(80 + 80 * i, 720);
        glVertex2i(80 + 80 * i, 80);
        
        glVertex2i(80, 80 + 80 * i);
        glVertex2i(720, 80 + 80 * i);
    }
    glEnd();
    
    //盤面上の4点の描画
    glColor3d(0.0, 0.0, 0.0);
    glPointSize(10);
    glBegin(GL_POINTS);
        glVertex2i(240, 240);
        glVertex2i(240, 560);
        glVertex2i(560, 240);
        glVertex2i(560, 560);
    glEnd();
    
    showStone();
    glFlush(); //描画実行
    
    
}

void initialize(){
    //初期盤面生成
    glClearColor(0, 0.5, 0, 1); //背景色設定
    
    //以下石の初期配置
    for(int i; i < BOARD_SIZE * BOARD_SIZE; i++)
        board[i / BOARD_SIZE][i % BOARD_SIZE] = NONE;
    
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2] = BLACK;
    board[BOARD_SIZE / 2][BOARD_SIZE / 2 - 1] = BLACK;
    
    board[BOARD_SIZE / 2][BOARD_SIZE / 2] = WHITE;
    board[BOARD_SIZE / 2 - 1][BOARD_SIZE / 2 - 1] = WHITE;
}

int main(int argc, char* argv[]) {
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(screenWidth, screenHeight);
    
    glutCreateWindow("Othello");
    gluOrtho2D(0, 800, 800, 0); //座標系指定
    initialize();

	glutMouseFunc(mouse);
    glutDisplayFunc(display);
    glutMainLoop();
    
    return 0;
}