经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
【计项01组02号】C 语言快速实现五子棋【1.0】
来源:cnblogs  作者:yyyyfly  时间:2022/1/17 11:10:30  对本文有异议

1.1 实验内容

五子棋大家一定都玩过,想不想试着用 C 语言来实现一个简易版的五子棋呢?下面就让我们现在开始,用最简单易懂的代码来编写一个控制台下的五子棋,并逐步完善它,每个人都能轻松学会哦!

1.2 知识点

  • 游戏的逻辑
  • 判断结果的算法
  • 界面的设计

2.1 设计棋盘

注:实验楼环境无法输入中文,可以用O和X来代替棋子

我们首先需要一个棋盘(15 * 15),记录棋盘中每一个位置的“情况”。 那么我们可以定义一个 chessboard[16][16] 的数组,为什么不是 [15][15] 呢?因为这样我们就可以让数组的坐标正好对应棋盘的行和列,方便后面代码的编写。

查看代码
  1. #include <stdio.h>
  2. #define N 15
  3. //定义一个数组并为每一个元素赋初值0
  4. int chessboard[N + 1][N + 1] = { 0 };

2.2、main函数的编写

开始编写主函数之前,我们先简单的考虑一下,一个游戏通常的流程是怎么样的 (⊙o⊙?)首 先肯定是进入游戏的一个主界面,然后点击开始按钮进入游戏,接着显示游戏画面,判断输赢,游戏结束。那么一个五子棋游戏的流程呢?

查看代码
  1. //用来记录轮到玩家1还是玩家2,奇数表示轮到玩家1,偶数轮到玩家2
  2. int whoseTurn = 0;
  3. int main(void)
  4. {
  5. //自定义函数,用来初始化游戏,也就是显示欢迎界面并且进入游戏显示棋盘
  6. initGame();
  7. //这个循环就是用来让两个玩家轮流落子的
  8. while (1)
  9. {
  10. //每次循环自增1,这样就可以做到2人轮流
  11. whoseTurn++;
  12. //自定义函数,用来执行落子操作
  13. playChess();
  14. }
  15. return 0;
  16. }

2.3、initGame函数

在这个函数中,我们要实现的功能是

  • 显示一个简单的欢迎界面
  • 要求输入Y之后显示出棋盘

下面,我们就开始吧!

查看代码
  1. void initGame(void)
  2. {
  3. char c;
  4. printf("欢迎^_^请输入y进入游戏:");
  5. c = getchar();
  6. if ('y' != c && 'Y' != c)
  7. exit(0);
  8. //清屏,windows下为system("cls")
  9. system("clear");
  10. //这里我们又调用了一个自定义函数,函数的功能是打印出棋盘
  11. printChessboard();
  12. }

我们在 initGame 函数中使用了 exit 以及 system 这两个函数,所以要在程序的最上面包含 stdlib.h 这个头文件

查看代码
  1. #include <stdlib.h>

2.4、printChessboard 函数

功能:

  • 打印出行号和列号,并打印出棋盘
  • 数组元素的值为0,打印出星号(*),表示该位置没有人落子
  • 数组元素的值为1,打印实心圆(X,玩家1的棋子)
  • 数组元素的值为2,打印空心圆(O,玩家2的棋子)
查看代码
  1. void printChessboard(void)
  2. {
  3. int i, j;
  4. for (i = 0; i <= N; i++)
  5. {
  6. for (j = 0; j <= N; j++)
  7. {
  8. if (0 == i) //这样可以打印出列号
  9. printf("%3d", j);
  10. else if (j == 0) //打印出行号
  11. printf("%3d", i);
  12. else if (1 == chessboard[i][j])
  13. //windows下●占2列,前面只需加一个空格
  14. printf(" X");
  15. else if (2 == chessboard[i][j])
  16. printf(" O");
  17. else
  18. printf(" *");
  19. }
  20. printf("\n");
  21. }
  22. }

2.5、 playChess 函数

函数功能:

  • 要求玩家输入准备落子的位置
  • 如果当前是玩家1落子,就将1赋值给数组中对应位置的元素
  • 如果当前是玩家2落子,就将2赋值给数组中对应位置的元素
  • 每次落子完毕,判断当前玩家是否获胜
查看代码
  1. void playChess(void)
  2. {
  3. int i, j, winner;
  4. //判断轮到玩家1还是玩家2,然后把值赋给数组中对应的元素
  5. if (1 == whoseTurn % 2)
  6. {
  7. printf("轮到玩家1,请输入棋子的位置,格式为行号+空格+列号:");
  8. scanf("%d %d", &i, &j);
  9. chessboard[i][j] = 1;
  10. }
  11. else
  12. {
  13. printf("轮到玩家2,请输入棋子的位置,格式为行号+空格+列号:");
  14. scanf("%d %d", &i, &j);
  15. chessboard[i][j] = 2;
  16. }
  17. //重新打印一次棋盘
  18. system("clear");
  19. printChessboard(); //再次调用了这个函数
  20. /*
  21. *下面这段调用了自定义函数(judge函数)
  22. *用来判断当前玩家下完这步棋后,他有没有获胜
  23. *具体怎么判断的,马上就给大家解释哦
  24. */
  25. if (judge(i, j, whoseTurn))
  26. {
  27. if (1 == whoseTurn % 2)
  28. printf("玩家1胜!\n");
  29. else
  30. printf("玩家2胜!\n");
  31. }
  32. }

2.6、judge函数

函数参数:

  • x:当前落子的行号
  • y:当前落子的列号

返回值:

  • 1或0。1表示当前玩家落子之后出现五子连一线,也就是当前玩家获胜
查看代码
  1. int judge(int x, int y)
  2. {
  3. int i, j;
  4. int t = 2 - whoseTurn % 2;
  5. const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}};
  6. for(int i=0;i<4;++i)
  7. {
  8. const int d[2]={-1,1};
  9. int count=1;
  10. for(int j=0;j<2;++j)
  11. for(int k=1;k<=4;++k){
  12. int row=x+k*d[j]*step[i][0];
  13. int col=y+k*d[j]*step[i][1];
  14. if( row>=1 && row<=N && col>=1 && col<=N &&
  15. chessboard[x][y]==chessboard[row][col])
  16. count+=1;
  17. else
  18. break;
  19. }
  20. if(count>=5)
  21. return 1;
  22. }
  23. return 0;
  24. }

judge 这个函数中,有 3 个嵌套的 for 循环,这 3 个循环的目的在于判断是否有五子连城一条线。

五子连线,无非是在一行上,一列或者斜方向上有连续的五个子。在这里,我们将采取一种试探的方法,即沿着水平,竖直,倾斜等方向分别寻找是否有五子连线。下面举一个例子:

在上面的对局中,我们以(9,10)来讲解判断五子是否成线的算法。

首先判断(9,10)的倾斜方向是否出现五子连线,判断方式如下:

  • 以(9,10)为起点,向左上方向依此寻找,满足条件的坐标分别是(8,9),(7,8),(6,7)。因为(5,6)不满足条件,所以进入下一步
  • 然后在向右下方寻找,找到(10,11),仅有一个满足条件的点。
  • 然后一共找到五个在同一直线上的点,所以玩家二取得胜利,

如果倾斜方向不满足取胜的条件,就再判断竖直方向,水平方向,如果均不成立,这意味着当前玩家无法取得胜利,对局将会继续。

到这里,我们的五子棋游戏就基本上完成了。不过,我们的项目课并没有结束,我们还要对项目做一个后期的维护工作。

3.1 我的棋子被“吃”了

不知道大家发现没有,我们的五子棋小游戏在落子时,即便是落子的位置已经被占用,依旧可以“吃掉”原棋子。 这是因为我们在写 playChess 函数的时候,没有对落子位置进行检测。我们可以这样修改我们的代码:

查看代码
  1. void playChess(void)
  2. {
  3. int i, j, winner;
  4. if (1 == whoseTurn % 2)
  5. {
  6. printf("轮到玩家1,请输入棋子的位置,格式为行号+空格+列号:");
  7. scanf("%d %d", &i, &j);
  8. //修复BUG
  9. while(chessboard[i][j] != 0)
  10. {
  11. printf("您要下的位置已经被占用了哦,请重新输入:");
  12. scanf("%d %d", &i, &j);
  13. }
  14. //修复BUG
  15. chessboard[i][j] = 1;
  16. }
  17. else
  18. {
  19. printf("轮到玩家2,请输入棋子的位置,格式为行号+空格+列号:");
  20. scanf("%d %d", &i, &j);
  21. //修复BUG
  22. while(chessboard[i][j] != 0)
  23. {
  24. printf("您要下的位置已经被占用了哦,请重新输入:");
  25. scanf("%d %d", &i, &j);
  26. }
  27. //修复BUG
  28. chessboard[i][j] = 2;
  29. }
  30. system("clear");
  31. printChessboard();
  32. if (judge(i, j))
  33. {
  34. if (1 == whoseTurn % 2)
  35. printf("玩家1胜!\n");
  36. else
  37. printf("玩家2胜!\n");
  38. }
  39. }

在函数中加入一个循环,当落子位置已经被占用时,给出提示,并且要求重新输入。

3.2 我怎么永远赢不了

当出现五子连线的时候,提示玩家1或玩家2获胜之后,又提示“轮到玩家*,请输入棋子位置……” 是不是很郁闷呢? 其实我们只要加一句代码就行!

查看代码
  1. if (judge(i, j))
  2. {
  3. if (1 == whoseTurn % 2)
  4. {
  5. printf("玩家1胜!\n");
  6. exit(0); //修复BUG
  7. }
  8. else
  9. {
  10. printf("玩家2胜!\n");
  11. exit(0); //修复BUG
  12. }
  13. }
  14. }

在获胜后除了提示玩家某某获胜意外,退出游戏exit(0)

源代码

查看代码
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define N 15
  4. int chessboard[N+1][N+1]={0};
  5. int whoseTurn=0;
  6. void initGame(void);
  7. void printChessboard(void);
  8. void playChess(void);
  9. int judge(int ,int );
  10. int main(void)
  11. {
  12. initGame();
  13. while(1)
  14. {
  15. whoseTurn++;
  16. playChess();
  17. }
  18. return 0;
  19. }
  20. void initGame(void)
  21. {
  22. char c;
  23. printf("Please intput \'y\' to enter the game:");
  24. c = getchar();
  25. if('y'!=c&&'Y'!=c)
  26. exit(0);
  27. system("clear");
  28. printChessboard();
  29. }
  30. void printChessboard(void){
  31. int i,j;
  32. for(i=0;i<=N;i++){
  33. for(j=0;j<=N;j++){
  34. if(0==i)
  35. printf("%3d",j);
  36. else if(j==0)
  37. printf("%3d",i);
  38. else if(1==chessboard[i][j])
  39. printf(" 0");
  40. else if(2==chessboard[i][j])
  41. printf(" X");
  42. else
  43. printf(" *");
  44. }
  45. printf("\n");
  46. }
  47. }
  48. void playChess(void)
  49. {
  50. int i,j,winner;
  51. if(1==whoseTurn%2)
  52. {
  53. printf("Turn to player 1,please input the position:");
  54. scanf("%d %d",&i,&j);
  55. while(chessboard[i][j]!=0)
  56. {
  57. printf("This position has been occupied,please input the position again:");
  58. scanf("%d %d",&i,&j);
  59. }
  60. chessboard[i][j]=1;
  61. }
  62. else
  63. {
  64. printf("Turn to player 2,please input the position:");
  65. scanf("%d %d",&i,&j);
  66. while(chessboard[i][j]!=0)
  67. {
  68. printf("This position has been occupied,please input the position again:");
  69. scanf("%d %d",&i,&j);
  70. }
  71. chessboard[i][j]=1;
  72. }
  73. system("clear");
  74. printChessboard();
  75. if(judge(i,j))
  76. {
  77. if(1==whoseTurn%2)
  78. {
  79. printf("Winner is player 1!\n");
  80. exit(0);
  81. }
  82. else
  83. {
  84. printf("Winner is player 2!\n");
  85. exit(0);
  86. }
  87. }
  88. }
  89. int judge(int x,int y)
  90. {
  91. int i,j;
  92. int t= 2 - whoseTurn%2;
  93. const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}};
  94. for(int i=0;i<4;i++){
  95. const int d[2]={-1.1};
  96. int count=1;
  97. for(int j=0;j<2;++j)
  98. for(int k=1;k<=4;k++){
  99. int row=x+k*d[j]*step[i][0];
  100. int col=y+k*d[j]*step[i][1];
  101. if(row>=1&&row<=N&&
  102. col>=1&&col<=N&&
  103. chessboard[x][y]==chessboard[row][col])
  104. count+=1;
  105. else
  106. break;
  107. }
  108. if(count>=5)
  109. return 1;
  110. }
  111. return 0;
  112. }
在黑夜里梦想着光,心中覆盖悲伤,在悲伤里忍受孤独,空守一丝温暖。 我的泪水是无底深海,对你的爱已无言,相信无尽的力量,那是真爱永在。 我的信仰是无底深海,澎湃着心中火焰,燃烧无尽的力量,那是忠诚永在

原文链接:http://www.cnblogs.com/yyyyfly1/p/15773485.html

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

本站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号