经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
使用C语言实现五子棋游戏
来源:jb51  时间:2022/8/3 15:17:06  对本文有异议

本文实例为大家分享了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

  1. #pragma once
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include<Windows.h>
  5. #define ROW 10//数组号行号 按需求调整
  6. #define COL 10//数组列数 按需求调整
  7. #define PLAYER1 1//玩家编号,默认棋盘数据是0,玩家1落子,该位置被改成1
  8. #define PLAYER2 2//玩家编号,默认棋盘数据是0,玩家2落子,该位置被改成2
  9. #define NEXT ? ? ? ?0//游戏继续
  10. #define PLAYER1_WIN 1//玩家1赢
  11. #define PLAYER2_WIN 2//玩家2赢
  12. #define DRAW ? ? ? ?3//平局
  13.  
  14. ? ?enum Dir{
  15. ?? ?LEFT,
  16. ?? ?RIGHT,
  17. ?? ?UP,
  18. ?? ?DOWN,
  19. ?? ?LEFT_UP,
  20. ?? ?LEFT_DOWN,
  21. ?? ?RIGHT_UP,
  22. ?? ?RIGHT_DOWN
  23. ? ? };//用枚举去表示4个方向,上下,左右,左上右下,右上左下,统计用户当前棋子四个方向的棋数是否为大于等于5
  24. ? ? void Menu();//实现菜单
  25. ? ? void Game();//构建游戏入口Game()函数 ? ? ?

2、five_chress.c

  1. #include "five_chress.h"
  2.  
  3. int x = 0;
  4. int y = 0;
  5.  
  6. void Menu()
  7. {
  8. ?? ?printf("############################\n");
  9. ?? ?printf("## 1. Play ? ? ? ?0. Exit ##\n");
  10. ?? ?printf("############################\n");
  11. ?? ?printf("Please Select# ");
  12. }
  13.  
  14. //按照x,y作为起点,按照特定的方向,求连续相对的最大格式
  15. int ChessCount(int board[][COL], int row, int col, enum Dir d)
  16. {
  17. ?? ?int _x = x - 1; //从1
  18. ?? ?int _y = y - 1; //从1
  19.  
  20. ?? ?int count = 0;
  21. ?? ?while (1){
  22. ?? ??? ?switch (d){
  23. ?? ??? ?case LEFT://从当前位置向左移动统计 横坐标不变 纵坐标变了 所以是y--
  24. ?? ??? ??? ?_y--;
  25. ?? ??? ??? ?break;
  26. ?? ??? ?case RIGHT://从当前位置向右移动统计 横坐标不变 纵坐标变了 所以是_y++
  27. ?? ??? ??? ?_y++;
  28. ?? ??? ??? ?break;
  29. ?? ??? ?case UP://从当前位置向上移动统计 纵坐标不变 横坐标变了 所以是_x--
  30. ?? ??? ??? ?_x--;
  31. ?? ??? ??? ?break;
  32. ?? ??? ?case DOWN://从当前位置向下移动统计 纵坐标不变 横坐标变了 所以是_x++
  33. ?? ??? ??? ?_x++;
  34. ?? ??? ??? ?break;
  35. ?? ??? ?case LEFT_UP://从当前位置向左上移动统计 纵,横变都变了 所以是_x--,_y--
  36. ?? ??? ??? ?_x--, _y--;
  37. ?? ??? ??? ?break;
  38. ?? ??? ?case LEFT_DOWN://从当前位置左下移动统计 纵,横坐标都变了 所以是_x++,_y--
  39. ?? ??? ??? ?_x++, _y--;
  40. ?? ??? ??? ?break;
  41. ?? ??? ?case RIGHT_UP://从当前位置右上移动统计 纵,横坐标都变了 所以是_x--,_y++-
  42. ?? ??? ??? ?_x--, _y++;
  43. ?? ??? ??? ?break;
  44. ?? ??? ?case RIGHT_DOWN://从当前位置右下移动统计 纵,横坐标都变了 所以是_x++,_y++
  45. ?? ??? ??? ?_x++, _y++;
  46. ?? ??? ??? ?break;
  47. ?? ??? ?default:
  48. ?? ??? ??? ?//Do Nothing
  49. ?? ??? ??? ?break;
  50. ?? ??? ?}
  51. ?? ??? ?if (_x < 0 || _x > row - 1 || _y < 0 || _y > col - 1){
  52. ?? ??? ??? ?break;/表示越界了就停止
  53. ?? ??? ?}
  54. ?? ??? ?//合法
  55. ?? ??? ?if (board[x - 1][y - 1] == board[_x][_y]){
  56. ?? ??? ??? ?count++;//统计从旧位置出发统计和他一样的个数
  57. ?? ??? ?}
  58. ?? ??? ?else{
  59. ?? ??? ??? ?break;//如果碰到不一样的就终止循环
  60. ?? ??? ?}
  61. ?? ?}
  62. ?? ?return count;//返回统计个数
  63. }
  64.  
  65. //4种情况
  66. //NEXT:表明要继续
  67. //PLAYER1_WIN: 用户1赢了
  68. //PLAYER2_WIN:用户2赢了
  69. //DRAW: 平局
  70. int IsOver(int board[][COL], int row, int col)
  71. {
  72. ?? ?
  73. ?? ?int count1 = ChessCount(board, row, col, LEFT) + ChessCount(board, row, col, RIGHT) + 1; //?
  74. ?? ?int count2 = ChessCount(board, row, col, UP) + ChessCount(board, row, col, DOWN) + 1; //?
  75. ?? ?int count3 = ChessCount(board, row, col, LEFT_UP) + ChessCount(board, row, col, RIGHT_DOWN) + 1; //?
  76. ?? ?int count4 = ChessCount(board, row, col, LEFT_DOWN) + ChessCount(board, row, col, RIGHT_UP) + 1; //?
  77.  
  78. ?? ?if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5){
  79. ?? ??? ?//有五子连珠
  80. ?? ??? ?//一定有人赢
  81. ?? ??? ?//x, y
  82. ?? ??? ?if (board[x - 1][y - 1] == PLAYER1){
  83. ?? ??? ??? ?return PLAYER1_WIN;
  84. ?? ??? ?}
  85. ?? ??? ?else{
  86. ?? ??? ??? ?return PLAYER2_WIN;
  87. ?? ??? ?}
  88. ?? ?}
  89.  
  90. ?? ?int i = 0;
  91. ?? ?for (; i < row; i++){
  92. ?? ??? ?int j = 0;
  93. ?? ??? ?for (; j < col; j++){
  94. ?? ??? ??? ?if (board[i][j] == 0){
  95. ?? ??? ??? ??? ?return NEXT;//当前位置还没有被填写棋盘不满 当前用户没有赢返回next ?让下个用户继续下
  96. ?? ??? ??? ?}
  97. ?? ??? ?}
  98. ?? ?}
  99.  
  100. ?? ?return DRAW;//最后一种情况棋盘满了 为平局
  101. }
  102.  
  103. void ShowBoard(int board[][COL], int row, int col)
  104. {
  105. ?? ?//printf("\e[1;1H\e[2J");这是linux环境下用的清屏
  106. ?? ?//讲数组内容,进行可视化
  107. ?? ?system("cls");//vs环境下用的清屏
  108. ?? ?
  109. ?? ?int i = 0;
  110. ?? ?for (i=1; i <= col; i++){
  111. ?? ??? ?printf("%3d", i);
  112. ?? ?}
  113. ?? ?printf("\n");
  114.  
  115. ?? ?for (i = 0; i < row; i++){
  116. ?? ??? ?int j = 0;
  117. ?? ??? ?printf("%2d",i + 1 );
  118. ?? ??? ?for (; j < col; j++){
  119. ?? ??? ??? ?if (board[i][j] == 0){
  120. ?? ??? ??? ??? ?printf(" . ");
  121. ?? ??? ??? ?}
  122. ?? ??? ??? ?else if (board[i][j] == PLAYER1){
  123. ?? ??? ??? ??? ?printf(" x ");
  124. ?? ??? ??? ?}
  125. ?? ??? ??? ?else{
  126. ?? ??? ??? ??? ?printf (" y ");
  127. ?? ??? ??? ?}
  128. ?? ??? ?}
  129. ?? ??? ?printf("\n");
  130. ?? ?}
  131. }
  132.  
  133. void PlayerMove(int board[][COL], int row, int col, int who)
  134. {
  135. ?? ?while (1){
  136. ?? ??? ?printf("Player[%d] Please Enter Your Pos# ", who);
  137. ?? ??? ?scanf("%d %d", &x, &y);
  138. ?? ??? ?if (x < 1 || x > row || y < 1 || y > col){
  139. ?? ??? ??? ?printf("Pos Is Not Right!\n");
  140. ?? ??? ??? ?continue;
  141. ?? ??? ?}
  142. ?? ??? ?else if (board[x - 1][y - 1] != 0){
  143. ?? ??? ??? ?printf("Pos Is Occupied!\n");
  144. ?? ??? ??? ?continue;
  145. ?? ??? ?}
  146. ?? ??? ?else{
  147. ?? ??? ??? ?//合法性,去重
  148. ?? ??? ??? ?board[x - 1][y - 1] = who;
  149. ?? ??? ??? ?break;
  150. ?? ??? ?}
  151. ?? ?}
  152. }
  153.  
  154. void Game()
  155. {
  156. ?? ?int board[ROW][COL];
  157. ?? ?memset(board, 0, sizeof(board));
  158. ?? ?int result = NEXT;
  159. ?? ?do{
  160. ?? ??? ?ShowBoard(board, ROW, COL);//显示棋盘
  161. ?? ??? ?PlayerMove(board, ROW, COL, PLAYER1);//Player1先走
  162. ?? ??? ?result = IsOver(board, ROW, COL);//判断游戏是否结束
  163. ?? ??? ?if (NEXT != result){
  164. ?? ??? ??? ?break;//如果返回值不等于NEXT就跳出循环 说明当前用户赢了或者平局 如果=NEXT 下个用户继续下
  165. ?? ??? ?}
  166. ?? ??? ?ShowBoard(board, ROW, COL);//同上
  167. ?? ??? ?PlayerMove(board, ROW, COL, PLAYER2);
  168. ?? ??? ?result = IsOver(board, ROW, COL);
  169. ?? ??? ?if (NEXT != result){
  170. ?? ??? ??? ?break;
  171. ?? ??? ?}
  172. ?? ?} while (1);
  173. ?? ?//p1 win, p2 win, draw
  174. ?? ?switch (result){
  175. ?? ?case PLAYER1_WIN:
  176. ?? ??? ?ShowBoard(board, ROW, COL);
  177. ?? ??? ?printf("恭喜用户1,你已经赢了!\n");
  178. ?? ??? ?break;
  179. ?? ?case PLAYER2_WIN:
  180. ?? ??? ?printf("恭喜用户2,你已经赢了!\n");
  181. ?? ??? ?break;
  182. ?? ?case DRAW:
  183. ?? ??? ?printf("平局\n");
  184. ?? ??? ?break;
  185. ?? ?default:
  186. ?? ??? ?//do nothing!
  187. ?? ??? ?break;
  188. ?? ?}
  189. }

分析:

我们要先构建游戏入口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循环,来结收宏 去打印谁赢 还是平局。

3、main.c

  1. #include "five_chress.h"
  2.  
  3. int main()
  4. {
  5. ?? ?int quit = 0;
  6. ?? ?int select = 0;
  7. ?? ?while (!quit){
  8. ?? ??? ?Menu();
  9. ?? ??? ?scanf("%d", &select);
  10. ?? ??? ?switch (select){
  11. ?? ??? ?case 1:
  12. ?? ??? ??? ?Game();
  13. ?? ??? ??? ?break;
  14. ?? ??? ?case 0:
  15. ?? ??? ??? ?quit = 1;
  16. ?? ??? ??? ?printf("ByeBye!\n");
  17. ?? ??? ??? ?break;
  18. ?? ??? ?default:
  19. ?? ??? ??? ?printf("Enter Error, Try Again!\n");
  20. ?? ??? ??? ?break;
  21. ?? ??? ?}
  22. ?? ?}
  23.  
  24. ?? ?return 0;
  25. }

main函数作为测试入口,相比较里面的逻辑是很简单的,创建一个菜单函数和调用一个Game函数,再增添点其他的内容。

六、实现结果

七、总结

实现五子棋给我最大的体会是应用比理论学习难得多,首先要逻辑清楚,也会涉及到各种实际问题,但是加深了我对知识的理解和运用,也知道了只有多练习 多写代码才能更好的提升编程技术。同时我也学到了实现一个复杂的项目时,先去构建一个框架,一个清晰的逻辑。再去逐个击破每个问题,要学会用分而治之的思想去解决问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号