日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人工智能 > ChatGpt >内容正文

ChatGpt

基于C的α-β剪枝算法实现的AI五子棋游戏

發(fā)布時(shí)間:2023/12/20 ChatGpt 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于C的α-β剪枝算法实现的AI五子棋游戏 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
源碼下載 http://www.byamd.xyz/hui-zong-1/

對(duì)抗問(wèn)題

對(duì)抗問(wèn)題:顧名思義,博弈雙方是帶有對(duì)抗性質(zhì)的。博弈的任何一方都希望局面盡量對(duì)自己有利,同時(shí)局面也應(yīng)該盡量令對(duì)方不利。通常這一類問(wèn)題可以通過(guò) Minimax 算法解決。

Minimax 算法又名極小化極大算法,是一種找出失敗的最大可能性中的最小值的算法。

Minimax 算法常用于棋類等由兩方較量的游戲和程序,這類程序由兩個(gè)游戲者輪流,每次執(zhí)行一個(gè)步驟。

為了執(zhí)行Minimax 算法,我們可以通過(guò)窮舉的方式,枚舉所有的狀態(tài)空間,從而使得我們可以在游戲剛一開(kāi)始,就預(yù)測(cè)到輸贏。

但是,在實(shí)際情況下,游戲的狀態(tài)空間都是異常龐大的。很顯然,我們不能將以窮舉方式實(shí) 現(xiàn)的Minimax 算法用于實(shí)際應(yīng)用。

α-β 減枝

通過(guò)分析可以發(fā)現(xiàn),在利用窮舉方法執(zhí)行 Minimax 算法中有許多的無(wú)效搜索,也就是說(shuō),許多明顯較劣的狀態(tài)分支我們也進(jìn)行搜索了。

我們?cè)谶M(jìn)行極大值搜索的時(shí)候,我們僅僅關(guān)心,下面最大的狀態(tài),對(duì)于任何小于目前值 的分支也都是完全沒(méi)有必要進(jìn)行進(jìn)一步檢查的。(α 減枝)

通過(guò)上圖,我們可以發(fā)現(xiàn),我們可以減去大量無(wú)用的狀態(tài)檢查,從而降低我們的運(yùn)算量。

同時(shí),我們?cè)谶M(jìn)行極小值搜索的時(shí)候,我們僅僅關(guān)心,下面最小的狀態(tài),對(duì)于任何大于 目前值的分支都是完全沒(méi)有必要進(jìn)行進(jìn)一步檢查的。(β 減枝)

通過(guò)上圖,我們可以發(fā)現(xiàn),我們可以減去大量無(wú)用的狀態(tài)檢查,從而降低我們的運(yùn)算量。 將上述所提到的 α 減枝與 β 減枝進(jìn)行綜合就可以得到 α-β 減枝。

對(duì)于對(duì)抗搜索而言,我們需要精心設(shè)計(jì)其估值函數(shù),不然我們的 α-β 減枝將毫無(wú)用武之地。

五子棋問(wèn)題

五子棋:**是一種兩人對(duì)弈的純策略型棋類游戲,通常雙方分別使用黑白兩色的棋子,下在棋 盤(pán)直線與橫線的交叉點(diǎn)上,先形成 5 子連線者獲勝。

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-9KrUHl7H-1617337672265)(media/4e9ed78b0312128f30ed0dde6f043b13.jpeg)]

這里,我們采用了極大極小博弈樹(shù)(MGT),來(lái)實(shí)現(xiàn)AI

這里用一張井字棋的搜索示意圖來(lái)說(shuō)明。

上圖很清晰的展示了對(duì)局可能出現(xiàn)的所有情況(已經(jīng)去除了等價(jià)的情況),如果讓這個(gè)圖延展下去,我們就相當(dāng)于窮舉了所有的下法,如果我們能在知道所有下法的情況下,對(duì)這 些下法加以判斷,我們的AI 自然就可以選擇具有最高獲勝可能的位置來(lái)下棋。

極大極小博弈樹(shù)就是一種選擇方法,由于五子棋以及大多數(shù)博弈類游戲是無(wú)法窮舉出所有可能的步驟的(狀態(tài)會(huì)隨著博弈樹(shù)的擴(kuò)展而呈指數(shù)級(jí)增長(zhǎng)),所以通常我們只會(huì)擴(kuò)展有限的層數(shù),而 AI 的智能高低,通常就會(huì)取決于能夠擴(kuò)展的層數(shù),層數(shù)越高,AI 了解的信息就越多, 就越能做出有利于它的判斷。

為了讓計(jì)算機(jī)選擇那些獲勝可能性高的步驟走,我們就需要一個(gè)對(duì)局面進(jìn)行打分的算法, 越有利,算法給出的分?jǐn)?shù)越高。在得到這個(gè)算法過(guò)后,計(jì)算機(jī)就可以進(jìn)行選擇了,在極大極小博弈樹(shù)上的選擇規(guī)則是這樣的:

AI 會(huì)選擇子樹(shù)中具有最高估值葉子節(jié)點(diǎn)的路徑;

USER 會(huì)選擇子樹(shù)中具有最小估值葉子節(jié)點(diǎn)的路徑。

這樣的原則很容易理解,作為玩家,我所選擇的子一定要使自己的利益最大化,而相應(yīng) 的在考慮對(duì)手的時(shí)候,也不要低估他,一定要假設(shè)他會(huì)走對(duì)他自己最有利,也就是對(duì)我最不 利的那一步。

接下來(lái),我們實(shí)現(xiàn)關(guān)鍵的局面評(píng)分步驟:

直接分析整個(gè)棋面是一件很復(fù)雜的事情,為了讓其具備可分析性,我們可以將其進(jìn)行分 解,分解成易于我們理解和實(shí)現(xiàn)的子問(wèn)題。

對(duì)于一個(gè)二維的期面,五子棋不同于圍棋,五子棋的勝負(fù)只取決于一條線上的棋子,所 以根據(jù)五子棋的這一特征,我們就來(lái)考慮將二維的棋面轉(zhuǎn)換為一維的,下面是一種簡(jiǎn)單的思 考方式,對(duì)于整個(gè)棋盤(pán),我們只需要考慮四個(gè)方向即可,所以我們就按照四個(gè)方向來(lái)將棋盤(pán) 轉(zhuǎn)換為 15 * 6 個(gè)長(zhǎng)度不超過(guò) 15 的一維向量(分解斜向的時(shí)候,需要分為上下兩個(gè)半?yún)^(qū)),參考下圖:

我們的目的是為了為其評(píng)分,那么我們就還需要評(píng)估每個(gè)線狀態(tài),將每個(gè)線狀態(tài)的評(píng)分進(jìn)行匯總,當(dāng)做我們的棋面評(píng)分:

接下來(lái)我們所要做的就是評(píng)價(jià)每一條線狀態(tài),根據(jù)五子棋的規(guī)則,我們可以很容易窮舉出各種可能出現(xiàn)的基本棋型,我們首先為這些基本棋型進(jìn)行識(shí)別和評(píng)價(jià), 并且統(tǒng)計(jì)每個(gè)線狀態(tài)中出現(xiàn)了多少種下面所述的棋型,并據(jù)此得出評(píng)價(jià)值,得到如下圖所示的靜態(tài)估值表:

根據(jù)這個(gè)表以及我們之前所談到的規(guī)則,我們就可以得到一個(gè)可以運(yùn)行的AI 了。

進(jìn)一步的優(yōu)化

注意到,如果我們搜索到第四層,總共需要搜索:

224 + 224 * 223 + 224 * 223 * 222 + 224 * 223 * 222 * 221 = 2 461 884 544 個(gè) 狀

態(tài)節(jié)點(diǎn),搜索如此多的狀態(tài)節(jié)點(diǎn)的開(kāi)銷是十分可觀的,因此,我們提高效率的方式就鎖定到了:如何減少需要搜索的狀態(tài)節(jié)點(diǎn)。

我們可以采取以下方法來(lái)減少需要搜索的狀態(tài)節(jié)點(diǎn):

我們可以利用經(jīng)典的α-β剪枝算法對(duì)博弈樹(shù)剪枝。

我們可以每次搜索僅搜索落子點(diǎn)周圍 2*2 格范圍內(nèi)存在棋子的位置,這樣可以避免搜索一些明顯無(wú)用的節(jié)點(diǎn),而且可以大幅度提升整體搜索速度。

避免對(duì)必勝/負(fù)局面搜索,當(dāng)搜索過(guò)程中出現(xiàn)了必勝/負(fù)局面的時(shí)候直接返回不再搜索, 因?yàn)榇藭r(shí)繼續(xù)搜索是沒(méi)有必要的,直接返回當(dāng)前棋局的估價(jià)值即可。

加入隨機(jī)化AI 的下棋方式,普通的AI 算法對(duì)于給定的玩家下棋方式會(huì)給出固定的回應(yīng), 這就導(dǎo)致玩家獲勝一次之后只要此后每次都按此方式下棋,都能夠獲勝。為了避免這種 情況,可以在 AI 選擇下子位置的時(shí)候,在估值相差不多的幾個(gè)位置中隨機(jī)挑選一個(gè)進(jìn)行放置,以此增加AI 的靈活性。

規(guī)劃搜索順序,有很多有價(jià)值的下子點(diǎn)存在于更靠近棋盤(pán)中央的地方,如果從棋盤(pán)中央 向外搜索的話,則能夠提高α-β剪枝的效率,讓盡可能多的分支被排除。

實(shí)驗(yàn)成果

(游戲中間界面)

(游戲中間界面)

實(shí)驗(yàn)總結(jié)

通過(guò)本次實(shí)驗(yàn),加強(qiáng)了組員之間的溝通協(xié)調(diào)能力,同時(shí)也提高了我們對(duì)αβ減枝算法的 了解。我們更了解了五子棋相關(guān)的游戲規(guī)則以及一些技巧,拓寬了我們的知識(shí)面,有助于我 們?cè)谖磥?lái)的生活中更好的與人交流。

同時(shí),經(jīng)過(guò)此次實(shí)驗(yàn),我們深入了解了棋類人工智能算法,進(jìn)一步的提升了我們的專業(yè) 水平,有助于我們?cè)谖磥?lái)的就業(yè)與科研崗位上走的更遠(yuǎn)。

雖然αβ減枝實(shí)現(xiàn)起來(lái)非常容易,但是五子棋的局勢(shì)估計(jì)卻十分的有挑戰(zhàn)性,其局勢(shì)估 計(jì)的準(zhǔn)確與否直接影響了程序的運(yùn)行結(jié)果是否令人滿意,AI 是否能夠展現(xiàn)出足夠的智能。

本次實(shí)驗(yàn),由周宇星(1352652)和蔡樂(lè)文(1353100)完成。其中,周宇星設(shè)計(jì)并完成 了五子棋布局的估價(jià)函數(shù),與蔡樂(lè)文共同完成了αβ減枝算法的研究與實(shí)現(xiàn)。蔡樂(lè)文設(shè)計(jì)并 完成了有關(guān)程序界面以及操作的功能。

源代碼

#include “opencv2/imgproc/imgproc.hpp” #include “opencv2/imgcodecs.hpp”
#include “opencv2/videoio/videoio.hpp” #include “opencv2/highgui/highgui.hpp”

#include <iostream>

#include <iostream> #include <cstdio> #include <cstring> #include
<cstdio> #include <cstdlib> #include <iomanip>

using namespace std; using namespace cv;

//sro 菜神 Orz

cv::Mat chessboard, whiteChess, blackChess, tmp, BGS;

int is_red(Vec3b X) {

// cout << (int)X[1] << ’ ’ << (int)X[2] << ’ ’ << (int)X[3] <<
endl;

return X[0] < 200 && X[1] < 200 && X[2] > 230;

}

cv::Mat BG;

//將棋子復(fù)制到背景畫(huà)面上

void imageCopyToBG(cv::Mat chess, int x, int y) {

x *= 35;

y *= 35;

int rows = chess.rows;

int cols = chess.cols;

for (int i = 0; i < rows; ++i) {

for (int j = 0; j < cols; ++j) {

if (!is_red(chess.at<Vec3b>(i, j))) {

BG.at<Vec3b>(x + i + 8, y + j + 8) = chess.at<Vec3b>(i, j);

}

}

}

}

/*

實(shí)現(xiàn)用的參數(shù)

*/

class CONFIG { public:

static const int BOARD_SIZE = 15;

static const int EMPTY = 0;

static const int USER_1 = 1;

static const int USER_2 = 2;

static const int AI_EMPTY = 0; // 無(wú)子

static const int AI_MY = 1; // 待評(píng)價(jià)子

static const int AI_OP = 2; // 對(duì)方子或不能下子

static const int MAX_NODE = 2;

static const int MIN_NODE = 1;

static const int INF = 106666666;

static const int ERROR_INDEX = -1;

//估價(jià)值

static const int AI_ZERO = 0;

static const int AI_ONE = 10;

static const int AI_ONE_S = 1;

static const int AI_TWO = 100;

static const int AI_TWO_S = 10;

static const int AI_THREE = 1000;

static const int AI_THREE_S = 100;

static const int AI_FOUR = 10000;

static const int AI_FOUR_S = 1000;

static const int AI_FIVE = 100000;

};

/*

棋盤(pán)格子

*/

class Grid :CONFIG { public:

int type; //類型

Grid() {

type = EMPTY;

}

Grid(int t) {

type = t;

}

void grid(int t = EMPTY) {

type = t;

}

int isEmpty() {

return type == EMPTY ? true : false;

}

};

/* 棋盤(pán)

*/

class ChessBoard :CONFIG { public:

Grid chessBoard[BOARD_SIZE][BOARD_SIZE];

ChessBoard() {

for (int i = 0; i < BOARD_SIZE; ++i)

for (int j = 0; j < BOARD_SIZE; ++j)

chessBoard[i][j].grid();

}

ChessBoard(const ChessBoard &othr) {

for (int i = 0; i < BOARD_SIZE; ++i)

for (int j = 0; j < BOARD_SIZE; ++j)

chessBoard[i][j].grid(othr.chessBoard[i][j].type);

}

/*

放置棋子

返回放置棋子是否成功

*/

bool placePiece(int x, int y, int type) {

if (chessBoard[x][y].isEmpty()) {

chessBoard[x][y].type = type;

return true;

}

return false;

}

};

/*

煞筆AI

*/

class Game :CONFIG { public:

ChessBoard curState; // 當(dāng)前棋盤(pán)

bool isStart; // 是否進(jìn)行中

int curUser; // 當(dāng)前行棋人

int MAX_DEPTH; // 最大搜索層數(shù)

/*

開(kāi)始并設(shè)定難度

*/

void startGame(int nd = 2) {

MAX_DEPTH = nd;

isStart = true;

curUser = USER_1;

}

/*

轉(zhuǎn)換行棋人

*/

void changeUser() {

curUser = curUser == USER_1 ? USER_2 : USER_1;

}

/*

根據(jù)給定type

A:待判斷棋子的類型

type:我方棋子的類型

返回A是待判斷棋子 無(wú)棋子 對(duì)方棋子

*/

int getPieceType(int A, int type) {

return A == type ? AI_MY : (A == EMPTY ? AI_EMPTY : AI_OP);

}

int getPieceType(const ChessBoard &board, int x, int y, int type) {

if (x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE)//
超出邊界按對(duì)方棋子算

return AI_OP;

else

return getPieceType(board.chessBoard[x][y].type, type);

}

/*

當(dāng)前行棋人放置棋子

放置失敗返回失敗

放置成功

檢察游戲是否結(jié)束

轉(zhuǎn)換游戲角色后返回成功

*/

bool placePiece(int x, int y) {

if (curState.placePiece(x, y, curUser)) {

// 檢察行棋人是否勝利

if (isWin(x, y)) {

isStart = false; // 游戲結(jié)束

// return true;

}

changeUser(); // 轉(zhuǎn)換游戲角色

return true;

}

return false;

}

bool isWin(int x, int y) {

if (evaluatePiece(curState, x, y, curUser) >= AI_FIVE)

return true;

return false;

}

/*

以center作為評(píng)估位置進(jìn)行評(píng)價(jià)一個(gè)方向的棋子

*/

int evaluateLine(int line[], bool ALL) {

int value = 0; // 估值

int cnt = 0; // 連子數(shù)

int blk = 0; // 封閉數(shù)

for (int i = 0; i < BOARD_SIZE; ++i) {

if (line[i] == AI_MY) { // 找到第一個(gè)己方的棋子

// 還原計(jì)數(shù)

cnt = 1;

blk = 0;

// 看左側(cè)是否封閉

if (line[i - 1] == AI_OP)

++blk;

// 計(jì)算連子數(shù)

for (i = i + 1; i < BOARD_SIZE && line[i] == AI_MY; ++i, ++cnt);

// 看右側(cè)是否封閉

if (line[i] == AI_OP)

++blk;

// 計(jì)算評(píng)估值

value += getValue(cnt, blk);

}

}

return value;

}

/*

以center作為評(píng)估位置進(jìn)行評(píng)價(jià)一個(gè)方向的棋子(前后4格范圍內(nèi))

*/

int evaluateLine(int line[]) {

int cnt = 1; // 連子數(shù)

int blk = 0; // 封閉數(shù)

// 向左右掃

for (int i = 3; i >= 0; --i) {

if (line[i] == AI_MY) ++cnt;

else if (line[i] == AI_OP) {

++blk;

break;

}

else

break;

}

for (int i = 5; i < 9; ++i) {

if (line[i] == AI_MY) ++cnt;

else if (line[i] == AI_OP) {

++blk;

break;

}

else

break;

}

return getValue(cnt, blk);

}

/*

根據(jù)連字?jǐn)?shù)和封堵數(shù)給出一個(gè)評(píng)價(jià)值

*/

int getValue(int cnt, int blk) {

if (blk == 0) {// 活棋

switch (cnt) {

case 1:

return AI_ONE;

case 2:

return AI_TWO;

case 3:

return AI_THREE;

case 4:

return AI_FOUR;

default:

return AI_FIVE;

}

}

else if (blk == 1) {// 單向封死

switch (cnt) {

case 1:

return AI_ONE_S;

case 2:

return AI_TWO_S;

case 3:

return AI_THREE_S;

case 4:

return AI_FOUR_S;

default:

return AI_FIVE;

}

}

else {// 雙向堵死

if (cnt >= 5)

return AI_FIVE;

else

return AI_ZERO;

}

}

/*

對(duì)一個(gè)狀態(tài)的一個(gè)位置放置一種類型的棋子的優(yōu)劣進(jìn)行估價(jià)

*/

int evaluatePiece(ChessBoard state, int x, int y, int type) {

int value = 0; // 估價(jià)值

int line[17]; //線狀態(tài)

bool flagX[8];// 橫向邊界標(biāo)志

flagX[0] = x - 4 < 0;

flagX[1] = x - 3 < 0;

flagX[2] = x - 2 < 0;

flagX[3] = x - 1 < 0;

flagX[4] = x + 1 > 14;

flagX[5] = x + 2 > 14;

flagX[6] = x + 3 > 14;

flagX[7] = x + 4 > 14;

bool flagY[8];// 縱向邊界標(biāo)志

flagY[0] = y - 4 < 0;

flagY[1] = y - 3 < 0;

flagY[2] = y - 2 < 0;

flagY[3] = y - 1 < 0;

flagY[4] = y + 1 > 14;

flagY[5] = y + 2 > 14;

flagY[6] = y + 3 > 14;

flagY[7] = y + 4 > 14;

line[4] = AI_MY; // 中心棋子

// 橫

line[0] = flagX[0] ? AI_OP : (getPieceType(state.chessBoard[x - 4][y].type,
type));

line[1] = flagX[1] ? AI_OP : (getPieceType(state.chessBoard[x - 3][y].type,
type));

line[2] = flagX[2] ? AI_OP : (getPieceType(state.chessBoard[x - 2][y].type,
type));

line[3] = flagX[3] ? AI_OP : (getPieceType(state.chessBoard[x - 1][y].type,
type));

line[5] = flagX[4] ? AI_OP : (getPieceType(state.chessBoard[x + 1][y].type,
type));

line[6] = flagX[5] ? AI_OP : (getPieceType(state.chessBoard[x + 2][y].type,
type));

line[7] = flagX[6] ? AI_OP : (getPieceType(state.chessBoard[x + 3][y].type,
type));

line[8] = flagX[7] ? AI_OP : (getPieceType(state.chessBoard[x + 4][y].type,
type));

value += evaluateLine(line);

// 縱

line[0] = flagY[0] ? AI_OP : getPieceType(state.chessBoard[x][y - 4].type,
type);

line[1] = flagY[1] ? AI_OP : getPieceType(state.chessBoard[x][y - 3].type,
type);

line[2] = flagY[2] ? AI_OP : getPieceType(state.chessBoard[x][y - 2].type,
type);

line[3] = flagY[3] ? AI_OP : getPieceType(state.chessBoard[x][y - 1].type,
type);

line[5] = flagY[4] ? AI_OP : getPieceType(state.chessBoard[x][y + 1].type,
type);

line[6] = flagY[5] ? AI_OP : getPieceType(state.chessBoard[x][y + 2].type,
type);

line[7] = flagY[6] ? AI_OP : getPieceType(state.chessBoard[x][y + 3].type,
type);

line[8] = flagY[7] ? AI_OP : getPieceType(state.chessBoard[x][y + 4].type,
type);

value += evaluateLine(line);

// 左上-右下

line[0] = flagX[0] || flagY[0] ? AI_OP : getPieceType(state.chessBoard[x -
4][y

- 4].type, type);

line[1] = flagX[1] || flagY[1] ? AI_OP : getPieceType(state.chessBoard[x
- 3][y

- 3].type, type);

line[2] = flagX[2] || flagY[2] ? AI_OP : getPieceType(state.chessBoard[x -
2][y

- 2].type, type);

line[3] = flagX[3] || flagY[3] ? AI_OP : getPieceType(state.chessBoard[x -
1][y

- 1].type, type);

line[5] = flagX[4] || flagY[4] ? AI_OP : getPieceType(state.chessBoard[x +
1][y

+ 1].type, type);

line[6] = flagX[5] || flagY[5] ? AI_OP : getPieceType(state.chessBoard[x +
2][y

+ 2].type, type);

line[7] = flagX[6] || flagY[6] ? AI_OP : getPieceType(state.chessBoard[x +
3][y

+ 3].type, type);

line[8] = flagX[7] || flagY[7] ? AI_OP : getPieceType(state.chessBoard[x +
4][y

+ 4].type, type);

value += evaluateLine(line);

// 右上-左下

line[0] = flagX[7] || flagY[0] ? AI_OP : getPieceType(state.chessBoard[x +
4][y

- 4].type, type);

line[1] = flagX[6] || flagY[1] ? AI_OP : getPieceType(state.chessBoard[x +
3][y

- 3].type, type);

line[2] = flagX[5] || flagY[2] ? AI_OP : getPieceType(state.chessBoard[x +
2][y

- 2].type, type);

line[3] = flagX[4] || flagY[3] ? AI_OP : getPieceType(state.chessBoard[x +
1][y

- 1].type, type);

line[5] = flagX[3] || flagY[4] ? AI_OP : getPieceType(state.chessBoard[x -
1][y

+ 1].type, type);

line[6] = flagX[2] || flagY[5] ? AI_OP : getPieceType(state.chessBoard[x -
2][y

+ 2].type, type);

line[7] = flagX[1] || flagY[6] ? AI_OP : getPieceType(state.chessBoard[x -
3][y

+ 3].type, type);

line[8] = flagX[0] || flagY[7] ? AI_OP : getPieceType(state.chessBoard[x -
4][y

+ 4].type, type);

value += evaluateLine(line);

return value;

}

/*

評(píng)價(jià)一個(gè)棋面上的一方

*/

int evaluateState(ChessBoard state, int type) {

int value = 0;

// 分解成線狀態(tài)

int line[6][17];

int lineP;

for (int p = 0; p < 6; ++p)

line[p][0] = line[p][16] = AI_OP;

// 從四個(gè)方向產(chǎn)生

for (int i = 0; i < BOARD_SIZE; ++i) {

// 產(chǎn)生線狀態(tài)

lineP = 1;

for (int j = 0; j < BOARD_SIZE; ++j) {

line[0][lineP] = getPieceType(state, i, j, type); /* | */

line[1][lineP] = getPieceType(state, j, i, type); /* - */

line[2][lineP] = getPieceType(state, i + j, j, type); /* \ */

line[3][lineP] = getPieceType(state, i - j, j, type); /* / */

line[4][lineP] = getPieceType(state, j, i + j, type); /* \ */

line[5][lineP] = getPieceType(state, BOARD_SIZE - j - 1, i + j, type);

/* / */

++lineP;

}

// 估計(jì)

int special = i == 0 ? 4 : 6;

for (int p = 0; p < special; ++p) {

value += evaluateLine(line[p], true);

}

}

return value;

}

/*

若x, y位置周圍1格內(nèi)有棋子則搜索

*/

bool canSearch(ChessBoard state, int x, int y) {

int tmpx = x - 1;

int tmpy = y - 1;

for (int i = 0; tmpx < BOARD_SIZE && i < 3; ++tmpx, ++i) {

int ty = tmpy;

for (int j = 0; ty < BOARD_SIZE && j < 3; ++ty, ++j) {

if (tmpx >= 0 && ty >= 0 && state.chessBoard[tmpx][ty].type != EMPTY)

return true;

else

continue;

}

}

return false;

}

/*

給出后繼節(jié)點(diǎn)的類型

*/

int nextType(int type) {

return type == MAX_NODE ? MIN_NODE : MAX_NODE;

}

/*

state 待轉(zhuǎn)換的狀態(tài)

type 當(dāng)前層的標(biāo)記:MAX MIN

depth 當(dāng)前層深

alpha 父層alpha值

beta 父層beta值

*/

int minMax(ChessBoard state, int x, int y, int type, int depth, int alpha, int
beta) {

ChessBoard newState(state);

newState.placePiece(x, y, nextType(type));

int weight = 0;

int max = -INF; // 下層權(quán)值上界

int min = INF; // 下層權(quán)值下界

if (depth < MAX_DEPTH) {

// 已輸或已勝則不繼續(xù)搜索

if (evaluatePiece(newState, x, y, nextType(type)) >= AI_FIVE) {

if (type == MIN_NODE)

return AI_FIVE; // 我方勝

else

return -AI_FIVE;

}

int i, j;

for (i = 0; i < BOARD_SIZE; ++i) {

for (j = 0; j < BOARD_SIZE; ++j) {

if (newState.chessBoard[i][j].type == EMPTY && canSearch(newState, i, j)) {

weight = minMax(newState, i, j, nextType(type), depth + 1, min, max);

if (weight > max)

max = weight; // 更新下層上界

if (weight < min)

min = weight; // 更新下層下界

// alpha-beta

if (type == MAX_NODE) {

if (max >= alpha)

return max;

}

else {

if (min <= beta)

return min;

}

}

else

continue;

}

}

if (type == MAX_NODE)

return max; // 最大層給出最大值

else

return min; // 最小層給出最小值

}

else {

weight = evaluateState(newState, MAX_NODE); // 評(píng)估我方局面

weight -= type == MIN_NODE ? evaluateState(newState, MIN_NODE) * 10 :
evaluateState(newState, MIN_NODE); // 評(píng)估對(duì)方局面

return weight; // 搜索到限定層后給出權(quán)值

}

}

int cnt[BOARD_SIZE][BOARD_SIZE];

/*

AI 行棋

*/

bool placePieceAI() {

int weight;

int max = -INF; // 本層的權(quán)值上界

int x = 0, y = 0;

memset(cnt, 0, sizeof(cnt));

for (int i = 0; i < BOARD_SIZE; ++i) {

for (int j = 0; j < BOARD_SIZE; ++j) {

if (curState.chessBoard[i][j].type == EMPTY && canSearch(curState, i, j)) {

weight = minMax(curState, i, j, nextType(MAX_NODE), 1, -INF, max);

cnt[i][j] = weight;

if (weight > max) {

max = weight; // 更新下層上界

x = i;

y = j;

}

}

else

continue;

}

}

return placePiece(x, y); // AI最優(yōu)點(diǎn)

}

/*

控制臺(tái)打印。。。

*/

void show() {

chessboard.copyTo(BG);

for (int i = 0; i < BOARD_SIZE; ++i) {

for (int j = 0; j < BOARD_SIZE; ++j) {

if (curState.chessBoard[i][j].type == 1)

imageCopyToBG(blackChess, i, j);

if (curState.chessBoard[i][j].type == 2)

imageCopyToBG(whiteChess, i, j);

}

}

for (int i = 0; i < BOARD_SIZE; ++i) {

for (int j = 0; j < BOARD_SIZE; ++j) {

if (curState.chessBoard[i][j].type == 0)

cout << " -";

if (curState.chessBoard[i][j].type == 1)

cout << " X";

if (curState.chessBoard[i][j].type == 2)

cout << " O";

}

cout << endl;

}

imshow(“gobang”, BG);

cv::waitKey(5);

}

};

using namespace cv; using namespace std;

int X, Y = 0; int optIsOk = 1; Game G;

//使用回調(diào)函數(shù)輸入數(shù)據(jù)

static void onMouse(int event, int x, int y, int, void*)

{

if (event != EVENT_LBUTTONDOWN)

return;

if (!optIsOk) return;

X = x; Y = y;

optIsOk = 0;

}

int main(int argc, char** argv)

{

chessboard = cv::imread(“chessboard.bmp”);

tmp = cv::imread(“whiteChess.bmp”);

resize(tmp, whiteChess, Size(30, 30), 0, 0, CV_INTER_LINEAR);

tmp = cv::imread(“blackChess.bmp”);

resize(tmp, blackChess, Size(30, 30), 0, 0, CV_INTER_LINEAR);

namedWindow(“gobang”, 1);

setMouseCallback(“gobang”, onMouse, 0);

chessboard.copyTo(BG);

imshow(“gobang”, BG);

cv::waitKey(50);

int flag = 0;

G.startGame(4);

for (;😉

{

G.placePieceAI();

G.show();

G.placePieceAI();

G.show();

optIsOk = 1;

// }

cv::waitKey(5);

}

return 0;

}

總結(jié)

以上是生活随笔為你收集整理的基于C的α-β剪枝算法实现的AI五子棋游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。