五子棋勝負(fù)的判定,一般有一下兩種算法:
創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)營(yíng)銷推廣、網(wǎng)站重做改版、連山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為連山等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
1.掃描整個(gè)棋盤,分別掃描四個(gè)方向是否有5個(gè)連子。網(wǎng)上找了很多五子棋源碼都是用此算法,這意味著每下一個(gè)棋子都要掃描一遍19×19的棋盤,復(fù)雜而且低效,代碼略。
2.每下一字,從該子開始掃描其四個(gè)方向(例如:從該子的(x-4,y)坐標(biāo)開始掃描橫向)是否存在5個(gè)連子。此算法較為常用,而且不涉及更為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
另外,為解決掃描越界的問(wèn)題,在聲明棋盤棋子位置時(shí),可聲明一個(gè)(4+19+4)×(4+19+4)的棋盤,而讓棋子偏移(4,4)個(gè)坐標(biāo)。
算法2源代碼如下:
?123456789101112131415161718192021static void IfWin(int x,int y,int color){ TCHAR win[20]; int a,b; if(stone[x][y]==1) wcscpy_s(win,_T("黑棋勝利!")); else wcscpy_s(win,_T("白棋勝利!")); for(a=x-4;a=x+4;a++)//判斷橫 if(stone[a][y]==colorstone[a+1][y]==colorstone[a+2][y]==colorstone[a+3][y]==colorstone[a+4][y]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(b=y-4;b=y+4;b++)//判斷豎 if(stone[x][b]==colorstone[x][b+1]==colorstone[x][b+2]==colorstone[x][b+3]==colorstone[x][b+4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(a=x-4,b=y-4;a=x+4;a++,b++)//判斷右斜 if(stone[a][b]==colorstone[a+1][b+1]==colorstone[a+2][b+2]==colorstone[a+3][b+3]==colorstone[a+4][b+4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;} for(a=x-4,b=y+4;a=x+4;a++,b--)//判斷左斜 if(stone[a][b]==colorstone[a+1][b-1]==colorstone[a+2][b-2]==colorstone[a+3][b-3]==colorstone[a+4][b-4]==color) {MessageBoxW(Xqwl.hWnd,win,TEXT(""),MB_OK);return;}}
給個(gè)思路吧:
對(duì)每一條輸入進(jìn)行判斷是否構(gòu)成五連珠,也就是對(duì)每一條輸入去搜索它的橫豎斜三個(gè)方向去檢查是否存在五個(gè)連續(xù)點(diǎn)。存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)使用二維數(shù)組即可,注意要區(qū)分雙方的不同(可以奇數(shù)步使用0,偶數(shù)步使用1標(biāo)記)。橫方向即x不變,y增減;豎方向即y不變,x增減;斜方向有兩個(gè),一個(gè)是x,y同增減,另一個(gè)是xy增減相反。
我瀏覽了一下你的代碼,你對(duì)勝利的判斷采用的是檢查整個(gè)棋盤的方式,這樣做的最大弊端自然是低效,而且在編寫斜方向判斷的時(shí)候比較復(fù)雜。我建議你采用下子后判斷的方式,即玩家1下了一個(gè)字后,像該子周圍8個(gè)方向檢查是否存在5子的情況,只需要一個(gè)判斷方法,而且較為簡(jiǎn)單。
void chooseONE()
{
printf("第一玩家請(qǐng)選擇下棋位置\n");
printf("第幾個(gè)直的\n");
scanf("%d",co);
printf("第幾個(gè)橫的\n");
scanf("%d",ro);
while(arr[ro][co]==1||arr[ro][co]==2)
{
printf("重復(fù)了!!!\n");
printf("第幾個(gè)直的\n");
scanf("%d",co);
printf("第幾個(gè)橫的\n");
scanf("%d",ro);
}
arr[ro][co]=1;
//這里加判斷代碼,建議用一個(gè)判斷函數(shù),我給你寫個(gè)吧
}
//我這里這個(gè)方法寫了個(gè)大概,你看一下和你的代碼結(jié)合一下就可以了,我用i和j作為for循環(huán)的變量,你用來(lái)做最大的長(zhǎng)寬值,這些你都要改一下。
flag作為判斷是否勝利的標(biāo)志,playerNum是玩家的標(biāo)志,分1和2,這個(gè)函數(shù)只寫了左和左上的判斷,其他方向樓主仿照著寫
int win(int row, int col, int playerNum){
int i = 0,j = 0;
int flag = 1;
if(row - 4 = 0){
flag = 1;
for(i = row; i = 0; i--){
if(arr[i][j] != playerNum){
flag = 0;
break;
}
}
if(flag == 1){
return 1;
}
}
if(row - 4 = 0 col - 4 = 0){
flag = 1;
for(i = row ,j = col ; i = 0j=0; i--,j--){
if(arr[i][j] != playerNum){
flag = 0;
break;
}
}
if(flag == 1){
return 1;
}
}
}
/*一個(gè)月就想做五子棋,有點(diǎn)難啊,希望你能看懂,這是代碼*/
#include?stdlib.h
#include?stdio.h
#include?conio.h
#include?string.h
#define?MAXIMUS?15?//定義棋盤大小
int?p[MAXIMUS][MAXIMUS];//存儲(chǔ)對(duì)局信息
char?buff[MAXIMUS*2+1][MAXIMUS*4+3];//輸出緩沖器
int?Cx,Cy;//當(dāng)前光標(biāo)位置
int?Now;//當(dāng)前走子的玩家,1代表黑,2代表白
int?wl,wp;//當(dāng)前寫入緩沖器的列數(shù)和行數(shù)位置
char*?showText;//在棋盤中央顯示的文字信息
int?count;//回合數(shù)
char*?Copy(char*?strDest,const?char*?strSrc)//修改過(guò)的字符串復(fù)制函數(shù),會(huì)忽略末端的\0
{
char*?strDestCopy?=?strDest;
while?(*strSrc!='\0')
{
*strDest++=*strSrc++;
}
return?strDestCopy;
}
void?Initialize()//初始化一個(gè)對(duì)局函數(shù)
{
int?i,j;//循環(huán)變量
showText="";//重置顯示信息
count=0;//回合數(shù)歸零
for(i=0;iMAXIMUS;i++)//重置對(duì)局?jǐn)?shù)據(jù)
{
for(j=0;jMAXIMUS;j++)
{
p[i][j]=0;
}
}
Cx=Cy=MAXIMUS/2;//重置光標(biāo)到中央
Now=1;//重置當(dāng)前為黑方
}
char*?getStyle(int?i,int?j)//獲得棋盤中指定坐標(biāo)交點(diǎn)位置的字符,通過(guò)制表符拼成棋盤
{
if(p[i][j]==1)//1為黑子
return?"●";
else?if(p[i][j]==2)//2為白子
return?"○";
else?if(i==0j==0)//以下為邊緣棋盤樣式
return?"┏";
else?if(i==MAXIMUS-1j==0)
return?"┓";
else?if(i==MAXIMUS-1j==MAXIMUS-1)
return?"┛";
else?if(i==0j==MAXIMUS-1)
return?"┗";
else?if(i==0)
return?"┠";
else?if(i==MAXIMUS-1)
return?"┨";
else?if(j==0)
return?"┯";
else?if(j==MAXIMUS-1)
return?"┷";
return?"┼";//中間的空位
}
char*?getCurse(int?i,int?j)//獲得指定坐標(biāo)交點(diǎn)位置左上格的樣式,通過(guò)制表符來(lái)模擬光標(biāo)的顯示
{
if(i==Cx)
{
if(j==Cy)
return?"┏";
else?if?(j==Cy+1)
return?"┗";
}
else?if(i==Cx+1)
{
if(j==Cy)
return?"┓";
else?if?(j==Cy+1)
return?"┛";
}
return?" ";//如果不在光標(biāo)附近則為空
}
void?write(char*?c)//向緩沖器寫入字符串
{
Copy(buff[wl]+wp,c);
wp+=strlen(c);
}
void?ln()//緩沖器寫入位置提行
{
wl+=1;
wp=0;
}
void?Display()//將緩沖器內(nèi)容輸出到屏幕
{
int?i,l=strlen(showText);//循環(huán)變量,中間文字信息的長(zhǎng)度
int?Offset=MAXIMUS*2+2-l/2;//算出中間文字信息居中顯示所在的橫坐標(biāo)位置
if(Offset%2==1)//如果位置為奇數(shù),則移動(dòng)到偶數(shù),避免混亂
{
Offset--;
}
Copy(buff[MAXIMUS]+Offset,showText);//講中間文字信息復(fù)制到緩沖器
if(l%2==1)//如果中間文字長(zhǎng)度為半角奇數(shù),則補(bǔ)上空格,避免混亂
{
*(buff[MAXIMUS]+Offset+l)=0x20;
}
system("cls");//清理屏幕,準(zhǔn)備寫入
for(i=0;iMAXIMUS*2+1;i++)//循環(huán)寫入每一行
{
printf("%s",buff[i]);
if(iMAXIMUS*2)//寫入完每一行需要換行
printf("\n");
}
}
void?Print()//將整個(gè)棋盤算出并儲(chǔ)存到緩沖器,然后調(diào)用Display函數(shù)顯示出來(lái)
{
int?i,j;//循環(huán)變量
wl=0;
wp=0;
for(j=0;j=MAXIMUS;j++)//寫入出交點(diǎn)左上角的字符,因?yàn)樾枰蛴∑灞P右下角,所以很以橫縱各多一次循環(huán)
{
for(i=0;i=MAXIMUS;i++)
{
write(getCurse(i,j));//寫入左上角字符
if(j==0||j==MAXIMUS)//如果是棋上下盤邊緣則沒(méi)有連接的豎線,用空格填充位置
{
if(i!=MAXIMUS)
write(" ");
}
else//如果在棋盤中間則用豎線承接上下
{
if(i==0||i==MAXIMUS-1)//左右邊緣的豎線更粗
write("┃");
else?if(i!=MAXIMUS)//中間的豎線
write("│");
}
}
if(j==MAXIMUS)//如果是最后一次循環(huán),則只需要處理邊側(cè)字符,交點(diǎn)要少一排
{
break;
}
ln();//提行開始打印交點(diǎn)內(nèi)容
write(" ");//用空位補(bǔ)齊位置
for(i=0;iMAXIMUS;i++)//按橫坐標(biāo)循環(huán)正常的次數(shù)
{
write(getStyle(i,j));//寫入交點(diǎn)字符
if(i!=MAXIMUS-1)//如果不在最右側(cè)則補(bǔ)充一個(gè)橫線承接左右
{
if(j==0||j==MAXIMUS-1)
{
write("━");//上下邊緣的橫線更粗
}
else
{
write("—");//中間的橫線
}
}
}
ln();//寫完一行后提行
}
Display();//將緩沖器內(nèi)容輸出到屏幕
}
int?Put()//在當(dāng)前光標(biāo)位置走子,如果非空,則返回0表示失敗
{
if(p[Cx][Cy]==0)
{
p[Cx][Cy]=Now;//改變?cè)撐恢脭?shù)據(jù)
return?1;//返回1表示成功
}
else
{
return?0;
}
}
int?Check()//勝負(fù)檢查,即判斷當(dāng)前走子位置有沒(méi)有造成五連珠的情況
{
int?w=1,x=1,y=1,z=1,i;//累計(jì)橫豎正斜反邪四個(gè)方向的連續(xù)相同棋子數(shù)目
for(i=1;i5;i++)//向下檢查
if(Cy+iMAXIMUSp[Cx][Cy+i]==Now)
w++;
else?
break;
for(i=1;i5;i++)//向上檢查
if(Cy-i0p[Cx][Cy-i]==Now)
w++;
else?
break;
if(w=5)//若果達(dá)到5個(gè)則判斷當(dāng)前走子玩家為贏家
return?Now;
for(i=1;i5;i++)//向右檢查
if(Cx+iMAXIMUSp[Cx+i][Cy]==Now)
x++;
else?
break;
for(i=1;i5;i++)//向左檢查
if(Cx-i0p[Cx-i][Cy]==Now)
x++;
else?
break;
if(x=5)//若果達(dá)到5個(gè)則判斷當(dāng)前走子玩家為贏家
return?Now;
for(i=1;i5;i++)//向右下檢查
if(Cx+iMAXIMUSCy+iMAXIMUSp[Cx+i][Cy+i]==Now)
y++;
else?
break;
for(i=1;i5;i++)//向左上檢查
if(Cx-i0Cy-i0p[Cx-i][Cy-i]==Now)
y++;
else?
break;
if(y=5)//若果達(dá)到5個(gè)則判斷當(dāng)前走子玩家為贏家
return?Now;
for(i=1;i5;i++)//向右上檢查
if(Cx+iMAXIMUSCy-i0p[Cx+i][Cy-i]==Now)
z++;
else?
break;
for(i=1;i5;i++)//向左下檢查
if(Cx-i0Cy+iMAXIMUSp[Cx-i][Cy+i]==Now)
z++;
else?
break;
if(z=5)//若果達(dá)到5個(gè)則判斷當(dāng)前走子玩家為贏家
return?Now;
return?0;//若沒(méi)有檢查到五連珠,則返回0表示還沒(méi)有玩家達(dá)成勝利
}
int?RunGame()//進(jìn)行整個(gè)對(duì)局,返回贏家信息(雖然有用上)
{
int?input;//輸入變量
int?victor;//贏家信息
Initialize();//初始化對(duì)局
while(1)//開始無(wú)限回合的死循環(huán),直到出現(xiàn)勝利跳出
{
Print();//打印棋盤
input=getch();//等待鍵盤按下一個(gè)字符
if(input==27)//如果是ESC則退出程序
{
exit(0);
}
else?if(input==0x20)//如果是空格則開始走子
{
if(Put())//如果走子成功則判斷勝負(fù)
{
victor=Check();
Now=3-Now;//輪換當(dāng)前走子玩家
count++;
if(victor==1)//如果黑方達(dá)到勝利,顯示提示文字并等待一次按鍵,返回勝利信息
{
showText="黑方獲得了勝利!";
Print();
if(getch()==0xE0)
{
getch();
}
return?Now;
}
else?if(victor==2)//如果白方達(dá)到勝利,顯示提示文字并等待一次按鍵,返回勝利信息
{
showText="白方獲得了勝利!";
Display();
if(getch()==0xE0)
{
getch();
}
return?Now;
}
else?if(count==MAXIMUS*MAXIMUS)//如果回合數(shù)達(dá)到了棋盤總量,即棋盤充滿,即為平局
{
showText="平局!";
Display();
if(getch()==0xE0)
{
getch();
}
return?0;
}
}
}
else?if(input==0xE0)//如果按下的是方向鍵,會(huì)填充兩次輸入,第一次為0xE0表示按下的是控制鍵
{
input=getch();//獲得第二次輸入信息
switch(input)//判斷方向鍵方向并移動(dòng)光標(biāo)位置
{
case?0x4B:
Cx--;
break;
case?0x48:
Cy--;
break;
case?0x4D:
Cx++;
break;
case?0x50:
Cy++;
break;
}
if(Cx0)//如果光標(biāo)位置越界則移動(dòng)到對(duì)側(cè)
Cx=MAXIMUS-1;
if(Cy0)
Cy=MAXIMUS-1;
if(CxMAXIMUS-1)
Cx=0;
if(CyMAXIMUS-1)
Cy=0;
}
}
}
int?main()//主函數(shù)
{
system("title?簡(jiǎn)易五子棋?——Etsnarl制作");//設(shè)置標(biāo)題
system("mode?con?cols=63?lines=32");//設(shè)置窗口大小
system("color?E0");//設(shè)置顏色
while(1)//循環(huán)執(zhí)行游戲
{
RunGame();
}
return?0;
}
按照五子棋規(guī)則,當(dāng)一方的棋子,在橫向,縱向或斜向連續(xù)五個(gè)均為同一用戶的棋子時(shí),代表勝利。
另外,勝利判斷只需要在一個(gè)新子落子時(shí)判斷,且僅需要判斷新子所在的四條線上(縱橫加兩個(gè)斜線)是否滿足條件即可。
所以,可以以新子坐標(biāo)為基準(zhǔn)點(diǎn),判斷四次。
比如橫向的,需要判斷左側(cè)和右側(cè)連續(xù)的同類棋子個(gè)數(shù),如果左側(cè)+右側(cè)+1(自身)總數(shù)=5,則為勝利。
參考代碼如下:
static?int?map[100][100];?//?全局變量棋盤。未下子時(shí)值為0,下子時(shí)值為1或2,區(qū)分下子人。
int?check_win(int?m,?int?n)
{
int?total?=?1;?
int?i;
for(i?=?m-1;?i?=?0;?i?--)//統(tǒng)計(jì)同行左側(cè)連續(xù)同樣棋子個(gè)數(shù)。
if(map[i][n]?==?map[m][n])?total++;
else?break;
for(i?=?m+1;?i??100;?i?++)//統(tǒng)計(jì)同行右側(cè)連續(xù)同樣棋子個(gè)數(shù)。
if(map[i][n]?==?map[m][n])?total++;
else?break;
if(total=5)?return?1;//勝利。
return?0;?//沒(méi)有勝利。
}
其它類似。
下一個(gè)新的子在weizhi處,然后以這個(gè)子為基準(zhǔn)來(lái)判斷,case
0為例,橫著判斷-》贏得可能性有:這個(gè)子是5個(gè)子最右邊的子……這個(gè)子是五個(gè)子最左邊的子。所以贏得可能性中,那最左邊的子的坐標(biāo)就是weizhi.x-4,weizhi.y
即count=4,然后一次判斷左邊第三個(gè)子,第二個(gè)子,……右邊第四個(gè)子,如果有連續(xù)的5個(gè)子(通過(guò)count2或3的值來(lái)判斷)就算贏了。