当前位置 : 主页 > 操作系统 > centos >

linux实现 五子棋(人人对战)

来源:互联网 收集:自由互联 发布时间:2022-10-26
分步解析 对于 game 函数的解析 进入game函数中,通过创建一个二维数组来打印棋盘,进入 do while 循环中,策略是 先打印出棋盘, 然后先让用户1落子,进行判定,看是否需要继续,若需

分步解析

对于 game 函数的解析

image.png

进入game函数中,通过创建一个二维数组来打印棋盘,进入 do while 循环中, 策略是 先打印出棋盘, 然后先让用户1落子,进行判定,看是否需要继续,若需要则让 用户2落子,再进行判定,直到用户1/用户2赢,或者平局 跳出循环 image.png 通过isover函数的返回值来确定进入switch语句中的那个case 中 最后打印出结果

playermove ——用户落子

image.png

这里使用 全局变量 x y 会在下方说明,进入while(1)循环中,若碰到越界问题 和被占用问题 直接continue ,返回重新输入。 除此之外,直接将定义的变量who 赋值给 board[x-1][y-1]中,因为 无论是 用户1/用户2都是在game.h文件中用宏定义了的。 下标表示为 x-1,y-1,是因为我们设计的棋盘是从1开始的。

isover ——判定四种情况

image.png

在isover函数中,还有一个函数chessout是用来计算特定方向的最大格式,这个我们等会再说,通过chessout函数记录最大连珠数后,通过判断加上本身的1是否大于5,若大于5,则有人赢,(用户1赢/用户2赢), 如果没人赢,判断下棋盘中是否有默认初始化的0,若有0则为继续,若没有0则平局。

chessout —— 求特定方向的连珠数

image.png image.png

通过该图判断每次改变方向时,x y的变化 如果可以一直向某个方向变化且保持连珠,则count++ 反之,直接break跳出循环,输出count 在循环中若该下标越界,也直接break 这里我们需要注意下,将原来的 坐标 x y 的值保存起来,用改变后的下标_x _y,与其值进行比较,若相等则说明可以连珠,若不相等 ,就直接break。 image.png 这里的d 即为枚举变量,无论对应输入那个方向都可以接收

使用全局变量 x y 的原因

image.png image.png

1.当使用 playermove函数表示使用户1/用户2落子时,此时的x y就分别代表在当前用户1/用户2在棋盘所显示的值,因为 PLAYER1(1) 与 PLAYER2(2) 都是被宏定义了值的。

  • 当落子后,进入isover函数进行判定 image.png 通过 x y 所对应棋盘下标的值,来确定是用户1,还是用户2
  • showboard—— 数组内容可视化

    image.png

    这里需要注意的是,刚开始有一个空格的存在是为了 将棋盘的 x y 对齐

    image.png

    初始化时,我们将棋盘显示的0记作 . image.png 用户1输入 坐标 1 1 ,显示处 x

    image.png

    用户2输入 坐标 2 2,出现 o

    完整代码

    1. game.c

    #include"game.h" int x = 0; int y = 0; void menu() { printf("******************\n"); printf("*****1.play 0.exit\n"); printf("******************\n"); } void showboard(int board[][COL],int row,int col) { int i=0; int j=0; printf(" "); for(i=1;i<=col;i++) { printf("%3d",i); } printf("\n"); for(i=0;i<row;i++) { printf("%2d",i+1); for(j=0;j<col;j++) { if(board[i][j]==0) { printf(" . "); } else if(board[i][j]==PLAYER1) { printf(" x "); } else { printf(" o "); } } printf("\n"); } } //按照 x y作为起点,按照特定方向,求连续相对的最大格式 int chesscount(int board[ROW][COL],int row,int col,enum dir d)//d为枚举变量 { int _x=x-1;//_x作为当前x的下标 int _y=y-1;//_y作为当前y的下标 int count=0; while(1) { switch(d) { case LEFT://左 _y--; break; case RIGHT://右 _y++; break; case UP://上 _x--; break; case DOWN://下 _x++; break; case LEFT_UP://左上 _x--; _y--; break; case LEFT_DOWN://左下 _x++; _y--; break; case RIGHT_UP://右上 _x--; _y++; break; case RIGHT_DOWN://右下 _x++; _y++; break; } if(_x<0||_x>row-1||_y<0||_y>col-1)// _x _y 都是下标,如果越界就跳出循环 { break; } if(board[x-1][y-1]==board[_x][_y])//如果 改变后的下标 与用户的值相等,count++ { count++; } else { break; } } return count; } int isover(int board[][COL],int row,int col) { int count1=chesscount(board,row,col,LEFT)+chesscount(board,row,col,RIGHT)+1;//坐标所在的左右连接相同棋子数+本身棋子数1 int count2=chesscount(board,row,col,UP)+chesscount(board,row,col,DOWN)+1; //坐标所在的上下连接相同棋子数+本身棋子数1 int count3=chesscount(board,row,col,LEFT_UP)+chesscount(board,row,col,RIGHT_DOWN)+1;//坐标所在的左上 与右下连接相同棋子数+本身棋子数1 int count4=chesscount(board,row,col,LEFT_DOWN)+chesscount(board,row,col,RIGHT_UP)+1;//坐标所在的左下 与右上连接相同棋子数+本身棋子数1 if(count1>=5||count2>=5||count3>=5||count4>=5)//说明有五子连珠的情况,有人赢 { if(board[x-1][y-1]==PLAYER1)//因为设置的全局变量的x y,落子就判定,此时x y所对应棋盘的数字是 用户1(1)还是用户2(2) { return PLAYER1_WIN;//用户1赢 } else { return PLAYER2_WIN;//用户2赢 } } //没人赢,有两种情况1.继续 2.平局 int i=0; int j=0; for(i=0;i<row;i++)//继续 { for(j=0;j<col;j++) { if(board[i][j]==0)//有默认值0说明该坐标没有被下棋 { return NEXT; } } } return DRAW;//平局 } void playermove(int board[][COL],int row,int col ,int who)//用户1/用户2落子 { while(1) { printf("player[%d] please Enter your pos# ",who); scanf("%d%d",&x,&y); if(x<1||x>row||y<1||y>col)//如果x y越界,就返回重新输入 { printf("pos is not right!\n"); continue; } else if(board[x-1][y-1]!=0) //在棋盘中被占用,就重新输入 { printf("棋盘被占用,重新输入\n"); continue; } else { board[x-1][y-1]=who; //此时的who 已经被宏定义 (用户1代表1, 用户2代表2) break; } } } void game() { int board[ROW][COL];//定义一个二维数组 memset(board,0,sizeof(board));//使用memset将二维数组初始化为0 int result=0; do { showboard(board,ROW,COL);//显示棋盘 playermove(board,ROW,COL,PLAYER1);//用户1进行下棋,落子 result= isover(board,ROW,COL);//判定 共有四种情况 用户1赢 用户2赢 平局 继续 if(NEXT!=result)//NEXT代表要继续,反之要出结果: 用户1赢 用户2赢 平局 { break; } showboard(board,ROW,COL);//将用户1下好的步 显示到棋盘中 playermove(board,ROW,COL,PLAYER2);//用户2进行下棋,落子 if(result!=NEXT) { break; } showboard(board,ROW,COL);//将用户2下好的步,显示到棋盘中 }while(1); switch(result) { case PLAYER1_WIN: //用户1赢 printf("用户1赢\n"); break; case PLAYER2_WIN: //用户2赢 printf("用户2赢\n"); break; case DRAW: //平局 printf("平局\n"); break; } }

    2. game.h

    #pragma once //为了防止头文件的多次重复利用 #include<stdio.h> #include<string.h> #define ROW 20 #define COL 20 #define NEXT 0 #define PLAYER1 1//默认用户1 的编号1 #define PLAYER2 2//默认用户2 的编号2 #define PLAYER1_WIN 1//表示用户1赢 #define PLAYER2_WIN 2//表示用户2赢 #define DRAW 3//表示平局 void showboard(int board[][COL],int row,int col); void playermove(int board[][COL],int row, int col,int who); int isover(int board[][COL],int row,int col); enum dir { LEFT,//左 RIGHT,//右 UP,//上 DOWN,//下 LEFT_UP,//左上 LEFT_DOWN,//左下 RIGHT_UP,//右上 RIGHT_DOWN//右下 };

    3.main.c

    #include "game.h" int main() { int result=0; do { menu(); scanf("%d",&result); switch(result) { case 1: game(); break; case 0: printf("程序结束\n"); break; default: printf("输入错误,重新输入\n"); break; } } while(result); return 0; }

    4. makefile

    game :main.c game.c gcc $^ -o $@ .PHONY:clean clean: rm -f game
    上一篇:【10.15-10.21】博客精彩回顾
    下一篇:没有了
    网友评论