当前位置:   article > 正文

三子棋(N子棋)C语言编程实现,超详细讲解_c语言三子棋列子

c语言三子棋列子

你好,本期内容,纯干货,三子棋详细教程,现在开始!

目录

一.main函数所在的.c为后缀的源代码

1.main函数内容的框架

2.srand与rand

3.game()函数的框架

二.game.h游戏源代码所需要的头文件

1.为什么要把这些头文件放在game.h里面?

2.头文件与源文件的区别

三.game.c游戏源代码的实现

1. 棋盘打印的思路:

2.玩家下棋的思路:

3.电脑下棋的思路:

4.谁是赢家的思路:

5.棋盘是否满的思路:

四.game.c源代码


一.main函数所在的.c为后缀的源代码

  1. #include "game.h"
  2. void menu()
  3. {
  4. printf("********************\n");
  5. printf("***1.play 0.exit***\n");
  6. printf("********************\n");
  7. }
  8. void game()
  9. {
  10. char board[ROW][COL] = { 0 };
  11. char ret = 0;
  12. initboard(board, ROW, COL); //初始化棋盘
  13. printboard(board, ROW, COL); //打印棋盘
  14. while (1)
  15. {
  16. playerdown(board, ROW, COL); //玩家下棋
  17. ret = is_winner(board, ROW, COL); //判断赢家
  18. if (ret != 'C')
  19. {
  20. break;
  21. }
  22. printboard(board, ROW, COL); //打印棋盘
  23. computerdown(board, ROW, COL); //电脑下棋
  24. ret = is_winner(board, ROW, COL); //判断赢家
  25. if (ret != 'C')
  26. {
  27. break;
  28. }
  29. printboard(board, ROW, COL); //打印棋盘
  30. }
  31. if (ret == '*') //判断赢家
  32. printf("玩家赢\n");
  33. else if (ret == '#')
  34. printf("电脑赢\n");
  35. else if (ret == 'Q')
  36. printf("平局\n");
  37. printboard(board, ROW, COL); //打印胜利的战果
  38. }
  39. //主函数
  40. int main()
  41. {
  42. int input = 0;
  43. srand((unsigned int)time(NULL)); //用于电脑下棋时所需要的随机值
  44. do
  45. {
  46. menu(); //菜单
  47. printf("请选择:>");
  48. scanf_s("%d", &input);
  49. switch (input) //选择
  50. {
  51. case 1:
  52. game(); break;
  53. case 0:
  54. printf("退出游戏\n"); break;
  55. default: //输入1开始游戏,输入0退出游戏
  56. printf("选择错误,请从新选择\n"); break; //while条件为真则继续,为假终止循环
  57. } //输入非10 从新选择,非0继续循环
  58. } while (input); //
  59. return 0;
  60. }

1.main函数内容的框架

  1. 菜单
  2. 选择
  3. 根据选择调用所属函数

2.srand与rand

   1.大致内容

      srand意思为设置rand的生成器,初始化随机数生成器它是个库函数,头文件为#include            <stdlib.h>

      详细内容请见:srand参考

      rand()生成的是1-RANDMAX(32767)的随机值,头文件与srand一样

      详细内容请见:   rand参考

   2.srand( (unsigned int) time(NULL) )

      time设置时间戳(下面会给你讲解),time是一个库函数,头文件#include <time.h>

      传参NULL意思为空指针,将time强制转换为无符号整形(unsigned int)

      详细内容请见:time参考

      时间戳(单位为秒):系统当前时间-系统起始时间

3.game()函数的框架

1.大致内容:

棋盘的初始化需要一个字符类型的二维数组来实现,棋盘的初始内容应当是空格,玩家输入坐标,将某个字符存储到所选坐标x-1,坐标y-1为下标的二维数组内,判断是否赢了,其次电脑利用srand设置的生成器后的rand来设置随机值,利用这个随机值%上棋盘的行数或者列数,得到的值的范围是小于行数的,放心将其作为下标,引用棋盘的二维数组,将咱们自己所设置的字符存入这个二维数组。判断是否赢了,如果赢了,则打印赢家。

2.ROW行与COL列的初始化

由于行与列需要我们自己任意定义,所以我们应当选择更合适的#define来标识符常量,排除需要换行改列的隐患,#define ROW 3    #define  COL 3,由于实现整个程序不止test.c源文件要使用ROW行与COL列,我们要把ROW,COL设置在game.h头文件里,在test.c文件头部输入代码#include "game.h",注意:双引号所引用的头文件为咱们自己设置的头文件,尖括号所引用的头文件为库函数所需要的头文件

二.game.h游戏源代码所需要的头文件

  1. #include <stdio.h> //输入输出头文件
  2. #include <time.h> //time设置时间戳头文件
  3. #include <stdlib.h> //rand,srand设置随机值头文件
  4. #define ROW 5 //行的设置
  5. #define COL 5 //列的设置
  6. void initboard(char board[ROW][COL], int row, int col); //初始化棋盘
  7. void printboard(char board[ROW][COL], int row, int col); //打印棋盘
  8. void playerdown(char board[ROW][COL], int row, int col); //玩家下棋
  9. void computerdown(char board[ROW][COL], int row, int col);//电脑下棋
  10. char is_winner(char board[ROW][COL], int row, int col); //谁是赢家

1.为什么要把这些头文件放在game.h里面?

因为咱的test.c源文件的代码里面包含了game.h的头文件,所以它能够实现game.h里面的功能。

2.头文件与源文件的区别

头文件来声明,源文件来定义。

例如:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int a = 10;
  5. int b = 20;
  6. printf("%d\n",add(a, b));
  7. return 0;
  8. }
  9. int add(int a, int b)
  10. {
  11. return a + b;
  12. }

上面的代码控制台会出现:

咱知道程序的扫描是自上而下的,在main函数之前定义add函数是非不可选的,那么如何将其“add未定义,假设外部返回int”的这段话不报告的话,这里就是需要“声明”上线了

  1. #include <stdio.h>
  2. int add(int a, int b); //这就是声明,标注其函数的返回类型,函数参数的类型
  3. int main()
  4. {
  5. int a = 10;
  6. int b = 20;
  7. printf("%d\n",add(a, b));
  8. return 0;
  9. }
  10. int add(int a, int b)
  11. {
  12. return a + b;
  13. }

三.game.c游戏源代码的实现

棋盘的执行效果:

1. 棋盘打印的思路:

board[ROW][COL]中的元素与 | 打印在一行,但 | 有限制条件,就是当j < col - 1  注意:col是COL传参后的临时拷贝,意思为列

其次打印 --- 与 | ,--- 的限制条件是i < row-1,i为行的循环, | 的限制条件为j < col - 1, row为行

2.玩家下棋的思路:

1.输入坐标x,y

2.判断该坐标x-1,y-1引用下标后的二维数组那个元素是否为空格,或者是否为电脑所下过的棋子,或者坐标非法,如果条件满足,则执行board[x-1][y-1] = '*';break;

  1. void playerdown(char board[ROW][COL], int row, int col) //玩家下棋
  2. {
  3. int x = 0;
  4. int y = 0;
  5. while (1)
  6. {
  7. printf("玩家下棋\n");
  8. printf("请输入坐标:>");
  9. scanf_s("%d %d", &x, &y);
  10. if ((x <= row && x - 1 >= 0) || (y <= col && y - 1 >= 0))
  11. {
  12. if (board[x - 1][y - 1] == '#')
  13. {
  14. printf("坐标已经被占用,请从新输入\n");
  15. }
  16. if (board[x - 1][y - 1] == ' ')
  17. {
  18. board[x - 1][y - 1] = '*';
  19. break;
  20. }
  21. }
  22. else
  23. printf("坐标非法,请从新输入\n");
  24. }
  25. }

3.电脑下棋的思路:

1.初始化x,y

初始化的值为rand%row和rand%col,即大于等于0,小于row或者col的值的范围

2.判断条件

如果满足,赋值'#'

  1. void computerdown(char board[ROW][COL], int row, int col) //电脑下棋
  2. {
  3. int x = rand() % row;
  4. int y = rand() % col;
  5. printf("电脑下棋\n");
  6. while (1)
  7. {
  8. if (board[x][y] == ' ')
  9. {
  10. board[x][y] = '#';
  11. break;
  12. }
  13. else
  14. {
  15. x = rand() % row;
  16. y = rand() % col;
  17. }
  18. }
  19. }

4.谁是赢家的思路:

1.框架

①横向连线判断

②竖向连线判断

③X型连线判断

2.具体

  1. for (i = 0; i < row; i++)
  2. {
  3. count = 0;
  4. for (j = 0; j < col - 1; j++)
  5. {
  6. if (board[i][j] == board[i][j + 1] && board[i][j] != ' ' && board[i][j + 1] != ' ')
  7. {
  8. count++;
  9. }
  10. }
  11. if (count == ROW - 1)
  12. {
  13. return board[i][0];
  14. }
  15. }

①横向连线判断

横向的和行、列都有关系,所以嵌套两层循环,比如第一行,咱需要判断两个紧挨着的1列和2列的内容是否相同,那这需要需要一个变量来计数,我设置整形count,利用count++来计数,那咱这计数也需要判断条件吧,咱知道紧挨着的凑两对的数量极限是board[0][2]吧,那么if条件中的==操作符右值应当撑死是board[0][2],所以你思考一下,j+1中j的值是否是应该撑死是col-1-1,由于我们for循环中j的初值是0,所以判断条件应当是j<col-1。

注意:空格也是存在相同的内容的,所以这里也需要判断该坐标-1后为下标的元素是否是空格,count最终计算的值应当是判断是否相等我们的列-1,如果条件满足,返回这个返回值,设置board[i][0]意思为返回第i行下标为0的元素,这个元素不是#就是*,因为*是玩家,#是电脑.

  1. for (i = 0; i < row; i++)
  2. {
  3. count = 0;
  4. for (j = 0; j < col - 1; j++)
  5. {
  6. if (board[j][i] == board[j + 1][i] && board[j][i] != ' ' && board[j + 1][i] != ' ')
  7. {
  8. count++;
  9. }
  10. }
  11. if (count == COL - 1)
  12. {
  13. return board[0][i];
  14. }
  15. }

②竖向连线判断

竖向就是先把列固定住,循环行来判断紧邻两个元素是否相等

具体实践就是board[j][i] == board[j+1][i]

并且这两个元素不为空格

①横向连线判断中的count的计算相同道理,返回值主要与列有关。

  1. //左上-右下
  2. count = 0;
  3. for (i = 0; i < col - 1; i++)
  4. {
  5. if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ' && board[i + 1][i + 1] != ' ')
  6. {
  7. count++;
  8. }
  9. }
  10. if (count == col - 1)
  11. return board[0][0];

③X型连线判断

1.左上---右下

无非是一层循环判断board[i][i] = board[i+1][i+1]并且两个元素不为空格,再count++;

这里对角线的x与y相等,就好比数学中的函数y=x的图像。

  1. //右上---左下
  2. count = 0;
  3. for (i = 0; i < row - 1; i++)
  4. {
  5. if (board[i][row-1-i] == board[i+1][row-2-i] && board[i][row - 1 - i] != ' ' && board[i + 1][row - 2 - i] != ' ')
  6. {
  7. count++;
  8. }
  9. }
  10. if (count == col - 1)
  11. {
  12. return board[i][row-1-i];
  13. }

③X型连线判断

2.右上---左下

经过上面一些代码的磨练,这个难度相对较高一点

我们知道这个列是从row-1开始的,行是从0开始的,但是每次循环都是从row-1的列下标开始的吗?答案是:NO!我们总要把列下标与行建立关系吧,所以就有了row-1-i,一层循环就够了,跟1.左上---右下相似,最终返回的值为与咱们判断的需要的任意一个值一样就ok了。

5.棋盘是否满的思路:

看代码,你就懂了。

  1. int if_full(char board[ROW][COL], int row, int col) //判断棋盘是否满了
  2. {
  3. int i = 0;
  4. int j = 0;
  5. for (i = 0; i < row; i++)
  6. {
  7. for (j = 0; j < col; j++)
  8. {
  9. if (board[i][j] == ' ')
  10. return 0;
  11. }
  12. }
  13. return 1;
  14. }

四.game.c源代码:

  1. #include "game.h"
  2. /*----------------------------------------------------------------------------------*/
  3. void initboard(char board[ROW][COL], int row, int col) //初始化棋盘,初始化为空格
  4. {
  5. int i = 0;
  6. int j = 0;
  7. for (i = 0; i < row; i++)
  8. {
  9. for (j = 0; j < col; j++)
  10. {
  11. board[i][j] = ' ';
  12. }
  13. }
  14. }
  15. /*----------------------------------------------------------------------------------*/
  16. void printboard(char board[ROW][COL], int row, int col) //打印棋盘
  17. {
  18. int i = 0;
  19. int j = 0;
  20. for (i = 0; i < row; i++)
  21. {
  22. for (j = 0; j < col; j++)
  23. {
  24. printf(" %c ", board[i][j]);
  25. if (j < col - 1)
  26. {
  27. printf("|");
  28. }
  29. }
  30. printf("\n");
  31. for (j = 0; j < col; j++)
  32. {
  33. if (i < row - 1)
  34. {
  35. printf("---");
  36. if (j < col - 1)
  37. {
  38. printf("|");
  39. }
  40. }
  41. }
  42. printf("\n");
  43. }
  44. }
  45. /*----------------------------------------------------------------------------------*/
  46. void playerdown(char board[ROW][COL], int row, int col) //玩家下棋
  47. {
  48. int x = 0;
  49. int y = 0;
  50. while (1)
  51. {
  52. printf("玩家下棋\n");
  53. printf("请输入坐标:>");
  54. scanf_s("%d %d", &x, &y);
  55. if ((x <= row && x - 1 >= 0) || (y <= col && y - 1 >= 0))
  56. {
  57. if (board[x - 1][y - 1] == '#')
  58. {
  59. printf("坐标已经被占用,请从新输入\n");
  60. }
  61. if (board[x - 1][y - 1] == ' ')
  62. {
  63. board[x - 1][y - 1] = '*';
  64. break;
  65. }
  66. }
  67. else
  68. printf("坐标非法,请从新输入\n");
  69. }
  70. }
  71. /*----------------------------------------------------------------------------------*/
  72. void computerdown(char board[ROW][COL], int row, int col) //电脑下棋
  73. {
  74. int x = rand() % row;
  75. int y = rand() % col;
  76. printf("电脑下棋\n");
  77. while (1)
  78. {
  79. if (board[x][y] == ' ')
  80. {
  81. board[x][y] = '#';
  82. break;
  83. }
  84. else
  85. {
  86. x = rand() % row;
  87. y = rand() % col;
  88. }
  89. }
  90. }
  91. int if_full(char board[ROW][COL], int row, int col) //判断棋盘是否满了
  92. {
  93. int i = 0;
  94. int j = 0;
  95. for (i = 0; i < row; i++)
  96. {
  97. for (j = 0; j < col; j++)
  98. {
  99. if (board[i][j] == ' ')
  100. return 0;
  101. }
  102. }
  103. return 1;
  104. }
  105. /*----------------------------------------------------------------------------------*/
  106. char is_winner(char board[ROW][COL], int row, int col) //谁是赢家
  107. {
  108. int i = 0;
  109. int j = 0;
  110. int count = 0;
  111. //
  112. for (i = 0; i < row; i++)
  113. {
  114. count = 0;
  115. for (j = 0; j < col - 1; j++)
  116. {
  117. if (board[i][j] == board[i][j + 1] && board[i][j] != ' ' && board[i][j + 1] != ' ')
  118. {
  119. count++;
  120. }
  121. }
  122. if (count == ROW - 1)
  123. {
  124. return board[i][0];
  125. }
  126. }
  127. //
  128. for (i = 0; i < row; i++)
  129. {
  130. count = 0;
  131. for (j = 0; j < col - 1; j++)
  132. {
  133. if (board[j][i] == board[j + 1][i] && board[j][i] != ' ' && board[j + 1][i] != ' ')
  134. {
  135. count++;
  136. }
  137. }
  138. if (count == COL - 1)
  139. {
  140. return board[0][i];
  141. }
  142. }
  143. //X
  144. //左上-右下
  145. count = 0;
  146. for (i = 0; i < col - 1; i++)
  147. {
  148. if (board[i][i] == board[i + 1][i + 1] && board[i][i] != ' ' && board[i + 1][i + 1] != ' ')
  149. {
  150. count++;
  151. }
  152. }
  153. if (count == col - 1)
  154. return board[0][0];
  155. //左下-右上
  156. count = 0;
  157. for (i = 0; i < row - 1; i++)
  158. {
  159. if (board[i][row-1-i] == board[i+1][row-2-i] && board[i][row - 1 - i] != ' ' && board[i + 1][row - 2 - i] != ' ')
  160. {
  161. count++;
  162. }
  163. }
  164. if (count == col - 1)
  165. {
  166. return board[i][row-1-i];
  167. }
  168. if (if_full(board, ROW, COL))
  169. {
  170. return 'Q'; //Q为平局
  171. }
  172. return 'C'; //返回值C为继续
  173. }

本期内容当中的ROW行与COL列可以设置任何无符号整形值,棋盘大小可不止3X3。

那么你应该收获了许多吧,代码哪里需要改正的话,评论区留言,多多指教,共同进步!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/909578
推荐阅读
相关标签
  

闽ICP备14008679号