c语言编程一个象棋游戏,急求:C语言编写的中国象棋游戏一个
急求:C語言編寫的中國象棋游戲一個(gè)
來源:互聯(lián)網(wǎng)??2009-09-08 12:30:35??評(píng)論
分類: 電腦/網(wǎng)絡(luò) >> 程序設(shè)計(jì) >> 其他編程語言
問題描述:
由于學(xué)習(xí)需要......熱烈歡迎個(gè)位大俠,高手相助!小生在此道謝了!!! 希望留下您的郵箱或者QQ以遍交流。20分哦
參考答案:
先弄明白數(shù)據(jù)的結(jié)構(gòu):
MantisChessDef.h里的東西一定要先看一下, 否則會(huì)摸不到頭腦的。
還有棋盤坐標(biāo):
象棋棋盤大小9x10,為了便于編程,規(guī)定棋盤每條邊留有一個(gè)元素的邊界。
這樣棋盤大小(包括邊界)變成11x12。棋盤x坐標(biāo)軸向右,y軸向下。
黑棋永遠(yuǎn)在上方,在標(biāo)準(zhǔn)開局時(shí)左上角的黑車坐標(biāo)是(1,1)。
局面用這三個(gè)變量表示:
static POINT g_pointChessman[32]; //棋子坐標(biāo)
static int g_iChessmanMap[11][12]; //棋位狀態(tài)
static int g_iSide; //輪到哪方走
智能部分有幾個(gè)函數(shù)的前三個(gè)參數(shù)就是這個(gè)東西, 應(yīng)該不難理解吧?
---------------------------------------------------------------------------------------
search函數(shù):
先說明一下, 經(jīng)常有朋友問我要原理, 但我公開源代碼是給大家一個(gè)參考, 而不是什么教程,所以我不想說那些理論的東西。
基本原理是α-β搜索, 很多人工智能的教科書上都有講到, 沒看過的的趕快去找一本來啃一啃;
雖然這些書上的文字大多晦澀難懂,但畢竟講得明明白白。
沒有書的朋友請(qǐng)發(fā)揮一下主觀能動(dòng)性, 去找一找,不要來問我要, 因?yàn)槲乙矝]有。
我在這里只分析一下search函數(shù):
弄懂α-β搜索后來看看這個(gè)博弈樹, 看怎么編程實(shí)現(xiàn)它。
先規(guī)定一下, 我們用一個(gè)整數(shù)表示局面的好壞.
這個(gè)數(shù)越大說明局面對(duì) "走棋方" 越有利,0表示雙方實(shí)力相等。
1a( 1) ┬ 2a(-1) ┬ 3a(-1)
│ └ 3b( 1)
└ 2b(-5) ┬ 3c( 2)
├ 3d(-4)
└ 3e( 5)
分析一下這棵樹,有這么個(gè)特點(diǎn): 父結(jié)點(diǎn)的值 = -MAX(子結(jié)點(diǎn)的值)
我們還知道1、每個(gè)結(jié)點(diǎn)對(duì)應(yīng)一個(gè)局面。2、底層的結(jié)點(diǎn)的值是"估"出來的。
于是我們可以寫出偽代碼了:
偽代碼: 搜索一個(gè)結(jié)點(diǎn)下的分支, 得到這個(gè)結(jié)點(diǎn)的值。
參數(shù): 局面,搜索深度
返回值:結(jié)點(diǎn)的值
int search(局面,int depth)
{
if(depth!=0)//不是底層結(jié)點(diǎn)
{
枚舉出所有子結(jié)點(diǎn)(列出所有走法);
int count=子結(jié)點(diǎn)數(shù);
int maxvalue= -∞;
for(int i=0;i
{
算出子結(jié)點(diǎn)局面;
maxvalue=max(maxvalue,search(子結(jié)點(diǎn)局面,depth-1));
}
return -maxvalue;
}
else //是底層結(jié)點(diǎn)
{
return 估計(jì)值;
}
}
這就是搜索算法的框架, 用到了遞歸。
MantisChess的智能部分函數(shù)都在MantisChessThink.cpp里, 其中search是搜索, 跟上面的這個(gè)search差不多,我把它c(diǎn)opy出來注釋一下:
int Search(int tmap[11][12],POINT tmanposition[32],int &tside,int man, POINT point,int upmax,int depth)
{
//前面的三個(gè)參數(shù)就是局面。
//man 和point 是走法,用來計(jì)算本結(jié)點(diǎn)的局面。 這里是把計(jì)算局面放在函數(shù)的開頭,跟上面的偽代碼不太一樣。
//upmax: up - 上一層, max - 最大值, 這是α-β的剪枝用到的東西, 后面再講。
//depth: 搜索深度
int ate,cur,maxvalue,curvalue,xs,ys;
int count;
//#####################這一段是計(jì)算本結(jié)點(diǎn)的局面#########################################
ate=32;
//移動(dòng)棋子:
xs=tmanposition[man].x;ys=tmanposition[man].y; //原坐標(biāo)
if (SideOfMan[tmap[point.x][point.y]]==!tside) //目標(biāo)點(diǎn)有對(duì)方的棋子
{
ate=tmap[point.x][point.y]; //記錄下被吃掉的棋子
if(ate==0 || ate==16)
{
return 9999;
}
tmanposition[ate].x=0; //目標(biāo)點(diǎn)的棋子被吃掉
}
tmap[point.x][point.y]=man; //這兩行是:
tmap[xs][ys]=32; //在map上的移動(dòng)
tmanposition[man]=point;
tside=!tside;
//####################################################################################
depth--;
if(depth>0) //不是底層結(jié)點(diǎn)
{
int chessman[125];
POINT targetpoint[125];
if(EnumList(tmap,tmanposition,tside,chessman,targetpoint,count)) //枚舉出所有子結(jié)點(diǎn)(列出所有走法)
{
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//這里是剪枝(不是α-β剪枝), 原理是在正式搜索之前先用較淺的搜索來得到誤差較大的值
//然后根據(jù)這些值來對(duì)子結(jié)點(diǎn)排序, 只保留最好的S_WIDTH個(gè)結(jié)點(diǎn)進(jìn)行正式搜索。
//顯然,這個(gè)剪枝有一定的風(fēng)險(xiǎn)
if(depth>=2 && count>S_WIDTH+2)
{
int value[125];
cur=0;
maxvalue=-10000;
while(cur< count)
{
curvalue=Search(tmap,tmanposition,tside,chessman[cur],targetpoint[cur],-10000,depth-2);
value[cur]=curvalue;
if(curvalue>maxvalue)maxvalue=curvalue;
cur ++;
}
::Mantis_QuickSort(value,chessman,targetpoint,0,count-1); //排序
count=S_WIDTH;//剪枝
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
maxvalue=-10000;
cur=0;
while(cur< count)
{
curvalue=Search(tmap,tmanposition,tside,chessman[cur],targetpoint[cur],maxvalue,depth);
if(curvalue>maxvalue)maxvalue=curvalue;
if(curvalue>=-upmax)goto _ENDSUB; //α-β剪枝, 符合剪枝條件的就Cut掉。 這里用了goto語句了, 千萬別學(xué)我。
cur ++;
}
}
else maxvalue=9800;
}
else //是底層結(jié)點(diǎn)
{
maxvalue=Value(tmap,tmanposition,tside); //估值
}
_ENDSUB:
//返回之前要恢復(fù)父結(jié)點(diǎn)的局面
//####################################################################################
tmanposition[man].x=xs; //這兩行是:
tmanposition[man].y=ys; //在face上的恢復(fù)
tmap[xs][ys]=man; //在map上的恢復(fù)
if(ate!=32)
{
tmanposition[ate]=point;
tmap[point.x][point.y]=ate;
}
else tmap[point.x][point.y]=32;
tside=!tside;
//####################################################################################
return -maxvalue;
}
上面的代碼用到了α-β剪枝, 舉個(gè)例子就明白了:
還是這個(gè)博弈樹,從上往下遍歷。
1a( 1) ┳ 2a(-1) ┳ 3a(-1)
┃ ┗ 3b( 1)
┗ 2b(-5) ┯ 3c( 2)
├ 3d(-4)
└ 3e( 5)
2a遍歷完后 upmax=-1, 繼續(xù)遍歷完3c后返回2b, 發(fā)現(xiàn)3c=2>-upmax, 這時(shí)就不用管3d和3e了, 因?yàn)闊o論他們的值是多少 2b=-max(3c,3d,3e)<2a 一定成立,
也就是說2b可以安全地剪掉。這就是α-β剪枝。
從上面的代碼來看我的MantisChess算法與標(biāo)準(zhǔn)的α-β剪枝搜索并沒有什么不同, 只不過加了排序和剪枝而已。
[b]分類:[/b] 電腦/網(wǎng)絡(luò) >> 程序設(shè)計(jì) >> 其他編程語言[br][b]問題描述:[/b][br]由于學(xué)習(xí)需要......熱烈歡迎個(gè)位大俠,高手相助!小生在此道謝了!!! 希望留下您的郵箱或者QQ以遍交流。20分哦[br][b]參考答案:[/b][br]先弄明白數(shù)據(jù)的結(jié)構(gòu):
MantisChessDef.h里的東西一定要先看一下, 否則會(huì)摸不到頭腦的。
還有棋盤坐標(biāo):
象棋棋盤大小9x10,為了便于編程,規(guī)定棋盤每條邊留有一個(gè)元素的邊界。
這樣棋盤大小(包括邊界)變成11x12。棋盤x坐標(biāo)軸向右,y軸向下。
黑棋永遠(yuǎn)在上方,在標(biāo)準(zhǔn)開局時(shí)左上角的黑車坐標(biāo)是(1,1)。
局面用這三個(gè)變量表示:
static POINT g_pointChessman[32]; //棋子坐標(biāo)
static int g_iChessmanMap[11][12]; //棋位狀態(tài)
static int g_iSide; //輪到哪方走
智能部分有幾個(gè)函數(shù)的前三個(gè)參數(shù)就是這個(gè)東西, 應(yīng)該不難理解吧?
---------------------------------------------------------------------------------------
search函數(shù):
先說明一下, 經(jīng)常有朋友問我要原理, 但我公開源代碼是給大家一個(gè)參考, 而不是什么教程,所以我不想說那些理論的東西。
基本原理是α-β搜索, 很多人工智能的教科書上都有講到, 沒看過的的趕快去找一本來啃一啃;
雖然這些書上的文字大多晦澀難懂,但畢竟講得明明白白。
沒有書的朋友請(qǐng)發(fā)揮一下主觀能動(dòng)性, 去找一找,不要來問我要, 因?yàn)槲乙矝]有。
我在這里只分析一下search函數(shù):
弄懂α-β搜索后來看看這個(gè)博弈樹, 看怎么編程實(shí)現(xiàn)它。
先規(guī)定一下, 我們用一個(gè)整數(shù)表示局面的好壞.
這個(gè)數(shù)越大說明局面對(duì) "走棋方" 越有利,0表示雙方實(shí)力相等。
1a( 1) ┬ 2a(-1) ┬ 3a(-1)
│ └ 3b( 1)
└ 2b(-5) ┬ 3c( 2)
├ 3d(-4)
└ 3e( 5)
分析一下這棵樹,有這么個(gè)特點(diǎn): 父結(jié)點(diǎn)的值 = -MAX(子結(jié)點(diǎn)的值)
我們還知道1、每個(gè)結(jié)點(diǎn)對(duì)應(yīng)一個(gè)局面。2、底層的結(jié)點(diǎn)的值是"估"出來的。
于是我們可以寫出偽代碼了:
偽代碼: 搜索一個(gè)結(jié)點(diǎn)下的分支, 得到這個(gè)結(jié)點(diǎn)的值。
參數(shù): 局面,搜索深度
返回值:結(jié)點(diǎn)的值
int search(局面,int depth)
{
if(depth!=0)//不是底層結(jié)點(diǎn)
{
枚舉出所有子結(jié)點(diǎn)(列出所有走法);
int count=子結(jié)點(diǎn)數(shù);
int maxvalue= -∞;
for(int i=0;i
{
算出子結(jié)點(diǎn)局面;
maxvalue=max(maxvalue,search(子結(jié)點(diǎn)局面,depth-1));
}
return -maxvalue;
}
else //是底層結(jié)點(diǎn)
{
return 估計(jì)值;
}
}
這就是搜索算法的框架, 用到了遞歸。
MantisChess的智能部分函數(shù)都在MantisChessThink.cpp里, 其中search是搜索, 跟上面的這個(gè)search差不多,我把它c(diǎn)opy出來注釋一下:
int Search(int tmap[11][12],POINT tmanposition[32],int &tside,int man, POINT point,int upmax,int depth)
{
//前面的三個(gè)參數(shù)就是局面。
//man 和point 是走法,用來計(jì)算本結(jié)點(diǎn)的局面。 這里是把計(jì)算局面放在函數(shù)的開頭,跟上面的偽代碼不太一樣。
//upmax: up - 上一層, max - 最大值, 這是α-β的剪枝用到的東西, 后面再講。
//depth: 搜索深度
int ate,cur,maxvalue,curvalue,xs,ys;
int count;
//#####################這一段是計(jì)算本結(jié)點(diǎn)的局面#########################################
ate=32;
//移動(dòng)棋子:
xs=tmanposition[man].x;ys=tmanposition[man].y; //原坐標(biāo)
if (SideOfMan[tmap[point.x][point.y]]==!tside) //目標(biāo)點(diǎn)有對(duì)方的棋子
{
ate=tmap[point.x][point.y]; //記錄下被吃掉的棋子
if(ate==0 || ate==16)
{
return 9999;
}
tmanposition[ate].x=0; //目標(biāo)點(diǎn)的棋子被吃掉
}
tmap[point.x][point.y]=man; //這兩行是:
tmap[xs][ys]=32; //在map上的移動(dòng)
tmanposition[man]=point;
tside=!tside;
//####################################################################################
depth--;
if(depth>0) //不是底層結(jié)點(diǎn)
{
int chessman[125];
POINT targetpoint[125];
if(EnumList(tmap,tmanposition,tside,chessman,targetpoint,count)) //枚舉出所有子結(jié)點(diǎn)(列出所有走法)
{
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//這里是剪枝(不是α-β剪枝), 原理是在正式搜索之前先用較淺的搜索來得到誤差較大的值
//然后根據(jù)這些值來對(duì)子結(jié)點(diǎn)排序, 只保留最好的S_WIDTH個(gè)結(jié)點(diǎn)進(jìn)行正式搜索。
//顯然,這個(gè)剪枝有一定的風(fēng)險(xiǎn)
if(depth>=2 && count>S_WIDTH+2)
{
int value[125];
cur=0;
maxvalue=-10000;
while(cur< count)
{
curvalue=Search(tmap,tmanposition,tside,chessman[cur],targetpoint[cur],-10000,depth-2);
value[cur]=curvalue;
if(curvalue>maxvalue)maxvalue=curvalue;
cur ++;
}
::Mantis_QuickSort(value,chessman,targetpoint,0,count-1); //排序
count=S_WIDTH;//剪枝
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
maxvalue=-10000;
cur=0;
while(cur< count)
{
curvalue=Search(tmap,tmanposition,tside,chessman[cur],targetpoint[cur],maxvalue,depth);
if(curvalue>maxvalue)maxvalue=curvalue;
if(curvalue>=-upmax)goto _ENDSUB; //α-β剪枝, 符合剪枝條件的就Cut掉。 這里用了goto語句了, 千萬別學(xué)我。
cur ++;
}
}
else maxvalue=9800;
}
else //是底層結(jié)點(diǎn)
{
maxvalue=Value(tmap,tmanposition,tside); //估值
}
_ENDSUB:
//返回之前要恢復(fù)父結(jié)點(diǎn)的局面
//####################################################################################
tmanposition[man].x=xs; //這兩行是:
tmanposition[man].y=ys; //在face上的恢復(fù)
tmap[xs][ys]=man; //在map上的恢復(fù)
if(ate!=32)
{
tmanposition[ate]=point;
tmap[point.x][point.y]=ate;
}
else tmap[point.x][point.y]=32;
tside=!tside;
//####################################################################################
return -maxvalue;
}
上面的代碼用到了α-β剪枝, 舉個(gè)例子就明白了:
還是這個(gè)博弈樹,從上往下遍歷。
1a( 1) ┳ 2a(-1) ┳ 3a(-1)
┃ ┗ 3b( 1)
┗ 2b(-5) ┯ 3c( 2)
├ 3d(-4)
└ 3e( 5)
2a遍歷完后 upmax=-1, 繼續(xù)遍歷完3c后返回2b, 發(fā)現(xiàn)3c=2>-upmax, 這時(shí)就不用管3d和3e了, 因?yàn)闊o論他們的值是多少 2b=-max(3c,3d,3e)<2a 一定成立,
也就是說2b可以安全地剪掉。這就是α-β剪枝。
從上面的代碼來看我的MantisChess算法與標(biāo)準(zhǔn)的α-β剪枝搜索并沒有什么不同, 只不過加了排序和剪枝而已。
總結(jié)
以上是生活随笔為你收集整理的c语言编程一个象棋游戏,急求:C语言编写的中国象棋游戏一个的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机平面设计专业有哪些课程,计算机平面
- 下一篇: 计算机控制常用数据通信标准,计算机控制数