c语言coord坐标结构提,五子棋项目 --C语言

前段时间用C语言和小组成员一起写了一个五子棋的小项目

我写的代码基本被毙了 惨 但也学到很多

总结一下

五子棋项目简要介绍:

1.用光标控制棋子运动及下棋

2.控制台输出 没用gui

3.有悔棋功能

4.只有人人对战 无ai 人机对战(之后可能会升级 并加入联机操作)

5.其他和一般五子棋一样

6.采用简单的栈进行棋子数据的存储,实现下棋,悔棋功能

代码分析:

大体分几个模块:

一个欢迎界面

一个游戏界面

游戏模块:下棋悔棋

判断胜负模块

main函数

每个模块含义一些细小的控制细节

1.棋子 定义为结构体

typedef struct {

int x;

int y;

int type;//棋子颜色 黑或白

}ChessMan;

棋盘:二维数组 直接用中文“十”填充

//初始化棋盘

void InitChessBoard() {

for(int i = 0; i < BOARD_SIZE ; i ++) {

for(int j = 0; j < BOARD_SIZE; j ++) {

ChessBoard[i][j] = "十";

}

}

}

下棋即用黑子或白子直接覆盖即可

例:

ChessBoard[chessArray[i].y][chessArray[i].x] = "●";

2.用链栈存储棋子数据 实现下棋 悔棋

下棋即入栈 悔棋即出栈

一开始我没找到棋子类型与光标相互匹配的方法,因为用光标控制,之前没尝试过,搜到的光标控制方法有设置横纵坐标,与棋子横纵坐标有些重复,后来队友用了更好的光标控制方法解决此问题。

光标控制方法:

此控制方法也有借鉴网上找到的控制方法

用到API函数:

SetConsoleCursorPosition 以此设置光标位置

具体使用方法详见:https://blog.csdn.net/xiexievv/article/details/7475848

https://blog.csdn.net/qq_38241045/article/details/69941464

/**设置游戏光标*/

void SetPosition(int x,int y)

{

HANDLE winHandle;//句柄 ?存疑

COORD pos={x,y};//坐标x,y

winHandle=GetStdHandle(STD_OUTPUT_HANDLE);调用函数

//设置光标的坐标

SetConsoleCursorPosition(winHandle,pos);//调用函数

}

下棋模块代码:

具体见注释

int counts = 0;//记录落子数 步数

int i = 0;

void Play() {

InitChessBoard();//初始化棋盘

ShowGameInterface();

HANDLE hwnd = GetStdHandle(STD_OUTPUT_HANDLE);

COORD coord;

coord.X = 41;

coord.Y = 9;//设置初始光标位置

SetConsoleCursorPosition(hwnd,coord);

while (1) {//进入下棋

switch(getch() ) {

case 27://esc 退出 回到欢迎界面

return 0;

break;

case 32: {

loopout(hwnd, coord);

int X=coord.X-27,Y=coord.Y-2;

counts++;

int n=225;//总步数

ChessMan chessArray[n];//棋子结构数组

chessArray[i].x = X/2; //棋子坐标 横坐标变化两个单位 棋盘上移动一格

chessArray[i].y =Y;

chessArray[i].type = counts%2;//先手为甲方 //mod2结果只能是0或1

LinkedStack * linkedStack =(LinkedStack *)malloc(sizeof(ChessMan));//链栈

PushLinkedStack(linkedStack,chessArray[i]);

//将棋子压入栈

//根据棋子类型修改棋盘

//下子

if(strcmp(ChessBoard[Y][X/2],"十")==0){ //非重子 可下棋

if(chessArray[i].type == BLACK) {

ChessBoard[chessArray[i].y][chessArray[i].x] = "●";

if(judge_win("●",chessArray[i].y,chessArray[i].x)) {//判断是否胜利,目前只会响铃一下

printf("\a");

winner = 0;//不同值 不同状态 0 黑棋 1 白棋 2 和棋 3 重棋 -1 初始值

}

if(counts == 225) { //判断是否和棋

winner = 2;

}

} else {

ChessBoard[chessArray[i].y][chessArray[i].x] = "○";

if(judge_win("○",chessArray[i].y,chessArray[i].x)) {

printf("\a");

winner = 1;

}

}

} else { **//重子**

f_print(ChessBoard[Y][X/2],Y,X/2,1,1);

winner = 3; //重子状态

ShowGameInterface(counts-1,winner);

counts--;

winner = -1;

break;

}

i++;//循环

system("cls");//清屏 及时清屏 清屏后要再显示游戏界面

ShowGameInterface(counts,winner);/**显示游戏界面 注意此函数 不同的参数表示不同状态 详见此函数实现*/

int button= getch();//悔棋,退出操作

if(button==98) { //98:b键

//悔棋即出栈,再次用中文“十”代替即可

while(linkedStack->top ) {

ChessMan currChess;

PopLinkedStack(linkedStack,&currChess);

ChessBoard[currChess.y][currChess.x] = "十";

system("cls");

counts--;//悔棋要减步数 且悔棋者要再下一子 只可悔一次

//ptr_num = &counts;

ShowGameInterface(counts,winner);

break;

}

}

}

case 0xE0://光标操作上下左右移动 且要判断是否出界并将其移进棋盘中

switch (getch()) {

case 72://上

if(coord.Y<3)//判断边界

coord.Y=16;

else {

coord.Y--;

}

loopout(hwnd, coord);

break;

case 80://下

if(coord.Y>15)//判断边界

coord.Y=1;

else {

coord.Y++;

loopout(hwnd, coord);

}

break;

case 75://左

if(coord.X<=28)//判断边界

coord.X=53;

else {

coord.X-=2;

loopout(hwnd, coord);

break;

}

case 77://右

if(coord.X>=54)//判断边界

coord.X=25;

else {

coord.X+=2;

loopout(hwnd, coord);

break;

}

}

}

}

getchar();

return ;

}

判断胜负与写入文件模块:

创建data.txt文件记录棋子的运行过程 查看当前状态 输出棋盘及相关判断棋子信息 用于debug

int judge_win(char *now_chess,int x,int y) { //now_chess 当前棋子,x、y 坐标

int x_temp,y_temp,flag;//x,y,替代值,flag为相同棋子判断值

int count = 0;//同向棋子个数

int k;

f_print(now_chess,x,y,1,counts);//data文件输出棋子,及当前棋盘

for(k=0; k<4; k++) {//四方向

x_temp = x;

y_temp = y;//重置

flag = 1;

count = 0;

while(flag) {//正向遍历 右,下,右下,右上 在下子哪里传入的是y,x这里直接用x,y即可

x_temp +=dx[k];//

y_temp+=dy[k];//

f_print(ChessBoard[x_temp][y_temp],x_temp,y_temp,0,0);//**输出当前判断棋子信息**

if(ChessBoard[x_temp][y_temp] == now_chess) {//相同棋子判断

if(x_temp>=0&&x_temp<15&&y_temp>=0&&y_temp<15) {//范围判断

count++;

} else {

flag = 0;

}

} else {

flag = 0;

}

}

flag = 1;

x_temp = x;

y_temp = y;//重置

while(flag) {//反向遍历

x_temp-=dx[k];

y_temp-=dy[k];

f_print(ChessBoard[x_temp][y_temp],x_temp,y_temp,0,0);//

if(ChessBoard[x_temp][y_temp] == now_chess) {

if(x_temp>=0&&x_temp<15&&y_temp>=0&&y_temp<15) {

count++;

} else {

flag = 0;

}

} else {

flag = 0;

}

}

if(count>=4)//如果同行有4个了,加上本体就是5个

return 1;

}

return 0;

}

void f_print(char *temp,int x,int y,int flag,int counts) {//temp: 当前棋子,x,y坐标,flag是否输出棋盘,counts,落子数

FILE *fp;

fp = fopen("data.txt","a");

if(flag) {

fprintf(fp,"第%d次落子,%s棋。 位置x: %d y: %d\n",counts,temp,x,y);

for(int i=0; i<15; i++) {

for(int j=0; j<15; j++) {

fprintf(fp,"%s",ChessBoard[i][j]);

}

fprintf(fp,"\n");

}

fprintf(fp,"\n");

} else {

fprintf(fp,"\t %s %d %d\n",temp,x,y);

}

return ;

}

main函数:

int main() {

SetTitle("DAWN小组五子棋项目");

system("color 37");//设置界面及字体颜色

system("mode con cols=120 lines=46");

while(1) {

ShowFirstPage();

ShowEnterOrQuit();

while(now_title) {

now_title = Play();

}

now_title = 1;//重置各个变量

i = 1;

counts = 0;

winner = -1;

system("cls");

}

return 0;

}

一些全局变量:

const int dx[4] = {1,0,1,1};//遍历方向

const int dy[4] = {0,1,1,-1};

int judge_win(char *now_chess,int x,int y); //判断胜负,就两个函数,先放到主函数里建了

void f_print(char *temp,int x,int y,int flag,int counts);//输出棋盘数据

int counts = 0;//记录落子数

int Play();//落子、悔棋功能

void InitLinkedStack(LinkedStack * linkedStack);

//光标移动函数

void PutDown();

void ShowGameInterface();

int i = 1;

int now_title = 1;

int winner = -1;

int temp_x[225],temp_y[225];

int a = 0;

总结:

胜负判断:

传入当前棋子类型(黑 白 无),当前坐标

设置坐标替代变量 同向棋子数

调用文件函数 输出此时棋盘情况

在四个方向上遍历 判断是否有四个以上同向同类型棋子 设置信号变量(主要用于判断坐标是否超出范围及用于判断文件是否输出情况,初始值为1)

整个项目不大,结构也不复杂,但是有些变量的设置还挺巧妙

比如显示轮到甲方,乙方下棋,胜利显示,ESC退出到main函数的几个变量设置

重子操作 用到简单的strcmp()函数即解决

分非重子

重子 两种情况

非重子才可进行下棋等操作

重子只需winner增加一个状态即可。

还有胜负判断中 几个方向上的移动 用数组来表示

胜负判断和文件虽然不难 但是值得学习

效果图:

e4d966f2e4210c3139a5eeeb87ff1a3f.png

0f93e099ed2e5125d737f51254d931ef.png

e06b987c5aabe60b455a08595bc685fc.png

再次感谢所有小组成员

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值