使用C语言实现五子棋游戏
目录
- 一、实现的目的和意义
- 二、实现内容描述
- 三、实现原理
- 四、实现模块五子棋实现分为三大模块
- 五、模块代码分析
- 六、实现结果
- 七、总结
一、实现的目的和意义
1、巩固和加深对c语言知识的理解
2、学会使用编译器的各种调试
3、提高解决实际问题的能力
二、实现内容描述
实现简单的人人对战五子棋,此设计用的是C语言去实现
三、实现原理
采用二位数组保存棋盘信息,棋盘上面的任何一个位置,里头可以放三个信息:
1、空
2、用户1的落子
3、用户2的落子
下棋就是在二维数组种找对应的空位置,进行落子,落完之后立即就要判断落子位置是否有五字连珠,从而判断谁数输谁赢。每走一次棋会有四种情况:
*用户1赢
*用户2赢
*平局(这里说的平局是棋盘被占满的情况)
*没有出结果 意思就是时此用户没赢 下个用继续去下棋
四、实现模块五子棋实现分为三大模块
文件名作用
five_chress.h五子棋的函数声明,头文件声明等
five_chress.c五子棋函数接口的实现
main.c五子棋函数测试功能
五、模块代码分析
1、five_chress.h
#pragma once#include #include #include#define ROW 10//数组号行号 按需求调整#define COL 10//数组列数 按需求调整#define PLAYER1 1//玩家编号,默认棋盘数据是0,玩家1落子,该位置被改成1#define PLAYER2 2//玩家编号,默认棋盘数据是0,玩家2落子,该位置被改成2#define NEXT0//游戏继续#define PLAYER1_WIN 1//玩家1赢#define PLAYER2_WIN 2//玩家2赢#define DRAW3//平局enum Dir{LEFT,RIGHT,UP,DOWN,LEFT_UP,LEFT_DOWN,RIGHT_UP,RIGHT_DOWN}; //用枚举去表示4个方向,上下,左右,左上右下,右上左下,统计用户当前棋子四个方向的棋数是否为大于等于5void Menu(); //实现菜单void Game(); //构建游戏入口Game()函数
2、five_chress.c
#include "five_chress.h"int x = 0; int y = 0; void Menu(){printf("############################\n"); printf("## 1. Play0. Exit ##\n"); printf("############################\n"); printf("Please Select# "); }//按照x,y作为起点,按照特定的方向,求连续相对的最大格式int ChessCount(int board[][COL], int row, int col, enum Dir d){int _x = x - 1; //从1int _y = y - 1; //从1int count = 0; while (1){switch (d){case LEFT://从当前位置向左移动统计 横坐标不变 纵坐标变了 所以是y--_y--; break; case RIGHT://从当前位置向右移动统计 横坐标不变 纵坐标变了 所以是_y++_y++; break; case UP://从当前位置向上移动统计 纵坐标不变 横坐标变了 所以是_x--_x--; break; case DOWN://从当前位置向下移动统计 纵坐标不变 横坐标变了 所以是_x++_x++; break; case LEFT_UP://从当前位置向左上移动统计 纵,横变都变了 所以是_x--,_y--_x--, _y--; break; case LEFT_DOWN://从当前位置左下移动统计 纵,横坐标都变了 所以是_x++,_y--_x++, _y--; break; case RIGHT_UP://从当前位置右上移动统计 纵,横坐标都变了 所以是_x--,_y++-_x--, _y++; break; case RIGHT_DOWN://从当前位置右下移动统计 纵,横坐标都变了 所以是_x++,_y++_x++, _y++; break; default://Do Nothingbreak; }if (_x < 0 || _x > row - 1 || _y < 0 || _y > col - 1){break; /表示越界了就停止}//合法if (board[x - 1][y - 1] == board[_x][_y]){count++; //统计从旧位置出发统计和他一样的个数}else{break; //如果碰到不一样的就终止循环}}return count; //返回统计个数}//4种情况//NEXT:表明要继续//PLAYER1_WIN: 用户1赢了//PLAYER2_WIN:用户2赢了//DRAW: 平局int IsOver(int board[][COL], int row, int col){int count1 = ChessCount(board, row, col, LEFT) + ChessCount(board, row, col, RIGHT) + 1; //?int count2 = ChessCount(board, row, col, UP) + ChessCount(board, row, col, DOWN) + 1; //?int count3 = ChessCount(board, row, col, LEFT_UP) + ChessCount(board, row, col, RIGHT_DOWN) + 1; //?int count4 = ChessCount(board, row, col, LEFT_DOWN) + ChessCount(board, row, col, RIGHT_UP) + 1; //?if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5){//有五子连珠//一定有人赢//x, yif (board[x - 1][y - 1] == PLAYER1){return PLAYER1_WIN; }else{return PLAYER2_WIN; }}int i = 0; for (; i < row; i++){int j = 0; for (; j < col; j++){if (board[i][j] == 0){return NEXT; //当前位置还没有被填写棋盘不满 当前用户没有赢返回next让下个用户继续下}}}return DRAW; //最后一种情况棋盘满了 为平局}void ShowBoard(int board[][COL], int row, int col){//printf("\e[1; 1H\e[2J"); 这是linux环境下用的清屏//讲数组内容,进行可视化system("cls"); //vs环境下用的清屏int i = 0; for (i=1; i <= col; i++){printf("%3d", i); }printf("\n"); for (i = 0; i < row; i++){int j = 0; printf("%2d",i + 1 ); for (; j < col; j++){if (board[i][j] == 0){printf(" . "); }else if (board[i][j] == PLAYER1){printf(" x "); }else{printf (" y "); }}printf("\n"); }}void PlayerMove(int board[][COL], int row, int col, int who){while (1){printf("Player[%d] Please Enter Your Pos# ", who); scanf("%d %d", &x, &y); if (x < 1 || x > row || y < 1 || y > col){printf("Pos Is Not Right!\n"); continue; }else if (board[x - 1][y - 1] != 0){printf("Pos Is Occupied!\n"); continue; }else{//合法性,去重board[x - 1][y - 1] = who; break; }}}void Game(){int board[ROW][COL]; memset(board, 0, sizeof(board)); int result = NEXT; do{ShowBoard(board, ROW, COL); //显示棋盘PlayerMove(board, ROW, COL, PLAYER1); //Player1先走result = IsOver(board, ROW, COL); //判断游戏是否结束if (NEXT != result){break; //如果返回值不等于NEXT就跳出循环 说明当前用户赢了或者平局 如果=NEXT 下个用户继续下}ShowBoard(board, ROW, COL); //同上PlayerMove(board, ROW, COL, PLAYER2); result = IsOver(board, ROW, COL); if (NEXT != result){break; }} while (1); //p1 win, p2 win, drawswitch (result){case PLAYER1_WIN:ShowBoard(board, ROW, COL); printf("恭喜用户1,你已经赢了!\n"); break; case PLAYER2_WIN:printf("恭喜用户2,你已经赢了!\n"); break; case DRAW:printf("平局\n"); break; default://do nothing!break; }}
分析:
我们要先构建游戏入口void game()函数在里面构建上层本调用框架 例如一开始初始化数组把每个位置都置为0,然后构建调用框架:
1、我们要保存二位数组并可视化 就要构建ShowBoard函数;
2、之后 我们要让用户下棋 就要构建PlayerMove()函数
3、第一个用户下完之后就要立马判断当前用户是否赢,因为落子和判定是强相关的 这时候要构建 IsOver()函数
如果此用户没赢 那二个用户继续下。
当我们这些函数逻辑都明确好的时候 就用分而治之思想 ,实现他们的功能。
* 1、ShowBoard()函数里面我用到了一个c语言里面的清屏函数printf(“cls”); 引上头文件window.h,这个的作用是在固定地方刷新视图,把上次的视图清理掉 ,显示当前位置视图。
后面就打印视图的内容。用户一和用户二可以用字符表示,也可以用圆圈图案表示这个图案可以在网上找复制一下就可
*2、 Playermove()函数让用户下棋,里面先考虑它的合法性 ,不能越界和重复,再然后用我们在five_chrsss.h文件定义宏来赋值 ,赋完之后再终止循环。
*3、 Isover()函数里面是让我们判断谁输谁赢 换句话游戏是否结束。游戏结束标志是分为四种情况。用户一赢,用户二赢,平局,继续。前两种情况则需要判断从当前位置出发 沿四个方向当前用户棋的个数是否为大于等于5,在判断一下是哪个用户的棋 就返回哪个用户。 而这判断需要在构建并调用ChressCount()函数去统计当前用户的个数是否大于等于5,有4个方向,例如上和下为一个方向,左和右为一个方向,左上和右下为一个方向,右上和左下为一个方向,分别各自相加之后在加上1就是当前的棋,如果满足这个4个方向大于等于5的一个条件,我们就能知道一定有人赢,否则在继续判断周围是否有
空位置,有则返回NEXT让下个用户继续下,没有则返回平局*ChressCoun()函数具体分析请看代码块
这些函数实现完之后再在Game()函数里面来个Switch循环,来结收宏 去打印谁赢 还是平局。
【使用C语言实现五子棋游戏】3、main.c
#include "five_chress.h"int main(){int quit = 0; int select = 0; while (!quit){Menu(); scanf("%d", &select); switch (select){case 1:Game(); break; case 0:quit = 1; printf("ByeBye!\n"); break; default:printf("Enter Error, Try Again!\n"); break; }}return 0; }
main函数作为测试入口,相比较里面的逻辑是很简单的,创建一个菜单函数和调用一个Game函数,再增添点其他的内容。
六、实现结果
文章图片
文章图片
七、总结
实现五子棋给我最大的体会是应用比理论学习难得多,首先要逻辑清楚,也会涉及到各种实际问题,但是加深了我对知识的理解和运用,也知道了只有多练习 多写代码才能更好的提升编程技术。同时我也学到了实现一个复杂的项目时,先去构建一个框架,一个清晰的逻辑。再去逐个击破每个问题,要学会用分而治之的思想去解决问题。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- 使用C语言实现三子棋小游戏
- 使用C语言实现扫雷游戏
- Zabbix|使用 Docker 安装 Zabbix,并配置自定义监控项
- 使用Typora+EasyBlogImageForTypora写博客,无图床快速上传图片
- 纯numpy数值微分法实现手写数字识别
- 图文详解梯度下降算法的原理及Python实现
- java实现计算器模板及源码
- Python使用captcha库制作带参数输入验证码案例
- C++虚继承的实现原理由内存布局开始讲起
- extjs图表绘制之条形图实现方法分析