五子棋的c語言原始碼
這是實現五子棋落子和判斷勝負的原始碼,電腦落子涉及的人工智慧演算法(目前AI屬於弱智的隨機落子)暫時沒有實現。本文重點講一下勝負判斷功能的實現,我們都知道五子棋中獲勝的條件就是五聯子,而五聯子的方向有四種:水平、豎直和兩個對角線方向。掃描的思想是在每個落子的位置判斷各個方向能掃描的次數(最多為5)。以水平方向為例,陣列下標為【5】【5】的從【5】【0】開始判斷連往右的五個座標(即陣列元素)的值是否相等,如果是則表明獲勝。
#include <stdio.h>
#include <stdlib.h>
#define NO_CHESS "十"
#define RED_CHESS "
#define BLACK_CHESS "♠️"
#define BOARD_SIZE 15 //定義棋盤的大小
typedef int DataType;
struct Stack
{
DataType arr[BOARD_SIZE][BOARD_SIZE];
int top;
};
//定義一個二維陣列來充當棋盤
constchar *Chesses[BOARD_SIZE][BOARD_SIZE];
//----函式的宣告-----
//初始化棋盤
void initChess(void);
//輸出棋盤
void prChess(void);
//判斷輸贏
void winJudge(char* corlor,int x,int y);
//提示獲得勝利
void printWin(char* color);
//橫向掃描函式
void horizonScan(char* color,int x,int y);
//縱向掃描函式
void verticalScan(char* color,int x,int y);
//正對角線掃描函式
void diagonalScan(char* color,int x,int y);
//反對角線掃描函式
void opposeDiagonalScan(char* color,int x,int y);
//悔棋函式
void retract();
//-----函式的實現-----
//初始化棋盤
void initChess(void)
{
//把每一個元素賦值為 "十" 用於控制檯畫出棋盤
for (int i =0; i<BOARD_SIZE; i++)
{
for (int k =0; k<BOARD_SIZE; k++)
{
Chesses[i][k] = NO_CHESS;
}
}
}
//輸出棋盤
void prChess(void)
{
printf(" 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14\n");
//列印每個陣列元素的值
for (int i =0; i<BOARD_SIZE; i++)//行
{
printf("%02d ",i);
for (int k =0; k<BOARD_SIZE; k++)//列
{
printf("%s ",Chesses[i][k]);
}
//換行
printf("\n");
}
}
//判斷輸贏
void winJudge(char* color,int x,int y)
{
//橫向掃描
horizonScan(color, x, y);
//縱向掃描
verticalScan(color, x, y);
//對角線方向掃描
diagonalScan(color, x, y);
//反對角線方向掃描
opposeDiagonalScan(color, x, y);
}
//橫向掃描函式
void horizonScan(char* color,int x,int y)
{
//count儲存掃描的次數
int count;
//儲存變數
int sign;
if((8-abs(y-7))>4)
{
count=4;
}else{
count=7-abs(y-7);
}
//4-10列掃描五次,0和14列掃描一次;其中0列從當前位置開始掃描,而14列從10列掃描;其他列類似
for (int i=count; i>=0; i--)
{
//前4列只能掃描到第0列,不能越界
if (y>7)
{
sign=i-4;
}else
{
sign=0-i;
}
//掃描是否五聯子
if ((*Chesses[x][y+sign]==*color)&&(*Chesses[x][y+sign+1]==*color)&&(*Chesses[x][y+sign+2]==*color)&&(*Chesses[x][y+sign+3]==*color)&&(*Chesses[x][y+sign+4]==*color))
printWin(color);
}
}
//縱向掃描函式
void verticalScan(char* color,int x,int y)
{
//count儲存掃描的次數
int count;
//儲存變數
int sign;
if((8-abs(x-7))>4)
{
count=4;
}else
{
count=7-abs(x-7);
}
//4-10行掃描五次,0和14行掃描一次;其中0行從當前位置開始掃描,而14行列從10行掃描;其他行類似
for (int i=count; i>=0; i--)
{
//前4行只能掃描到第0行,不能越界
if (x>7)
{
sign=i-4;
}else
{
sign=0-i;
}
//掃描是否五聯子
if ((*Chesses[x+sign][y]==*color)&&(*Chesses[x+sign+1][y]==*color)&&(*Chesses[x+sign+2][y]==*color)&&(*Chesses[x+sign+3][y]==*color)&&(*Chesses[x+sign+4][y]==*color))
printWin(color);
}
}
//對角線掃描函式/Users/tarena0036/Desktop/螢幕快照 2016-05-04下午2.16.17.png
void diagonalScan(char* color,int x,int y)
{
//count用於儲存掃描的次數
int count;
//儲存變數
int sign;
//用於儲存臨時資料
int temp;
if((8-abs(x-7))>4&&(8-abs(y-7))>4)
{
count=4;
}
else if(x<11&&y<11)
{
temp=x<=y?x:y;
count=7-abs(temp-7);
}
else if (x>3&&y>3)
{
temp=x>=y?x:y;
count=7-abs(temp-7);
}
else if (abs(x-y)==10)
{
count=0;
}
else if (abs(x-y)==9)
{
count=1;
}
else if (abs(x-y)==8)
{
count=2;
}
else
{
//其他情況無需掃描
count=-1;
}
//(4-10)*(4-10)區域掃描五次,0和14行/列掃描一次;其中0行/列從當前位置開始掃描,而14行/列從10行/列掃描;其他行類似
for (int i=count; i>=0; i--)
{
//前4行只能掃描到第0行,不能越界
if (x+y<14)
{
if (x==11||y==11)
{
sign=-(i+1);
}
else
sign=-i;
}else
{
if (x==2||y==2)
{
sign=i-2;
}
else if (x==3||y==3)
{
sign=i-3;
}
else
sign=i-4;
}
//掃描是否五聯子
if ((*Chesses[x+sign][y+sign]==*color)&&(*Chesses[x+sign+1][y+sign+1]==*color)&&(*Chesses[x+sign+2][y+sign+2]==*color)&&(*Chesses[x+sign+3][y+sign+3]==*color)&&(*Chesses[x+sign+4][y+sign+4]==*color))
printWin(color);
}
}
//反對角線掃描
void opposeDiagonalScan(char* color,int x,int y)
{
//count用於儲存掃描的次數
int count;
//儲存變數
int sign;
//用於儲存臨時資料
int temp;
if((8-abs(x-7))>4&&(8-abs(y-7))>4)
{
count=4;
}
else if(x<11&&y>3)
{
temp=(abs(x-7))>=(abs(y-7))?x:y;
count=7-abs(temp-7);
}
else if (x>3&&y<11)
{
temp=(abs(x-7))>=(abs(y-7))?x:y;
count=7-abs(temp-7);
}
else if ((x+y)==4||(x+y)==24)
{
count=0;
}
else if ((x+y)==5||(x+y)==23)
{
count=1;
}
else if ((x+y)==6||(x+y)==22)
{
count=2;
}
else
{
//其他情況無需掃描
count=-1;
}
//(4-10)*(4-10)區域掃描五次,0和14行/列掃描一次;其中0行/列從當前位置開始掃描,而14行/列從10行/列掃描;其他行類似
for (int i=count; i>=0; i--)
{
//前4行只能掃描到第0行,不能越界
if (x>y)
{
if (x==3||y==11)
{
sign=i+1;
}
else
sign=i;
}else
{
if (x==12||y==2)
{
sign=i+2;
}
else if (x==11||y==3)
{
sign=i+3;
}
else
sign=i+4;
}
//掃描是否五聯子
if ((*Chesses[x+sign][y-sign]==*color)&&(*Chesses[x+sign-1][y-sign+1]==*color)&&(*Chesses[x+sign-2][y-sign+2]==*color)&&(*Chesses[x+sign-3][y-sign+3]==*color)&&(*Chesses[x+sign-4][y-sign+4]==*color))
printWin(color);
}
}
//悔棋功能
void retract()
{
}
//輸出獲勝資訊
void printWin(char* color)
{
printf("%s Win!\n",color);
//結束程式
exit(1);
}
//主函式
int main(int argc,const char * argv[])
{
//初始化二維陣列,儲存棋盤座標點的是否已經有棋子資訊
int info1[BOARD_SIZE][BOARD_SIZE]={0};
//定義棧,用於儲存座標,悔棋時取出棧頂元素將對應位置的點復位
//呼叫函式
initChess();
prChess();
//開始迴圈下棋
while (1)
{
int xPos;
int yPos;
menu:
printf("請輸入您下棋的座標,如x y(輸入15 15為悔棋) \n");
scanf("%d %d",&xPos,&yPos);
if (xPos>BOARD_SIZE||yPos>BOARD_SIZE)
{
printf("請在邊界內輸入有效數字!\n");
goto menu;
}
else if(xPos==BOARD_SIZE&&yPos==BOARD_SIZE)
{
retract();
}
if (1==info1[xPos][yPos])
{
printf("您輸入的位置已經有棋子,請重新輸入:\n");
goto menu;
}
//將已經落子的點標記為1
info1[xPos][yPos]=1;
//把對應的陣列元素賦值成紅棋
Chesses[xPos][yPos] = RED_CHESS;
//重新整理棋盤
prChess();
//判斷是否獲勝
winJudge(Chesses[xPos][yPos],xPos,yPos);
int macXPos,macYPos;
macPosition:
//隨機生成2個 0~15之間的數作為電腦下棋的座標
macXPos = arc4random()%BOARD_SIZE;
macYPos = arc4random()%BOARD_SIZE;
//判斷生成的座標的對應的點是否已經有棋子了
if (1==info1[macXPos][macYPos])
{
goto macPosition;
}
//將電腦下棋的座標賦值 為 黑旗
Chesses[macXPos][macYPos] = BLACK_CHESS;
//將已經落子的點標記為1
info1[macXPos][macYPos]=1;
//重新整理棋盤
prChess();
//判斷黑棋是否獲勝
winJudge(Chesses[macXPos][macYPos],macXPos,macYPos);
}
/*
上面的程式碼還涉及到如下需要改進的地方
1、使用者輸入座標的有效性,只能是數字,不能超出棋盤的範圍(暫時沒有對整個棋盤是否落滿子進行判斷)
2、如果是已經下棋的點,不能重複下棋(實現)
3、每次下棋後,需要掃描誰贏了
4、悔棋功能
*/
return 0;
}