Gobang ai: The idea and implementation of the minimax search and α-β pruning algorithm (qt and c++) (1) Introduction and interface design

Source code

GitHub: Github livingsu/Gobang-ai: Minimax search and α-β pruning

introduction

The news that alphaGo defeated Go champion Lee Sedol made me very interested in chess games. I can’t help but don’t know how to go, but I am a gobang amateur, so I hope to learn about related algorithms and knowledge by implementing a gobang ai.

Gobang is also called Gobang in English, five-in-row, and there are two other titles: gomoku and renju (renju). Let me briefly introduce the difference. Since Gobang has been strictly proved by the machine to be an " unfair " game, the first black player is absolutely dominant, and the first player has a winning routine . Since the first hand must win, certain rules must be imposed on the first hand, so there is a "forbidden hand", that is, some positions (such as the formation of double live 3, live 3 punch 4) sunspots cannot be played, otherwise the sunspots lose . In Japan, the theory of gomoku has been greatly developed. Gomoku with forbidden hand rules is called "renju", and the gomoku with no forbidden hand rules is generally called gomoku. Since most ordinary people play gomoku only for fun, and do not need to study the theoretical rules in depth, gomoku is very popular among students (I often played gomoku with my classmates in my second year of high school, and I learned some routines but didn't go deep. ).

The Gobang ai that I have implemented has no banned hands rules (considering the banned hands are too complicated...), the standard board size is 15-15, and the rule is that the blacks play first*. Because the blacks are dominant, I usually hold the blacks. ai holds the white child. I said before that sunspots are absolutely dominant and have certain winning routines, so when the realized ai with no forbidden hand rules is the back hand, if people use the winning routine, ai will definitely lose. But we amateur players don't have to think about these. My goal is to achieve an ai that can defeat most ordinary people in the lead. So, don't be too surprised if you can beat the ai implemented according to my blog.

The effect diagram achieved is shown below.
Double (player) mode:
Insert picture description here
man-machine (ai) mode:
Insert picture description here

interface design

The interface design of qt is very convenient. The widget class is the initial welcome interface. There are two buttons to select player mode or ai mode. The gameWidget class is used to draw chessboards, chess pieces, scores, etc., and needs to respond to mouse events in order to place the pieces. Since the ai I wrote needs to view the chessboard information repeatedly, I put the chessboard in the chessAi class as a public member, and gameWidget can access the chess information and draw by visiting ai.chesses.

The realization of important effects:
1. Shield the mouse cursor when inside the chessboard. When the mouse is near a position where you can place a piece, a small square with a color (which side) is displayed at that position to indicate the cursor, and the mouse cannot be placed at a certain position. The forbidden cursor is displayed when the position of the drop is near.

There are members in the gameWidget class:

    int cursorRow;//光标位置
    int cursorCol;

Then rewrite the mouse movement function:

void gameWidget::mouseMoveEvent(QMouseEvent *event){
    
    
    if(event->x()>=5&&event->x()<=455&&event->y()>=5&&event->y()<=455){
    
    //5=20-15,455=20+14*30+15
        setCursor(Qt::BlankCursor);
        for(int i=0;i<15;++i)
            for(int j=0;j<15;++j){
    
    
                float x=event->x(),y=event->y();
                //判断鼠标落在哪一个点附近(正方形范围)
                if((x>=(chessboard[i][j].x()-15))&&(x<(chessboard[i][j].x()+15))&&
                   (y>=(chessboard[i][j].y()-15))&&(y<(chessboard[i][j].y()+15))){
    
    
                    cursorRow=j;
                    cursorCol=i;
                    if(ai.chesses[cursorRow][cursorCol]!=C_NONE)
                        setCursor(Qt::ForbiddenCursor);

                    //展示图标坐标
                    QString str="坐标:";
                    str+=QString::number(j);
                    str+=",";
                    str+=QString::number(i);
                    if(turn==T_BLACK)ui->lb_black_position->setText(str);
                    else ui->lb_white_position->setText(str);
                    break;
                }
            }
    }
    else setCursor(Qt::ArrowCursor);
    update();
}

To explain, the position of the upper left point of the chessboard is (20,20), and the length of each square of the chessboard is 30. Use a square area (the side length is also 30) to judge where the mouse is near. Set the mouse cursor with setCursor().

There is a problem to pay attention to: the monitoring mouse movement function is turned off by default , and it needs a mouse click to turn it on. In order to avoid this problem, you only need to add setMouseTracking(true) to the gameWidget constructor.

    setMouseTracking(true);//不用点击鼠标也一直追踪 

2. Since both the player and ai have to play chess, a function oneChessMove() can be used to write a simulated move:

void gameWidget::oneChessMove(int row, int col){
    
    
    if(turn==T_BLACK){
    
    
        turn=T_WHITE;
        ai.chesses[row][col]=C_BLACK;
    }
    else{
    
    
        turn=T_BLACK;
        ai.chesses[row][col]=C_WHITE;
    }

    gameResult result=ai.evaluate(ai.chesses).result;

    QMessageBox msg;
    msg.setIcon(QMessageBox::Critical);
    msg.setStandardButtons(QMessageBox::Yes);
    if(result!=R_DRAW){
    
    
        status=FINISH;
        if(result==R_BLACK){
    
    
            msg.setText("黑棋赢");
            score_black++;
        }
        else {
    
    
            msg.setText("白棋赢");
            score_write++;
        }
        msg.exec();

        ui->lcd_black->display(score_black);
        ui->lcd_write->display(score_write);
    }
    else if(isDeadGame()){
    
    
        status=FINISH;
        msg.setText("平局");
        msg.exec();
    }
    update();
}

3. Get the player's position:
rewrite the mouse release function:

void gameWidget::mouseReleaseEvent(QMouseEvent *event){
    
    
    if(mode==PLAYER){
    
    
        if(chessOneByPlayer()){
    
    
            if(status==FINISH)initializeGame();
        }
    }else{
    
    
        if(chessOneByPlayer()){
    
    
            if(status==UNDERWAY){
    
    
                chessOneByAi();
                if(status==FINISH)initializeGame();
            }
            else initializeGame();
        }
    }
}

Among them, chessOneByPlayer() uses the current cursorRow and cursorCol to take a move.

bool gameWidget::chessOneByPlayer(){
    
    
    if(ai.chesses[cursorRow][cursorCol]==C_NONE){
    
    
        oneChessMove(cursorRow,cursorCol);
        return true;
    }
    return false;
}

end

The interface is simply implemented, but the outcome judgment and ai have not yet been implemented. I put the outcome judgment into the evaluation function of ai.

Next post: Gobang ai: Ideas and implementation of minimax search and α-β pruning algorithm (qt and c++) (2) Greedy algorithm and evaluation function

Guess you like

Origin blog.csdn.net/livingsu/article/details/104536005