在我們的五子棋游戲中,黑白兩方輪流下子,會產生不同的棋盤局面。對於一個局面來講又有不同的應對方法,不同的應對方法,接着又會產生不同的局面。
也就是說黑方先下子,白方就有224種落子方法,如果黑方選擇了一其中的一步應對,那白方接下來就有223種方案和223種局面。
這樣看就是一個又一個的樹,但是在一個五子棋游戲里面博弈樹的全部遍歷有10的41次方個局面,所以我們基本上就是設定一個深度就不在搜索了,用一個評估函數對局勢進行判斷,用估計值來代替實際的搜索值。而且搜索算法用的就是極大極小的搜索來減少我們搜索的工作量。我們可以把一個五子棋的走步看成,黑方的節點估計值對標乙方子節點的最大值確定,同時乙方從葉節點選的就是越小越對它有利,兩者倒退就可以退出根節點的估計值,這樣就可以確定根節點的出發的最佳走步。同時為了減少搜索量,將葉節點的評估,跟就算倒退值與樹的生成同時進行。就可以減少搜索的數量,還可以保持效果的不便。
//---------搜索當前搜索狀態極大值--------------------------------//
//alpha 祖先節點得到的當前最小最大值,用於alpha 剪枝
//beta 祖先節點得到的當前最大最小值,用於beta 剪枝。
//step 還要搜索的步數
//return 當前搜索子樹極大值
protected int findMax(int alpha, int beta, int step) {//只有極小值的方法調用了這里
int max = alpha;
if (step == 0) {
return evaluate();
}
int[][] rt = getBests(1 - sbw);
for (int i = 0; i < rt.length; i++) {
int x = rt[i][0];
int y = rt[i][1];
if (getType(x, y, 1 - sbw) == 1) //電腦可取勝
return 100 * ( getMark(1) + step*1000 );
isChessOn[x][y] = 1 - sbw;
// 預存當前邊界值
int temp1=x_min,temp2=x_max,temp3=y_min,temp4=y_max;
resetMaxMin(x,y);
int t = findMin(max, beta, step - 1);
isChessOn[x][y] = 2;
// 還原預設邊界值
x_min=temp1;
x_max=temp2;
y_min=temp3;
y_max=temp4;
if (t > max)
max = t;
//beta 剪枝
if (max >= beta)
return max;
}
return max;
}
//-----------------------搜索當前搜索狀態極小值---------------------------------//
//alpha 祖先節點得到的當前最小最大值,用於alpha 剪枝
//beta 祖先節點得到的當前最大最小值,用於beta 剪枝
//step 還要搜索的步數
//return 當前搜索子樹極小值。
protected int findMin(int alpha, int beta, int step) {
int min = beta;
if (step == 0) {
return evaluate();
}
int[][] rt = getBests(sbw);
for (int i = 0; i < rt.length; i++) {
int x = rt[i][0];
int y = rt[i][1];
int type = getType(x, y, sbw);
if (type == 1) //玩家成5
return -100 * ( getMark(1) + step*1000 );
// 預存當前邊界值
int temp1=x_min,temp2=x_max,temp3=y_min,temp4=y_max;
isChessOn[x][y] = sbw;
resetMaxMin(x,y);
int t = findMax( alpha, min, step - 1 );
isChessOn[x][y] = 2;
// 還原預設邊界值
x_min=temp1;
x_max=temp2;
y_min=temp3;
y_max=temp4;
if (t < min)
min = t;
//alpha 剪枝
if (min <= alpha) {
return min;
}
}
return min;
}