C語(yǔ)言實(shí)現(xiàn)五子棋人人對(duì)戰(zhàn)
利用簡(jiǎn)單的c語(yǔ)言基礎(chǔ)實(shí)現(xiàn)最簡(jiǎn)單的功能,界面比較丑陋主要是剛學(xué)完c的一個(gè)小實(shí)踐,未使用MFC所以界面沒(méi)有很好看 ,主要目的加強(qiáng)對(duì)c語(yǔ)言的理解與運(yùn)用,同時(shí)增加自己的代碼量。

首先要學(xué)一些頭文件可以看我的博客前面的文章
要用到到的頭文件stdio.h stdlib.h windows.h time.h conio.h
思路就是
1.畫(huà)個(gè)棋盤(pán),使用數(shù)組來(lái)代替初始化出*
2.使用循環(huán)使雙方輪流下棋,使用數(shù)組存放棋子的位置
3.判斷是否有一方獲勝
首先打印棋盤(pán)
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
char qipan[16][16];
//函數(shù)聲明
void initQipan();//將*存入16*16的二維數(shù)組中
void printQipan();//將二維數(shù)組打印出來(lái)
void initQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
for(j = 0;j <16 ;j++)
qipan[i][j] = '*';
}
void printQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
printf("%c",qipan[i][j]);
printf("\n");
}
}
int main()
{
initQipan();
printQipan();
}
打印出來(lái)效果圖

這里面我發(fā)現(xiàn)一個(gè)算是c語(yǔ)言的小陷阱
void printQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
printf("%c",qipan[i][j]);
printf("\n");
}
}
這段代碼中內(nèi)層for循環(huán)后跟著兩個(gè)語(yǔ)句但是按正常想法應(yīng)該兩條語(yǔ)句都應(yīng)隨著內(nèi)層循環(huán)而循環(huán)也就是打出來(lái)的應(yīng)該是這樣

打印出來(lái)這樣的代碼是
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
{
printf("%c",qipan[i][j]);
printf("\n");
}
}
但是顯然他們的效果不等價(jià)
這樣其實(shí)是因?yàn)槿绻麅?nèi)層沒(méi)有寫(xiě)出{}就會(huì)默認(rèn)將第一條指令給內(nèi)層,其余所有指令給外層
可以看下面的代碼
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
printf("%c",qipan[i][j]);
printf(",");
printf("\n");
}
}

這樣很顯然得出結(jié)論
在這樣結(jié)構(gòu)的雙重for循環(huán)中
for()
{
for()
語(yǔ)句1
語(yǔ)句2
語(yǔ)句3
...
}
只有第一條語(yǔ)句屬于內(nèi)存循環(huán),寫(xiě)成這樣更加明了一些
for()
{
for()
語(yǔ)句1
語(yǔ)句2
語(yǔ)句3
...
}
下面實(shí)現(xiàn)雙方輪流下棋
/*************************************頭文件********************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
/************************************全局變量********************************************/
char qipan[16][16];
int x,y;
/************************************函數(shù)聲明********************************************/
void initQipan();//將*存入16*16的二維數(shù)組中
void printQipan();//將二維數(shù)組打印出來(lái)
void starGame();//開(kāi)始游戲
/************************************自定義函數(shù)******************************************/
void initQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
for(j = 0;j <16 ;j++)
qipan[i][j] = '*';
}
void printQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
printf("%c",qipan[i][j]);
printf("\n");
}
}
void starGame()
{
initQipan();
printQipan();
while(1)
{
printf("請(qǐng)白方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);
qipan[x][y]='W';
system("cls");
printQipan();
printf("請(qǐng)黑方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);
qipan[x][y]='B';
system("cls");
printQipan();
}
}
/*****************************************主函數(shù)****************************************/
int main()
{
starGame();
}
現(xiàn)在可以實(shí)現(xiàn)雙方輪流下棋,接下來(lái)就是要實(shí)現(xiàn)系統(tǒng)去判定是否有人獲勝
/*********************************************************************頭文件*************************************************************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
/********************************************************************全局變量************************************************************************************/
char qipan[16][16];
int x,y;
/********************************************************************函數(shù)聲明************************************************************************************/
void initQipan();//將*存入16*16的二維數(shù)組中
void printQipan();//將二維數(shù)組打印出來(lái)
void starGame();//開(kāi)始游戲
int panduan(int x,int y);//判斷是否有人獲勝
void win(int winner);//有人獲勝后顯示那方勝利
/********************************************************************自定義函數(shù)**********************************************************************************/
void initQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
for(j = 0;j <16 ;j++)
qipan[i][j] = '*';
}
void printQipan()
{
int i,j;
for(i = 0;i < 16 ;i++)
{
for(j = 0;j <16 ;j++)
printf("%c",qipan[i][j]);
printf("\n");
}
}
void starGame()
{
int temp;
initQipan();
printQipan();
while(1)
{
printf("請(qǐng)白方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);
qipan[x][y]='W';
system("cls");
printQipan();
temp = panduan(x,y);
if(temp==1)
{
printf("白方獲勝");
system("pause");
}
printf("請(qǐng)黑方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);
qipan[x][y]='B';
system("cls");
printQipan();
temp = panduan(x,y);
if(temp==2)
{
printf("黑方獲勝");
system("pause");
}
}
}
int panduan(int x,int y)
{
char temp;//保存棋子的顏色
int winner;//1代表白方,2代表黑方
int i;//距離落子位置水平方向的差
int j;//距離落子位置豎直方向的差
int count;//記下有多少個(gè)連續(xù)的棋子
count = 1;
i = 1;
j = 1;
winner = 0;
temp = qipan[x][y];
//***************************************************************************水平方向**************************************************************************
//水平左邊
while(temp = qipan[x-i][y]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
count++;
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//水平右邊
i = 1;//因?yàn)橐匦聫囊桓耖_(kāi)始移動(dòng),初始化i變量
while(temp = qipan[x+i][y]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
count++;//此時(shí)count是接著水平左邊繼續(xù)累加
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//**************************************************************************豎直方向***************************************************************************
//豎直上方
i = 1;//初始化變量
count = 1;//初始化變量
while(temp = qipan[x][y+j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
j++;
count++;
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//豎直下方
i = 1;//因?yàn)橐匦聫囊桓耖_(kāi)始移動(dòng),初始化i變量
while(temp = qipan[x][y-j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
j++;
count++;//此時(shí)count是接著水平左邊繼續(xù)累加
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//**************************************************************************從左向右傾斜***********************************************************************
//左上方
i = 1;//初始化變量
count = 1;//初始化變量
while(temp = qipan[x-i][y-j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
j++;
count++;
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//右下方
i = 1;//因?yàn)橐匦聫囊桓耖_(kāi)始移動(dòng),初始化i變量
while(temp = qipan[x+i][y+j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
j++;
count++;//此時(shí)count是接著水平左邊繼續(xù)累加
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//**************************************************************************從右向左傾斜***********************************************************************
//右上方
i = 1;//初始化變量
count = 1;//初始化變量
while(temp = qipan[x-i][y+j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
j++;
count++;
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
//左下方
i = 1;//因?yàn)橐匦聫囊桓耖_(kāi)始移動(dòng),初始化i變量
while(temp = qipan[x+i][y-j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
{
i++;
j++;
count++;//此時(shí)count是接著水平左邊繼續(xù)累加
if(count==5)//如果連成五子出現(xiàn)勝利的一方,否則繼續(xù)判斷
{
if(temp=='W')
winner = 1;
else
winner = 2;
}
}
return winner;
}
/*******************************************************************主函數(shù)**************************************************************************************/
int main()
{
starGame();
return 0;
}
此時(shí)有一個(gè)問(wèn)題就是程序會(huì)卡死如圖

在寫(xiě)程序時(shí)出現(xiàn)這種錯(cuò)誤可能的原因是:
①除以零
②數(shù)組越界:int a[3]; a[10000000]=10;
③指針越界:int * p; p=(int *)malloc(5 * sizeof(int)); *(p+1000000)=10;
④使用已經(jīng)釋放的空間:int * p; p=(int *)malloc(5 * sizeof(int));free(p); *p=10;
⑤數(shù)組開(kāi)得太大,超出了棧的范圍,造成棧溢出:int a[100000000]
ok發(fā)現(xiàn)問(wèn)題是在如圖位置沒(méi)有初始化這幾個(gè)變量現(xiàn)在已經(jīng)將上面的代碼修正了

下面來(lái)看最后優(yōu)化完的代碼
/***************************************頭文件******************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
/****************************************宏*********************************************/
#define N 16 //可以更改棋盤(pán)大小
/***************************************全局變量*****************************************/
char qipan[N][N];//全局變量,整個(gè)文件的都可以用
int x,y;//代表的是棋盤(pán)(數(shù)組)下標(biāo)為x的行 和 下標(biāo)為y列的一個(gè)交點(diǎn)
/***************************************函數(shù)聲明*****************************************/
void initQipan();//棋盤(pán)的初始化
void printQipan();//打印棋盤(pán)
void Pos(int x, int y);//設(shè)置光標(biāo)位置
void startGame();//游戲開(kāi)始
int panduan(int x,int y);//判斷是否有人連成五子
int showWhoWin();//輸出誰(shuí)贏了
void whitePlay();//白方下子
void blackPlay();//黑方下子
void printShuzi();//打印數(shù)字模板
/*****************************************自定義函數(shù)*************************************/
void Pos(int x, int y)//設(shè)置光標(biāo)位置,從哪里開(kāi)始輸出
{
COORD pos;//表示一個(gè)字符在控制臺(tái)屏幕上的坐標(biāo),左上角(0,0)
HANDLE hOutput;
pos.X = x;
pos.Y = y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//返回標(biāo)準(zhǔn)的輸入、輸出或錯(cuò)誤的設(shè)備的句柄,也就是獲得輸入、輸出/錯(cuò)誤的屏幕緩沖區(qū)的句柄
SetConsoleCursorPosition(hOutput, pos);
}
void printShuzi()
{
int i;
Pos(2,0);
for(i=0;i<N;i++)
printf("%2d",i);
for(i=0;i<16;i++)
{
Pos(0,1+i);
printf("%2d",i);
}
}
void initQipan()
{
int i,j;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
qipan[i][j]='*';
}
void printQipan()
{
int i,j;
printShuzi();
for(i=0;i<N;i++)
{
Pos(2,1+i);//自動(dòng)換行的輸出的功能,代替printf("\n");
for(j=0;j<N;j++)
printf(" %c",qipan[i][j]);
}
}
int panduan(int x,int y)
{
char temp;//保存下棋方的顏色,w b
int count=1;//統(tǒng)計(jì)個(gè)數(shù),針對(duì)的同一個(gè)線(水平線)
int i=1;//走一格
int j=1;//和i同時(shí)用來(lái)代表走斜的
int whoWin=0;//1代表白方,2代表黑方
temp=qipan[x][y];
//水平的左邊
while(temp==qipan[x][y-i]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//水平的右邊
i=1;
while(temp==qipan[x][y+i]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//解決垂直的方向
//垂直上方
i=1;
count=1;//清理掉之前的數(shù)據(jù)
while(temp==qipan[x-i][y]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//垂直下方
i=1;
while(temp==qipan[x+i][y]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//解決左上的斜線 上方
i=1;
j=1;
count=1;
while(temp==qipan[x-i][y-j]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
j++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//解決左上的斜線 下方
i=1;
j=1;
while(temp==qipan[x+i][y+j]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
j++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//解決右上的斜線 上方
i=1;
j=1;
count=1;
while(temp==qipan[x-i][y+j]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
j++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
//解決右上的斜線 下方
i=1;
j=1;
while(temp==qipan[x+i][y-j]&&x>=0&&x<N&&y>=0&&y<N&&count<5)
{
i++;
j++;
count++;
if(count==5)//首先count是5才能來(lái)判斷誰(shuí)贏了
{
if(temp=='W')
whoWin=1;
else
whoWin=2;
}
}
return whoWin;
}
int showWhoWin()
{
int overLeap=0;//1代表結(jié)束
int leap;//用來(lái)接收誰(shuí)贏了
leap=panduan(x,y);
if(leap==1)
{
overLeap=1;
system("cls");
printQipan();
printf("\n白方勝利\n");
system("pause");
}
if(leap==2)
{
overLeap=1;
system("cls");
printQipan();
printf("\n黑方勝利\n");
system("pause");
}
return overLeap;
}
void whitePlay()
{
printf("\n請(qǐng)白方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);//坐標(biāo)的值
while(1)//解決一直下錯(cuò)子的問(wèn)題
{
if(qipan[x][y]=='*')//下子的地方?jīng)]有其他子
{
qipan[x][y]='W';
//解決while(1)
break;
}
else
{
printf("您下子錯(cuò)誤\n");
printf("請(qǐng)白方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);//坐標(biāo)的值
}
}
printQipan();
}
void blackPlay()
{
printQipan();
printf("\n請(qǐng)黑方落子,按下行與列的坐標(biāo):");
scanf("%d%d",&x,&y);//坐標(biāo)的值
while(1)//解決一直下錯(cuò)子的問(wèn)題
{
if(qipan[x][y]=='*')//下子的地方?jīng)]有其他子
{
qipan[x][y]='B';
//解決while(1)
break;
}
else
{
printf("您下子錯(cuò)誤\n");
printf("請(qǐng)黑方落子,按下行與列的坐標(biāo):");
}
scanf("%d%d",&x,&y);//坐標(biāo)的值
}
printQipan();
}
void startGame()
{
initQipan();
printQipan();
while(1)
{
whitePlay();
if(showWhoWin()==1)//system("pause");
break;
system("cls");//清理屏幕,是屏幕上的字不重復(fù)
blackPlay();
if(showWhoWin()==1)//system("pause");
break;
system("cls");
printQipan();
}
printf("您是否重新游戲:y or n");
if(getch()=='n')
{
system("cls");
printf("游戲結(jié)束\n");
exit(0);//因?yàn)槌绦蚪K止
}
if(getch()=='y')
{
system("cls");
startGame();
}
}
/*********************************************主函數(shù)************************************/
int main()
{
startGame();
return 0;
}
下面測(cè)試一下功能



以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言自定義函數(shù)的實(shí)現(xiàn)
這篇文章主要介紹了C語(yǔ)言自定義函數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
從txt中讀入數(shù)據(jù)到數(shù)組中(fscanf)的實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇從txt中讀入數(shù)據(jù)到數(shù)組中(fscanf)的實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
C++標(biāo)準(zhǔn)庫(kù)介紹及使用string類(lèi)的詳細(xì)過(guò)程
C++中將string封裝為單獨(dú)的類(lèi),string?類(lèi)是?C++?標(biāo)準(zhǔn)庫(kù)中的一個(gè)非常重要的類(lèi),用于表示和操作字符串,這篇文章主要介紹了C++標(biāo)準(zhǔn)庫(kù)介紹及使用string類(lèi),需要的朋友可以參考下2024-08-08
C++實(shí)現(xiàn)二叉樹(shù)非遞歸遍歷方法實(shí)例總結(jié)
這篇文章主要介紹了C++實(shí)現(xiàn)二叉樹(shù)非遞歸遍歷方法實(shí)例總結(jié),是算法設(shè)計(jì)中比較經(jīng)典的一個(gè)遍歷算法,需要的朋友可以參考下2014-08-08
C語(yǔ)言多維數(shù)組數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn)詳解
對(duì)于數(shù)組想必大家都不陌生首先得要知道的是對(duì)于數(shù)組元素在內(nèi)存存儲(chǔ)是連續(xù)性的,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言多維數(shù)組數(shù)據(jù)結(jié)構(gòu)的相關(guān)資料,需要的朋友可以參考下2021-12-12
示例詳解C++語(yǔ)言中的命名空間 (namespace)
C++名字空間是一種描述邏輯分組的機(jī)制,也就是說(shuō),如果有一些聲明按照某種準(zhǔn)則在邏輯上屬于同一個(gè)模塊,就可以將它們放在同一個(gè)名字空間,以表明這個(gè)事實(shí),這篇文章主要給大家介紹了關(guān)于C++語(yǔ)言中命名空間 (namespace)的相關(guān)資料,需要的朋友可以參考下2021-08-08

