1. 程式人生 > >c語言實現五子棋人人對戰

c語言實現五子棋人人對戰

利用簡單的c語言基礎 實現最簡單的功能 介面比較醜陋主要是剛學完c的一個小實踐 未使用MFC所以介面沒有很好看 主要目的加強對c語言的理解與運用 同時增加自己的程式碼量

 

首先要學一些標頭檔案可以看我的部落格前面的文章

要用到到的標頭檔案stdio.h stdlib.h windows.h time.h conio.h

思路就是

1.畫個棋盤,使用陣列來代替初始化出*

2.使用迴圈使雙方輪流下棋,使用陣列存放棋子的位置

3.判斷是否有一方獲勝

首先列印棋盤

#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>

char qipan[16][16];
//函式宣告
void initQipan();//將*存入16*16的二維陣列中
void printQipan();//將二維陣列打印出來

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();  
}

打印出來效果圖

這裡面我發現一個算是c語言的小陷阱

void printQipan()
{
  int i,j;
	for(i = 0;i < 16 ;i++)
	{
	  for(j = 0;j <16 ;j++)
        printf("%c",qipan[i][j]);
      printf("\n");
	}	 
}

這段程式碼中內層for迴圈後跟著兩個語句但是按正常想法應該兩條語句都應隨著內層迴圈而迴圈也就是打出來的應該是這樣

打印出來這樣的程式碼是

  int i,j;
	for(i = 0;i < 16 ;i++)
	{
		for(j = 0;j <16 ;j++)
		{
		printf("%c",qipan[i][j]);
		printf("\n");
		}
		
        
	}
	

但是顯然他們的效果不等價

這樣其實是因為如果內層沒有寫出{}就會預設將第一條指令給內層,其餘所有指令給外層

可以看下面的程式碼

  int i,j;
	for(i = 0;i < 16 ;i++)
	{
		for(j = 0;j <16 ;j++)		
		printf("%c",qipan[i][j]);
		printf(",");
		printf("\n");		        
	}
	
}

這樣很顯然得出結論

在這樣結構的雙重for迴圈中

for()
{
  for()
    語句1
    語句2
    語句3
    ...
}

只有第一條語句屬於記憶體迴圈,寫成這樣更加明瞭一些

for()
{
  for()
    語句1
  語句2
  語句3
  ...
}

下面實現雙方輪流下棋

/*************************************標頭檔案********************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
/************************************全域性變數********************************************/
char qipan[16][16];
int x,y;
/************************************函式宣告********************************************/
void initQipan();//將*存入16*16的二維陣列中
void printQipan();//將二維陣列打印出來
void starGame();//開始遊戲
/************************************自定義函式******************************************/
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("請白方落子,按下行與列的座標:");
  scanf("%d%d",&x,&y);
  qipan[x][y]='W';
  system("cls");
  printQipan();
  printf("請黑方落子,按下行與列的座標:");
  scanf("%d%d",&x,&y);
  qipan[x][y]='B';
  system("cls");
  printQipan();
  }
  
}
/*****************************************主函式****************************************/
int main()
{
  starGame();
}

現在可以實現雙方輪流下棋,接下來就是要實現系統去判定是否有人獲勝

/*********************************************************************標頭檔案*************************************************************************************/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
/********************************************************************全域性變數************************************************************************************/
char qipan[16][16];
int x,y;
/********************************************************************函式宣告************************************************************************************/
void initQipan();//將*存入16*16的二維陣列中
void printQipan();//將二維陣列打印出來
void starGame();//開始遊戲
int panduan(int x,int y);//判斷是否有人獲勝
void win(int winner);//有人獲勝後顯示那方勝利
/********************************************************************自定義函式**********************************************************************************/
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("請白方落子,按下行與列的座標:");
  scanf("%d%d",&x,&y);
  qipan[x][y]='W';
  system("cls");
  printQipan();
  temp = panduan(x,y);
  if(temp==1)
  {
	  printf("白方獲勝");
	  system("pause");
  }
  printf("請黑方落子,按下行與列的座標:");
  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;//記下有多少個連續的棋子
  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)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     if(temp=='W')
		 winner = 1;
	 else 
		 winner = 2;
	}
  }
  //水平右邊
  i = 1;//因為要重新從一格開始移動,初始化i變數
  while(temp = qipan[x+i][y]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
  {
    i++;
    count++;//此時count是接著水平左邊繼續累加
    if(count==5)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     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)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     if(temp=='W')
		 winner = 1;
	 else 
		 winner = 2;
	}
  }
  //豎直下方
  i = 1;//因為要重新從一格開始移動,初始化i變數
  while(temp = qipan[x][y-j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
  {
    j++;
    count++;//此時count是接著水平左邊繼續累加
    if(count==5)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     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)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     if(temp=='W')
		 winner = 1;
	 else 
		 winner = 2;
	}
  }
  //右下方
  i = 1;//因為要重新從一格開始移動,初始化i變數
  while(temp = qipan[x+i][y+j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
  {
    i++;
	j++;
    count++;//此時count是接著水平左邊繼續累加
    if(count==5)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     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)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     if(temp=='W')
		 winner = 1;
	 else 
		 winner = 2;
	}
  }
  //左下方
  i = 1;//因為要重新從一格開始移動,初始化i變數
  while(temp = qipan[x+i][y-j]&&x >= 0&&x <= 15&&y >= 0&&y <= 15&&count < 5)
  {
    i++;
	j++;
    count++;//此時count是接著水平左邊繼續累加
    if(count==5)//如果連成五子出現勝利的一方,否則繼續判斷
	{
     if(temp=='W')
		 winner = 1;
	 else 
		 winner = 2;
	}  
  }
  return winner;
}

/*******************************************************************主函式**************************************************************************************/
int main()
{
  starGame();
  return 0;
}

此時有一個問題就是程式會卡死如圖

在寫程式時出現這種錯誤可能的原因是:

①除以零

②陣列越界:int a[3]; a[10000000]=10;

③指標越界:int * p; p=(int *)malloc(5 * sizeof(int)); *(p+1000000)=10;

④使用已經釋放的空間:int * p; p=(int *)malloc(5 * sizeof(int));free(p); *p=10;

⑤陣列開得太大,超出了棧的範圍,造成棧溢位:int a[100000000]

ok發現問題是在如圖位置沒有初始化這幾個變數現在已經將上面的程式碼修正了

下面來看最後優化完的程式碼

#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
//#define N 16

char qipan[16][16];//全域性變數,整個檔案的都可以用
int x,y;//代表的是棋盤(陣列)下標為x的行 和  下標為y列的一個交點
//函式宣告
void initQipan();//棋盤的初始化
void printQipan();//列印棋盤
void Pos(int x, int y);//設定游標位置
void startGame();//遊戲開始
int panduan(int x,int y);//判斷是否有人連成五子
int showWhoWin();//輸出誰贏了
void whitePlay();//白方下子
void blackPlay();//黑方下子
void printShuzi();//列印數字模板



void Pos(int x, int y)//設定游標位置,從哪裡開始輸出
{
    COORD pos;//表示一個字元在控制檯螢幕上的座標,左上角(0,0)
    HANDLE hOutput;
    pos.X = x;
    pos.Y = y;
    hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//返回標準的輸入、輸出或錯誤的裝置的控制代碼,也就是獲得輸入、輸出/錯誤的螢幕緩衝區的控制代碼
    SetConsoleCursorPosition(hOutput, pos);
}

void printShuzi()
{
	int i;
	Pos(2,0);
	for(i=0;i<16;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<16;i++)
		for(j=0;j<16;j++)
			qipan[i][j]='*';
}
void printQipan()
{
	int i,j;
	printShuzi();
	for(i=0;i<16;i++)
	{
		Pos(2,1+i);//自動換行的輸出的功能,代替printf("\n");
		for(j=0;j<16;j++)
			printf(" %c",qipan[i][j]);
	}
}

int  panduan(int x,int y)
{
	char temp;//儲存下棋方的顏色,w  b
	int count=1;//統計個數,針對的同一個線(水平線)
	int i=1;//走一格
	int j=1;//和i同時用來代表走斜的
	int whoWin=0;//1代表白方,2代表黑方
	temp=qipan[x][y];
	//水平的左邊
	while(temp==qipan[x][y-i]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
	//水平的右邊
	i=1;
   while(temp==qipan[x][y+i]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}

   //解決垂直的方向
   //垂直上方
   i=1;
   count=1;//清理掉之前的資料
   while(temp==qipan[x-i][y]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
   //垂直下方
   i=1;
   while(temp==qipan[x+i][y]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
   //解決左上的斜線  上方
	 i=1;
	 j=1;
	 count=1;
   while(temp==qipan[x-i][y-j]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		j++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
   //解決左上的斜線  下方
	 i=1;
	 j=1;
   while(temp==qipan[x+i][y+j]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		j++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
   //解決右上的斜線  上方
	 i=1;
	 j=1;
	 count=1;
   while(temp==qipan[x-i][y+j]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		j++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
   //解決右上的斜線  下方
	 i=1;
	 j=1;
   while(temp==qipan[x+i][y-j]&&x>=0&&x<16&&y>=0&&y<15&&count<5)
	{
		i++;
		j++;
		count++;
		if(count==5)//首先count是5才能來判斷誰贏了,不然連資格都沒有
		{
			if(temp=='W')
				whoWin=1;
				
			else
				whoWin=2;
		}
	}
	return whoWin;
}

int showWhoWin()
{
	int overLeap=0;//1代表結束
	int leap;//用來接收誰贏了
	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請白方落子,按下行與列的座標:");
	scanf("%d%d",&x,&y);//座標的值
	while(1)//解決一直下錯子的問題
	{
		if(qipan[x][y]=='*')//下子的地方沒有其他子
		{
		     qipan[x][y]='W';
			 //解決while(1)
			 break;
		}
		else
		{
			printf("您下子錯誤\n");
		    printf("請白方落子,按下行與列的座標:");
			scanf("%d%d",&x,&y);//座標的值
		}
		
	}
	printQipan();	
	
}
void blackPlay()
{
	
	printQipan();
	printf("\n請黑方落子,按下行與列的座標:");
	scanf("%d%d",&x,&y);//座標的值
		while(1)//解決一直下錯子的問題
	{
		if(qipan[x][y]=='*')//下子的地方沒有其他子
		{
		     qipan[x][y]='B';
			 //解決while(1)
			 break;
		}
		else
		{
			printf("您下子錯誤\n");
		    printf("請黑方落子,按下行與列的座標:");
		}
		scanf("%d%d",&x,&y);//座標的值
		
	}
	printQipan();
	
}
void startGame()
{
	initQipan();
	printQipan();
	while(1)
	{
		whitePlay();
		if(showWhoWin()==1)//system("pause");
		     break;
	    system("cls");//清理螢幕,是螢幕上的字不重複
		blackPlay();
		if(showWhoWin()==1)//system("pause");
		     break;
		system("cls");
	    printQipan();
	}
	printf("您是否重新遊戲:y  or n");
	if(getch()=='n')
	{
		system("cls");
		printf("遊戲結束\n");
		exit(0);//因為程式終止
	}
	if(getch()=='y')
	{
		system("cls");
		startGame();
	}

}
int main()
{
	startGame();
	return 0;
}