ソースコード
GitHub:Github livingsu / Gobang-ai:ミニマックス検索とα-β剪定
前書き
alphaGoが囲碁チャンピオンの李世ドルを破ったというニュースで、チェスゲームにとても興味を持ちました。どうしようもありませんが、囲碁のアマチュアなので、実装して関連するアルゴリズムや知識を学びたいと思っています。囲碁愛。
五目並べは英語では五目並べとも呼ばれ、五目並べと連珠(連珠)の2つのタイトルがあります。違いを簡単に紹介します。Gobangはマシンによって「不公平」なゲームであることが厳密に証明されているため、最初の黒人プレーヤーが絶対的に支配的であり、最初のプレーヤーが勝利ルーチンを持っています。直接勝つ必要があるため、特定のルールを直接課す必要があります。そのため、「禁止された手」があります。つまり、一部の位置(ダブルライブ3、ライブ3パンチ4の形成など)の黒点は再生できません。そうでなければ、黒点は失われます。日本では、五目並べの理論が大きく発展しました。禁止された手のルールがある五目並べは「連珠」と呼ばれ、禁止された手のルールがない五目並べは一般に五目並べと呼ばれます。ほとんどの一般の人々は楽しみのためだけに五目並べをプレイし、理論的なルールを深く研究する必要がないため、五目並べは学生の間で非常に人気があります(私は高校2年生でクラスメートと五目並べをよくプレイし、いくつかのルーチンを学びましたが深くは行きませんでした。)
私が実装したGobangaiには禁止ハンドルールがなく(禁止ハンドが複雑すぎることを考慮して...)、標準のボードサイズは15〜15で、ルールは黒が最初にプレイすることです*。黒が支配的であるため、私は通常黒人を保持します。aiは白人の子供を保持します。黒点が絶対的に支配的で、特定の勝利ルーチンがあることを前に言いました。したがって、禁止されたハンドルールのない実現されたaiがバックハンドである場合、人々が勝利ルーチンを使用すると、aiは間違いなく負けます。しかし、私たちアマチュアプレイヤーはこれらについて考える必要はありません。私の目標は、ほとんどの一般の人々をリードすることができるaiを達成することです。だから、私のブログに従って実装されたaiを打ち負かすことができても、それほど驚かないでください。
達成された効果図を以下に示します。
ダブル(プレイヤー)モード:
マンマシン(ai)モード:
インターフェイスデザイン
qtのインターフェースデザインはとても便利です。ウィジェットクラスは最初のウェルカムインターフェイスです。プレーヤーモードまたはaiモードを選択するための2つのボタンがあります。gameWidgetクラスは、チェス盤、チェスの駒、スコアなどを描画するために使用され、駒を配置するためにマウスイベントに応答する必要があります。私が書いたaiはチェス盤の情報を繰り返し表示する必要があるため、チェス盤をパブリックメンバーとしてchessAiクラスに配置し、gameWidgetはai.chessesにアクセスしてチェスの情報にアクセスして描画することができます。
重要な効果の実現:
1。チェス盤の内側でマウスカーソルをシールドします。マウスが駒を置くことができる位置に近づくと、その位置に色付きの小さな正方形(どちら側)が表示され、カーソルを示します。 、および特定の位置にマウスを置くことができません。ドロップの位置が近い場合、禁止カーソルが表示されます。
gameWidgetクラスには次のメンバーがいます。
int cursorRow;//光标位置
int cursorCol;
次に、マウス移動関数を書き直します。
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();
}
説明すると、チェス盤の左上の点の位置は(20,20)であり、チェス盤の各正方形の長さは30です。正方形の領域(辺の長さも30)を使用して、マウスがどこにあるかを判断します。setCursor()でマウスカーソルを設定します。
注意すべき問題があります:マウスの動きの監視機能はデフォルトでオフになっており、オンにするにはマウスをクリックする必要があります。この問題を回避するには、gameWidgetにsetMouseTracking(true)を追加するだけです。コンストラクタ。
setMouseTracking(true);//不用点击鼠标也一直追踪
2.プレーヤーとaiの両方がチェスをしなければならないので、関数oneChessMove()を使用してシミュレートされた動きを書くことができます。
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.プレーヤーの位置を取得します。
マウスリリース機能を書き直します。
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();
}
}
}
その中で、chessOneByPlayer()は現在のcursorRowとcursorColを使用して移動します。
bool gameWidget::chessOneByPlayer(){
if(ai.chesses[cursorRow][cursorCol]==C_NONE){
oneChessMove(cursorRow,cursorCol);
return true;
}
return false;
}
終わり
インターフェースは単純に実装されていますが、結果の判断とaiはまだ実装されていません。結果の判断をaiの評価関数に入れます。
次の投稿:Gobang ai:ミニマックス検索とα-βプルーニングアルゴリズム(qtおよびc ++)のアイデアと実装(2)欲張りアルゴリズムと評価関数