You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wuziqikechengsheji1801/C语言五子棋课程设计代码-黄智.c

472 lines
13 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define MAXIMUS 19 //定义棋盘大小
int p[MAXIMUS][MAXIMUS];//存储对局信息
char buff[MAXIMUS*2+1][MAXIMUS*4+3];//输出缓冲器
int Cx,Cy;//当前光标位置
int Now;//当前走子的玩家1代表黑2代表白
int wl,wp;//当前写入缓冲器的列数和行数位置
char* showText;//在棋盘中央显示的文字信息
int count;//回合数
char* Copy(char* strDest,const char* strSrc);//修改过的字符串复制函数,会忽略末端的\0
void Initialize();//初始化一个对局函数
char* getStyle(int i,int j);//获得棋盘中指定坐标交点位置的字符,通过制表符拼成棋盘
char* getCurse(int i,int j);//获得指定坐标交点位置左上格的样式,通过制表符来模拟光标的显示
void write(char* c);//向缓冲器写入字符串
void ln();//缓冲器写入位置提行
void Display();//将缓冲器内容输出到屏幕
void Print();//将整个棋盘算出并储存到缓冲器然后调用Display函数显示出来
int Put();//在当前光标位置走子如果非空则返回0表示失败
int JugeWin();//胜负检查,即判断当前走子位置有没有造成五连珠的情况
int RunGame();
void welcome();
void help();
void bye();
void DoWin(int v);
void huiqi(int (* p)[MAXIMUS],int num);//定义悔棋函数
int s1=0,s2=0;/*文件操作计分变量*/
void p1_point();/*1p计分文件读取,1p计分文件写入,1p计分文件输出*/
void p2_point();/*2p计分文件读取,2p计分文件写入,2p计分文件输出*/
char* Copy(char* strDest,const char* strSrc)//修改过的字符串复制函数,会忽略末端的\0
{
char* strDestCopy = strDest;
while (*strSrc!='\0')
{
*strDest++=*strSrc++;
}
return strDestCopy;
}
void Initialize()//初始化一个对局函数
{
int i,j;//循环变量
showText="";//重置显示信息
count=0;//回合数归零
for(i=0;i<MAXIMUS;i++)//重置对局数据
{
for(j=0;j<MAXIMUS;j++)
{
p[i][j]=0;
}
}
Cx=Cy=MAXIMUS/2;//重置光标到中央
Now=1;//重置当前为黑方
}
char* getStyle(int i,int j)//获得棋盘中指定坐标交点位置的字符,通过制表符拼成棋盘
{
if(p[i][j]==1)//1为黑子
return "";
else if(p[i][j]==2)//2为白子
return "";
else if(i==0&&j==0)//以下为边缘棋盘样式
return "";
else if(i==0&&j==MAXIMUS-1)
return "";
else if(i==MAXIMUS-1&&j==0)
return "";
else if(i==MAXIMUS-1&&j==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)//获得指定坐标交点位置左上格的样式,通过制表符来模拟光标的显示
{
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 " ";//如果不在光标附近则为空
}
void write(char* c)//向缓冲器写入字符串
{
Copy(buff[wl]+wp,c);
wp+=strlen(c);
}
void ln()//缓冲器写入位置提行
{
wl+=1;
wp=0;
}
void Display()//将缓冲器内容输出到屏幕
{
int i,l=strlen(showText);//循环变量,中间文字信息的长度
int Offset=MAXIMUS*2+2-l/2;//算出中间文字信息居中显示所在的横坐标位置
if(Offset%2==1)//如果位置为奇数,则移动到偶数,避免混乱
{
Offset--;
}
Copy(buff[MAXIMUS]+Offset,showText);//讲中间文字信息复制到缓冲器
if(l%2==1)//如果中间文字长度为半角奇数,则补上空格,避免混乱
{
*(buff[MAXIMUS]+Offset+l)=0x20;
}
system("cls");//清理屏幕,准备写入
for(i=0;i<MAXIMUS*2+1;i++){//循环写入每一行
printf("%s",buff[i]);
if(i<MAXIMUS*2)//写入完每一行需要换行
printf("\n");
}
}
void Print()//将整个棋盘算出并储存到缓冲器然后调用Display函数显示出来
{
int i,j;//循环变量
wl=0;
wp=0;
for(j=0;j<=MAXIMUS;j++)//写入出交点左上角的字符,因为需要打印棋盘右下角,所以很以横纵各多一次循环
{
for(i=0;i<=MAXIMUS;i++)
{
write(getCurse(i,j));//写入左上角字符
if(j==0||j==MAXIMUS)//如果是棋上下盘边缘则没有连接的竖线,用空格填充位置
{
if(i!=MAXIMUS)
write(" ");
}
else//如果在棋盘中间则用竖线承接上下
{
if(i==0||i==MAXIMUS-1)//左右边缘的竖线更粗
write("");
else if(i!=MAXIMUS)//中间的竖线
write("");
}
}
if(j==MAXIMUS)//如果是最后一次循环,则只需要处理边侧字符,交点要少一排
{
break;
}
ln();//提行开始打印交点内容
write(" ");//用空位补齐位置
for(i=0;i<MAXIMUS;i++)//按横坐标循环正常的次数
{
write(getStyle(i,j));//写入交点字符
if(i!=MAXIMUS-1)//如果不在最右侧则补充一个横线承接左右
{
if(j==0||j==MAXIMUS-1)
{
write("");//上下边缘的横线更粗
}
else
{
write("");//中间的横线
}
}
}
ln();//写完一行后提行
}
Display();//将缓冲器内容输出到屏幕
}
int Put()//在当前光标位置走子如果非空则返回0表示失败
{
if(p[Cx][Cy]==0)
{
p[Cx][Cy]=Now;//改变该位置数据
return 1;//返回1表示成功
}
else
{
return 0;
}
}
int JugeWin()//胜负检查,即判断当前走子位置有没有造成五连珠的情况
{
int w=1,x=1,y=1,z=1,i;//累计横竖正斜反邪四个方向的连续相同棋子数目
for(i=1;i<5;i++)if(Cy+i<MAXIMUS&&p[Cx][Cy+i]==Now)w++;else break;//向下检查
for(i=1;i<5;i++)if(Cy-i>0&&p[Cx][Cy-i]==Now)w++;else break;//向上检查
if(w>=5)return Now;//若果达到5个则判断当前走子玩家为赢家
for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&p[Cx+i][Cy]==Now)x++;else break;//向右检查
for(i=1;i<5;i++)if(Cx-i>0&&p[Cx-i][Cy]==Now)x++;else break;//向左检查
if(x>=5)return Now;//若果达到5个则判断当前走子玩家为赢家
for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy+i<MAXIMUS&&p[Cx+i][Cy+i]==Now)y++;else break;//向右下检查
for(i=1;i<5;i++)if(Cx-i>0&&Cy-i>0&&p[Cx-i][Cy-i]==Now)y++;else break;//向左上检查
if(y>=5)return Now;//若果达到5个则判断当前走子玩家为赢家
for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy-i>0&&p[Cx+i][Cy-i]==Now)z++;else break;//向右上检查
for(i=1;i<5;i++)if(Cx-i>0&&Cy+i<MAXIMUS&&p[Cx-i][Cy+i]==Now)z++;else break;//向左下检查
if(z>=5)return Now;//若果达到5个则判断当前走子玩家为赢家
return 0;//若没有检查到五连珠则返回0表示还没有玩家达成胜利
}
int RunGame()//进行整个对局,返回赢家信息(虽然有用上)
{
int input;//输入变量
int victor;//赢家信息
Initialize();//初始化对局
while(1){//开始无限回合的死循环,直到出现胜利跳出
if(Now==1)
printf("当前落子方棋子颜色为黑色");
if(Now==2)
printf("当前落子方棋子颜色为白色");
Print();//打印棋盘
input=getch();//等待键盘按下一个字符
if(input==27)//如果是ESC则退出程序
{
exit(0);
}
else if(input==8)
{
huiqi(p,Now);
Now=3-Now;
}
else if(input==0x20&&Now==1||input==13&&Now==2)//如果是空格则开始走子
{
if(Put())//如果走子成功则判断胜负
{
victor=JugeWin();
Now=3-Now;//轮换当前走子玩家
count++;
if(victor==1)//如果黑方达到胜利,显示提示文字并等待一次按键,返回胜利信息
{
DoWin(victor);
if(getch()==0xE0)
{
getch();
}
return Now;
}
else if(victor==2)//如果白方达到胜利,显示提示文字并等待一次按键,返回胜利信息
{
DoWin(victor);
if(getch()==0xE0)
{
getch();
}
return Now;
}
else if(count==MAXIMUS*MAXIMUS)//如果回合数达到了棋盘总量,即棋盘充满,即为平局
{
showText="平局!";
Display();
if(getch()==0xE0)
{
getch();
}
return 0;
}
}
}
else if(Now==2&&input==0xE0)//如果按下的是方向键会填充两次输入第一次为0xE0表示按下的是控制键
{
input=getch();//获得第二次输入信息
switch(input)//判断方向键方向并移动光标位置
{
case 0x4B: Cx--;break;
case 0x48: Cy--;break;
case 0x4D: Cx++;break;
case 0x50: Cy++;break;
}
}
if(Now==1)
{
switch(input)//判断w,s,a,d键并移动光标位置
{
case 'a': Cx--;break;
case 'w': Cy--;break;
case 'd': Cx++;break;
case 's': Cy++;break;
}
}
if(Cx<0)Cx=MAXIMUS-1;//如果光标位置越界则移动到对侧
if(Cy<0)Cy=MAXIMUS-1;
if(Cx>MAXIMUS-1)Cx=0;
if(Cy>MAXIMUS-1)Cy=0;
}
}
void welcome() /*欢迎界面*/
{
Initialize(); /*初始化*/
system("cls"); /*清屏*/
system("color 2"); /*设置颜色*/
system("mode con cols=504 lines=512");/*样式*/
printf("\n\n\t╔══════════════════╗\n");
printf("\t║ ║\n");
printf("\t║ 欢迎来到五子棋游戏,祝你玩的愉快! ║\n");
printf("\t║ ║\n");
printf("\t║ ._______________________. ║\n");
printf("\t║ | _____________________ | ║\n");
printf("\t║ | I I | ║\n");
printf("\t║ | I I | ║\n");
printf("\t║ | I 五 子 棋 I | ║\n");
printf("\t║ | I I | ║\n");
printf("\t║ | I___________________I | ║\n");
printf("\t║ !_______________________! ║\n");
printf("\t║ ._[__________]_. ║\n");
printf("\t║ .___|_______________|___. ║\n");
printf("\t║ |::: ____ | ║\n");
printf("\t║ | ~~~~ [CD-ROM] | ║\n");
printf("\t║ !_____________________! ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ 请按任意键继续,进入帮助界面。 ║\n");
printf("\t║ ▅▅ ║\n");
printf("\t║ ▅▅ ║\n");
printf("\t║ ▅▅ ║\n");
printf("\t║ ▅▅ ║\n");
printf("\t╚══════════════════╝\n");
getch();
}
void help() /*帮助界面,基本操作同welcome();*/
{
Initialize();
system("cls"); /*清屏*/
system("color 2"); /*设置颜色*/
system("mode con cols=504 lines=512");/*样式*/
printf("\n\n\t╔──────────────────╗\n");
printf("\t║ 帮助与提示 ║\n");
printf("\t║玩家1\n");
printf("\t║移动WS\n");
printf("\t║ AD\n");
printf("\t║落棋:空格键 ║\n");
printf("\t║玩家2\n");
printf("\t║移动:上下左右方向键 ║\n");
printf("\t║落棋:回车键 ║\n");
printf("\t║悔棋Backspace键 ║\n");
printf("\t║ 请 ║\n");
printf("\t║ 按 ║\n");
printf("\t║ 任 ║\n");
printf("\t║ 意 ║\n");
printf("\t║ 键 ║\n");
printf("\t║ 继 ║\n");
printf("\t║ 续! ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t╚━━━━━━━━━━━━━━━━━━╝\n");
getch();
}
void DoWin(int v)
{
int n;
Initialize();
system("cls"); /*清屏*/
system("color F0"); /*设置颜色*/
if(v==1)
{
printf(" 黑方获得了胜利! \n");
p1_point();
}
if(v==2)
{
printf(" 白方获得了胜利! \n");
p2_point();
}
printf("\n\n\n\n\t╔──────────────────╗\n");
printf("\t║如 ║\n");
printf("\t║ 果 ║\n");
printf("\t║ 还 ║\n");
printf("\t║ 想 ║\n");
printf("\t║ 在 ║\n");
printf("\t║ 来 ║\n");
printf("\t║ 一 ║\n");
printf("\t║ 局 ║\n");
printf("\t║ 请 ║\n");
printf("\t║ 输 ║\n");
printf("\t║ 1 ║\n");
printf("\t║ 离 ║\n");
printf("\t║ 开 ║\n");
printf("\t║ 请 ║\n");
printf("\t║ 输 ║\n");
printf("\t║ 2 ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t╚━━━━━━━━━━━━━━━━━━╝\n");
scanf("%d",&n);
if(n==1)
printf("请按任意键继续");
if(n==2)
bye();
}
void bye() /*say bye~@!,实现功能同上*/
{
Initialize();
system("cls"); /*清屏*/
system("color 2"); /*设置颜色*/
printf("\t╔──────────────────╗\n");
printf("\t║ 结束界面 ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ 谢谢使用 ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ ║\n");
printf("\t║ 请 ║\n");
printf("\t║ 按 ║\n");
printf("\t║ 任 ║\n");
printf("\t║ 意 ║\n");
printf("\t║ 键 ║\n");
printf("\t║ 退 ║\n");
printf("\t║ 出 ║\n");
printf("\t║ 谢 ║\n");
printf("\t║ 谢 ║\n");
printf("\t║ 再见! ║\n");
printf("\t║ ║\n");
printf("\t╚━━━━━━━━━━━━━━━━━━╝\n");
exit(0);
}
void huiqi(int (* p)[MAXIMUS],int num)//悔棋函数
{
int i,j;
for(i=0;i<MAXIMUS;i++)
{
for(j=0;j<MAXIMUS;j++)
{
if(p[i][j]!=num&&i==Cx&&j==Cy)
p[i][j]=0;
}
}
}
void p1_point()//玩家一计分函数
{
FILE *fp;
fp=fopen("score1.txt","w+");
s1++;
fprintf(fp,"%d",s1);
fclose(fp);
int i;
fp=fopen("score1.txt","r");
fscanf(fp,"%d",&i);
fclose(fp);
printf("玩家一的得分=%d",i);
}
void p2_point()
{
FILE *fp;
fp=fopen("score2.txt","w+");
s2++;
fprintf(fp,"%d",s2);
fclose(fp);
int i;
fp=fopen("score2.txt","r");
fscanf(fp,"%d",&i);
fclose(fp);
printf("玩家二的得分=%d",i);
}
int main()//主函数
{welcome();
help();
system("title C语言五子棋游戏课程设计 ——湖工大通一李得龙,黄智");//设置标题
system("mode con cols=504 lines=512");//设置窗口大小
system("color F0");//设置颜色
while(1){//循环执行游戏
RunGame();
}
}