欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

五子棋的c语言源码

程序员文章站 2022-07-03 20:35:01
这是实现五子棋落子和判断胜负的源代码,电脑落子涉及的人工智能算法(目前AI属于弱智的随机落子)暂时没有实现。本文重点讲一下胜负判断功能的实现,我们都知道五子棋中获胜的条件就是五联...

这是实现五子棋落子和判断胜负的源代码,电脑落子涉及的人工智能算法(目前AI属于弱智的随机落子)暂时没有实现。本文重点讲一下胜负判断功能的实现,我们都知道五子棋中获胜的条件就是五联子,而五联子的方向有四种:水平、竖直和两个对角线方向。扫描的思想是在每个落子的位置判断各个方向能扫描的次数(最多为5)。以水平方向为例,数组下标为【5】【5】的从【5】【0】开始判断连往右的五个坐标(即数组元素)的值是否相等,如果是则表明获胜。

#include

#include


#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;

};



//定义一个二维数组来充当棋盘

const char *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;>

{

for (int k =0; 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;>

{

printf("%02d ",i);

for (int k =0; 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

{

temp=x

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

{

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(x3)

{

temp=(abs(x-7))>=(abs(y-7))?x:y;

count=7-abs(temp-7);

}

else if (x>3&&y

{

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;

}





11&&y>