1. 程式人生 > >QT五子棋專案詳解之四:AI人機對戰max-min極大極小值博弈演算法

QT五子棋專案詳解之四:AI人機對戰max-min極大極小值博弈演算法

不考慮博弈的演算法怎麼能算是AI呢?

max-min極大極小值演算法就是考慮了博弈的演算法。

來看一個簡單的例子


在這個棋局中,電腦為白旗,白旗走哪一步更好呢,也許使用策略表會告訴你,應該衝4,但是衝4後,玩家就會連成4。

這就是考慮了博弈之後,這一步棋就是敗局。這就是為什麼有max-min演算法。也理所當然應該這樣。


現在我們考慮兩層的情況:

這一步,應該電腦走了,電腦現在有3種走法,A,B,C 。

當電腦走A後,玩家有D,E兩個位置可以走。  當電腦走B後,玩家有F,G兩個位置可以走......


如果一個電腦可以看到兩步以後的棋,就和普通人一樣。又假定電腦對整個棋盤的局勢有了自己的判斷。那麼在兩步棋之後,電腦判斷了整個棋盤的局勢,如下圖:得分越大,對於電腦越有利。電腦就會想了,我下哪一步好呢。電腦應該下C嗎?因為I的得分為6.當然不是了,因為當電腦選擇下C時,玩家會選擇下H,下這一步對玩家最不利的棋。當電腦選擇下A時,玩家會選擇下E,下這一步對玩家最不利的棋。所以,對於A,B,C三個節點來說


所以,對於A,B,C三個節點來說,電腦就已經對他們進行了打分,所以,電腦最後會走3這個點。


這就是max-min演算法,一個很簡單的東西,我就沒看到有人把它說清楚過。

明白了這一點,就知道需要幹嘛了。

1、需要計算出電腦可以走哪些棋。

2、有一個好的評價局勢的函式來評估分數

實現如下,如果你遞迴都還沒搞懂,就不要看了:

//2018年3月9日15:54:16——March 9, 2018 15:54:16
//追夢少年 QQ:1131052403 —— Dreamer QQ : 1131052403 
//開源的狂熱愛好者,程式碼風騷,效率恐怖 —— Open source enthusiasts, code coquettish, efficient horror

QPointGame::maxmin2(intdeep)
{
intbest=INT_MIN;
QVector<QPoint>points=gen(deep,computerColor); //可以走哪些點
for(inti=0;i<points.count();i++)  //每個點都走
{
chess[points[i].x()][points[i].y()]=computerColor;//下棋
intv=min2(deep-1,points[i]);
if(v==best) //分數最大的
{
bestpoints.push_back(points[i]);
}
if(v>best)  //找到最大的
{
best
=v;
bestpoints.clear();
bestpoints.push_back(points[i]);
}
chess[points[i].x()][points[i].y()]=0; //清除
}
srand((unsigned)time(NULL));
points.clear();
returnbestpoints[rand()%bestpoints.count()];
}
intGame::max2(intdeep,QPointpoint)
{
if(deep<=0||ifWin(point.x(),point.y()))
{
intk=evalute();
returnk;
}
intbest=INT_MIN;
QVector<QPoint>points=gen(deep,computerColor);
for(inti=0;i<points.count();i++)
{
chess[points[i].x()][points[i].y()]=computerColor;
intv=min2(deep-1,best>alpha?best:alpha,beta,points[i]);
if(v>best)
{
best=v;
}
chess[points[i].x()][points[i].y()]=0;
}
points.clear();
returnbest;
}
intGame::min2(intdeep,QPointpoint)
{
if(deep<=0||ifWin(point.x(),point.y()))
{
intk=evalute();
returnk;
}
intbest=INT_MAX;
QVector<QPoint>points=gen(deep,computerColor==4?5:4);
for(inti=0;i<points.count();i++)
{
chess[points[i].x()][points[i].y()]=computerColor==4?5:4;
intv=max2(deep-1,points[i]);
if(v<best)
{
best=v;
}
chess[points[i].x()][points[i].y()]=0;
}
points.clear();
returnbest;
}

總結:1、知道我為什麼要clear QT中的vector嗎,因為我發現這丫的要記憶體洩露,程式一直崩潰找不到原因,最後發現是記憶體洩露了。

2、一個經驗之談,vector裡面不要存實體,儘量存指標,不然你會很苦逼。

3、這段比較簡潔的max-min函式的實現,對遞迴的要求是很高的,如果你不精通遞迴,你膽子大可以寫個堆疊的。

4、最難的是評估局勢。

5、關於能夠搜尋到的層數,現在最多也就能搜尋到4層。