基于C++實現(xiàn)五子棋AI算法思想
今天我想要分享一下我做五子棋AI的思路。因為在做這個之前,我沒有接觸過任何像這種類似的東西。通過這一次,我也算是有所了解,我的思路也是來自很多網(wǎng)絡(luò)上的博客,看了很多,最終總結(jié)出了自己的這樣一個。
那我的五子棋是15*15的大?。ㄒ话阋簿褪沁@樣的一個大小)。我的AI算法要求每一次落子之后都要去計算每一個空暇的位置的“分值”,簡單的說,我們需要一個存放棋子的數(shù)組,表示是否存放了棋子,還要一個計算每一個空格的數(shù)組來記錄“分?jǐn)?shù)”,這個分?jǐn)?shù)是后期AI用來運算的基礎(chǔ),也是你AI難度控制的點。
我現(xiàn)有的思路就是分兩部分。首先是如果是玩家先落子,那么要求電腦AI隨即在你落子的地方的任意一個方向,隨機落子,這是第一步。接下來以后就正式進入到算法中去。
首先初始化你的分?jǐn)?shù)數(shù)組,讓他們?nèi)繛榱恪H缓笤诿恳淮温渥又筮M行全盤的遍歷,如果發(fā)現(xiàn)該處為空白,于是檢查其四周八個方向(當(dāng)然如果是邊緣位置就相對修改,判斷是否出了邊界)。若在空白處,且發(fā)現(xiàn)在某一對角線方向發(fā)現(xiàn)有一個其他顏色的棋子,那么相對的給這個空白區(qū)域的分?jǐn)?shù)數(shù)組加上一定的分值,然后繼續(xù)往這個方向檢測是否還有連續(xù)的同一顏色的棋子,若沒有則檢查其他方向或者檢測下一個空白位置。若是還在同一方向上面找到了相同顏色的棋子,那么第二個棋子的出現(xiàn),你可以給改空白處加上雙倍的分值,表明這個空白位置更加重要。一次類推,繼續(xù)檢測。(PS:因為最終AI棋子落在什么地方,依靠的是最后遍歷整個分?jǐn)?shù)數(shù)組,然后根據(jù)分?jǐn)?shù)的高低來進行判斷落子落在哪里的,在下面講)。
經(jīng)過上一遍的遍歷,每一次落子都會使得分?jǐn)?shù)數(shù)組得到一些變化,每一次都會導(dǎo)致AI判斷的變化。在這個基礎(chǔ)上,每一次落子還要進行一次對自己本身棋子顏色的一個遍歷,判斷自己的情況,同時加分加在分?jǐn)?shù)數(shù)組之中,這樣一來,電腦就會根據(jù)自己的棋子的情況以及玩家的落子情況進行判斷,哪一個地方更加適合落子。
因為我是第一次做AI,網(wǎng)絡(luò)上搜到的一些思想一般也是這種類似的遍歷思想。理解了以后寫代碼就比較方便。最后可能會有一些點的分?jǐn)?shù)是相同的,所以還有設(shè)置一下隨機落子。把分?jǐn)?shù)相同的地點隨機落子。
個人感覺AI的強弱是根據(jù)你每一次給他增加分?jǐn)?shù)的多少來確定的。這個我的AI有時候也會抽風(fēng),不過一般情況比較正常,可能運氣也占了一部分,當(dāng)初設(shè)計加分的時候其實沒想那么多,現(xiàn)在卻發(fā)現(xiàn)好像還不錯。
大家要多去實踐練習(xí),多改改分?jǐn)?shù)可能就會出來不錯的AI了,o(^▽^)o。
下面貼上我的代碼!
void GameScene::Robot(int *x, int *y, int *Sum)
{
ExWhile1 = true;
if (*Sum == 1)
{
while (ExWhile1)
{
ChessOne(*x, *y);
if (ch[*x][*y] == 2){ ExWhile1 = false; }
}
ch[*x][*y] = tp; //記錄這個點
printpart(*x, *y, tp); //打印出電腦AI第一次落子
isTouch = true;
tp++;
tp = tp % 2;
}
else //從第2步開始,使用評分系統(tǒng)
{
Findscore(*x, *y);
}
}
void GameScene::Findscore(int &x, int &y) //查找評分最高的坐標(biāo)
{
srand((unsigned)time(NULL));
int i, j, x1, x2, y1, y2, lx;
int Max = 0;
ChessScore(); //調(diào)用評分函數(shù)
for (i = 0; i<15; i++)
{
for (j = 0; j<15; j++)
{
if (Score[i][j]>Max)
{
Max = Score[i][j]; //獲取所有點中,評分最高的
x1 = i;
y1 = j;
}
}
}
x2 = x1; y2 = y1;
for (i = 0; i<15; i++) //可能的話,有評分相同的多個點
{
for (j = 0; j<15; j++)
{
if (Score[i][j] == Max&&i != x2&&j != y2) //在這么多個相同分?jǐn)?shù)的點中,隨機找一個
{
lx = rand() % 10;
if (lx<5)
{
x2 = i, y2 = j;
break;
}
}
}
}
if (x2 != x1 || y2 != y1) //棋盤上有2個最高分
{
lx = rand() % 10; //隨機一個
if (lx>6)
{
x = x1, y = y1;
}
else
{
x = x2, y = y2;
}
}
else //棋盤上只有一個最高分
{
x = x1, y = y1;
}
Max = 0; //清空最大值
ch[x][y] = tp; //記錄這個點
printpart(x, y, tp); //打印出電腦AI落子
if (winerValue==2)
{
isTouch = true;
}
tp++;
tp = tp % 2;
}
inline void GameScene::ChessOne(int &x, int &y) //玩家走第1步時的落子
{
int i, j;
srand((unsigned)time(NULL)); //隨機數(shù)隨著時間的改變而改變
for (i = 0; i<15; i++)
{
for (j = 0; j<15; j++)
{
if (ch[i][j] == 0) //如果找到了玩家的棋子,在它的8個方的任意一點落子
{
int lx = rand() % 7;
if (lx == 0)
{
x = i + 1; y = j + 1;
if (ch[x][y] == 2){ break; }
}
else if (lx == 1)
{
x = i + 1; y = j - 1;
if (ch[x][y] == 2){ break; }
}
else if (lx == 2)
{
x = i - 1; y = j - 1;
if (ch[x][y] == 2){ break; }
}
else if (lx == 3)
{
x = i - 1; y = j + 1;
if (ch[x][y] == 2){ break; }
}
else if (lx == 4)
{
x = i - 1; y = j; //上
if (ch[x][y] == 2){ break; }
}
else if (lx == 5)
{
x = i; y = j - 1; //左
if (ch[x][y] == 2){ break; }
}
else if (lx == 6)
{
x = i; y = j + 1; //右
if (ch[x][y] == 2){ break; }
}
else
{
x = i + 1; y = j; //下
if (ch[x][y] == 2){ break; }
}
}
}
}
}
void GameScene::ChessScore()
{
int x, y, i, j, k; //循環(huán)變量
int number1 = 0, number2 = 0; //number用來統(tǒng)計玩家或電腦棋子連成個數(shù)
int empty = 0; //empty用來統(tǒng)計空點個數(shù)
memset(Score, 0, sizeof(Score)); //把評分?jǐn)?shù)組先清零
for (x = 0; x<15; x++)
{
for (y = 0; y<15; y++)
{
if (ch[x][y] == 2) //如果這個點為空
{
for (i = -1; i <= 1; i++)
{
for (j = -1; j <= 1; j++) //判斷8個方向
{
if (i != 0 || j != 0) //若是都為0的話,那不就是原坐標(biāo)嘛
{
//對玩家落點評分
for (k = 1; i <= 4; k++) //循環(huán)4次
{ //這點沒越界 且這點存在黑子(玩家)
if (x + k*i >= 0 && x + k*i <= 14 &&
y + k*j >= 0 && y + k*j <= 14 &&
ch[x + k*i][y + k*j] == 0)
{
number1++;
}
else if (ch[x + k*i][y + k*j] == 2) //這點是個空點,+1后退出
{
empty++;
break;
}
else //否則是墻或者對方的棋子了
{
break;
}
}
for (k = -1; k >= -4; k--) //向它的相反方向判斷
{ //這點沒越界 且這點存在黑子(玩家)
if (x + k*i >= 0 && x + k*i <= 14 &&
y + k*j >= 0 && y + k*j <= 14 &&
ch[x + k*i][y + k*j] == 0)
{
number1++;
}
else if (ch[x + k*i][y + k*j] == 2) //這點是個空點,+1后退出
{
empty++;
break;
}
else
{
break;
}
}
if (number2 == 1) //2個棋子
{
Score[x][y] += 1;
}
else if (number1 == 2) //3個棋子
{
if (empty == 1)
{
Score[x][y] += 5; //有一個空點+5分 死3
}
else if (empty == 2)
{
Score[x][y] += 10; //有兩個空點+10分 活3
}
}
else if (number1 == 3) //4個棋子
{
if (empty == 1)
{
Score[x][y] += 20; //有一個空點+20分 死4
}
else if (empty == 2)
{
Score[x][y] += 100; //有2個空點+100分 活4
}
}
else if (number1 >= 4)
{
Score[x][y] += 1000; //對方有5個棋子,分?jǐn)?shù)要高點,先堵
}
empty = 0; //統(tǒng)計空點個數(shù)的變量清零
//對電腦落點評分
for (k = 1; i <= 4; k++) //循環(huán)4次
{ //這點沒越界 且這點存在白子(電腦)
if (x + k*i >= 0 && x + k*i <= 14 &&
y + k*j >= 0 && y + k*j <= 14 &&
ch[x + k*i][y + k*j] == 1)
{
number2++;
}
else if (ch[x + k*i][y + k*j] == 2)
{
empty++; break; //空點
}
else
{
break;
}
}
for (k = -1; k >= -4; k--) //向它的相反方向判斷
{
if (x + k*i >= 0 && x + k*i <= 14 &&
y + k*j >= 0 && y + k*j <= 14 &&
ch[x + k*i][y + k*j] == 1)
{
number2++;
}
else if (ch[x + k*i][y + k*j] == 2)
{
empty++; break;
}
else
{
break; //注釋與上面玩家版相同
}
}
if (number2 == 0)
{
Score[x][y] += 1; //1個棋子
}
else if (number2 == 1)
{
Score[x][y] += 2; //2個棋子
}
else if (number2 == 2) //3個棋子
{
if (empty == 1)
{
Score[x][y] += 8; //死3
}
else if (empty == 2)
{
Score[x][y] += 30; //活3
}
}
else if (number2 == 3) //4個棋子
{
if (empty == 1)
{
Score[x][y] += 50; //死4
}
else if (empty == 2)
{
Score[x][y] += 200; //活4
}
}
else if (number2 >= 4)
{
Score[x][y] += 10000; //自己落在這點能形成5個,也就能勝利了,分?jǐn)?shù)最高
}
number1 = 0; //清零,以便下次重新統(tǒng)計
number2 = 0;
empty = 0;
}
}
}
}
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
欄 目:C語言
下一篇:C&C++設(shè)計風(fēng)格選擇 命名規(guī)范
本文標(biāo)題:基于C++實現(xiàn)五子棋AI算法思想
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/843.html
您可能感興趣的文章
- 04-02c語言沒有round函數(shù) round c語言
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計-用棧實現(xiàn)表達式求值的方法詳解
- 01-10使用OpenGL實現(xiàn)3D立體顯示的程序代碼
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10求斐波那契(Fibonacci)數(shù)列通項的七種實現(xiàn)方法
- 01-10C語言 解決不用+、-、&#215;、&#247;數(shù)字運算符做加法
- 01-10使用C++實現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實現(xiàn)DBSCAN聚類算法
- 01-10深入全排列算法及其實現(xiàn)方法


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實例總結(jié)
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10delphi制作wav文件的方法
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置


