• 五子棋(C语言实现)


    目录

    构思

    1、主程序

    2、初始化

    3、游戏菜单

    4、打印棋盘

    6、玩家下棋

    7、判断输赢

     8、功能整合

    人机下棋

    完整版: 

    game.h

    game.c

    text.c

     测试功能代码


    构思

    五子棋不必多介绍了,大家小时候都玩过哈。

    我们要通过程序实现这个小游戏,大体上的构思得有:

    游戏流程:运行游戏>>打印棋盘>>下棋>>判断输赢

    由此,我们声明如下函数、棋盘数组和回合数 (用于双人下棋时下不同棋子的判断)。

    将这些都放在我创建的头文件game.h中方便其他文件使用: 

    1. #include
    2. #include
    3. int map[19][19];//棋盘
    4. int flag;//回合数
    5. //初始化棋盘
    6. void init();
    7. //游戏菜单
    8. void menuView();
    9. //打印棋盘
    10. void gameView_ShowMap();
    11. //玩家下棋
    12. int playerMove(int x, int y);
    13. //判断输赢
    14. int isWin(int x, int y);
    15. //判断输赢
    16. void winView();

    1、主程序

    先进行游戏下棋,后进行判断输赢,比较符合do—while的特点。 

    1. int main()
    2. {
    3. int input = 0;
    4. do
    5. {
    6. menuView();
    7. printf("请选择:");
    8. scanf("%d", &input);
    9. switch (input) {
    10. case 1:
    11. gameView();
    12. break;
    13. case 0:
    14. printf("退出游戏\n");
    15. break;
    16. default:
    17. printf("输入错误,请重新选择.\n");
    18. break;
    19. }
    20. } while (input);
    21. return 0;
    22. }
    • 首先打印菜单,提示玩家进行选择开始游戏。
    • 通过输入变量input的值,判断是否进行游戏,
    • 值为1则调用gameView函数进行游戏,0则结束游戏。
    • gameView函数对各种功能函数进行整合。

    在此之前先将各种功能函数进行实现,最后将它们放入gameView整合。 

    2、初始化

    1. void init() {
    2. for (int i = 0; i < 19; i++) {
    3. for (int j = 0; j < 19; j++) {
    4. map[i][j] = 0;
    5. }
    6. }
    7. flag = 0;
    8. }
    • 将棋盘每个格子初始化为0。
    • 回合数初始化为0。

    3、游戏菜单

    1. void menuView() {
    2. printf("*************************\n");
    3. printf("***** 1. play ******\n");
    4. printf("***** 0. exit ******\n");
    5. printf("*************************\n");
    6. }

    4、打印棋盘

    这里我选择设计了棋盘格和横纵坐标,我们可以根据需要自行设计。 

    1. void gameView_ShowMap() {
    2. int i, j;
    3. printf(" ");
    4. for (i = 0; i < 19; i++) {//打印横坐标
    5. printf("%3d ",i);
    6. }
    7. printf("\n ");
    8. for (i = 0; i < 19; i++) {
    9. printf("+---");
    10. }
    11. printf("+\n");
    12. for (i = 0; i < 19; i++) {
    13. printf("%2d |", i);//每行输出前都先打印纵坐标
    14. for (j = 0; j < 19; j++) {
    15. printf(" %d ", map[i][j]);//打印棋子
    16. if (j < 18)
    17. printf("|");
    18. }
    19. printf("|\n");
    20. if(i<18)
    21. printf(" |");
    22. if(i==18)
    23. printf(" +");
    24. for (j = 0; j < 19; j++) {
    25. printf("---");
    26. if (j < 18)
    27. printf("+");
    28. }
    29. printf("+\n");
    30. }
    31. }

    效果如下: 

    6、玩家下棋

    1. int playerMove(int x, int y) {
    2. if (x >= 0 && x < 19 && y >= 0 && y < 19) {
    3. if (map[x][y] == 0) {
    4. if (flag % 2 == 0)
    5. map[x][y] = 1;//下黑子
    6. else
    7. map[x][y] = 2;//下白子
    8. //落子成功
    9. return 1;
    10. }
    11. else {
    12. //该位置已有棋子
    13. return 0;
    14. }
    15. }
    16. else {
    17. //坐标不合法
    18. return -1;
    19. }
    20. }
    • 首先判断下棋位置是否在棋盘0到18的横纵坐标内,如果不在函数返回值-1,
    • 如果在棋盘内,则进行下棋。
    • 棋盘每个格子初始值为0,判断当前格子的值为0才可以下棋,否则返回值为0。
    • 回合数flag初始值为0,当flag为偶数下黑子>>1,奇数下白子>>2,成功下棋返回值为1。

    7、判断输赢

    1. int isWin(int x, int y) {
    2. int i, j;
    3. for (i = 0; i < 19; i++) {
    4. for (j = 0; j < 19; j++) {
    5. if (map[i][j] == 0) {
    6. continue;
    7. }
    8. //横着连成五子
    9. if (j < 15)
    10. if (map[i][j] == map[i][j + 1] && map[i][j] == map[i][j + 2]
    11. && map[i][j] == map[i][j + 3] && map[i][j] == map[i][j + 4])
    12. return map[i][j];
    13. //竖着连成五子
    14. if (i < 15)
    15. if (map[i][j] == map[i + 1][j] && map[i][j] == map[i + 2][j]
    16. && map[i][j] == map[i + 3][j] && map[i][j] == map[i + 4][j])
    17. return map[i][j];
    18. //左斜着连成五子-> " \ "
    19. if (i < 15 && j < 15)
    20. if (map[i][j] == map[i + 1][j + 1] && map[i][j] == map[i + 2][j + 2]
    21. && map[i][j] == map[i + 3][j + 3] && map[i][j] == map[i + 4][j + 4])
    22. return map[i][j];
    23. //右斜着连成五子-> " / "
    24. if (i < 15 && j > 4)
    25. if (map[i][j] == map[i + 1][j - 1] && map[i][j] == map[i + 2][j - 2]
    26. && map[i][j] == map[i + 3][j - 3] && map[i][j] == map[i + 4][j - 4])
    27. return map[i][j];
    28. }
    29. }
    30. return 0;
    31. }
    • i < 15 用于确保在检查垂直和左斜方向的连续五子时,起始位置 (i, j) 之后至少还有4个位置。因为五子连成一线需要五个连续的位置,所以确保从当前位置开始往下检查的时候不会超出数组的边界。

    • j < 15 用于确保在检查水平和左斜方向的连续五子时,起始位置 (i, j) 之后至少还有4个位置。同样,这是为了确保从当前位置开始往右检查的时候不会超出数组的边界。

    • j > 4 用于确保在检查右斜方向的连续五子时,起始位置 (i, j) 之前至少还有4个位置。这是为了确保从当前位置开始往左检查的时候不会超出数组的边界。

     8、功能整合

    1. void gameView()
    2. {
    3. init();
    4. int x = 0, y = 0;
    5. int ret = 0;//辅助判断坐标是否合法
    6. while (1) {
    7. gameView_ShowMap();
    8. printf("请输入要下棋的坐标:");
    9. scanf("%d %d", &x, &y);
    10. if (playerMove(x, y) == 0) {
    11. printf("\n!!!该坐标已被占用!!!\n");
    12. Sleep(2000);
    13. continue;
    14. }
    15. else if (playerMove(x, y) == -1) {
    16. printf("\n!!!请输入合法坐标!!!\n");
    17. Sleep(2000);
    18. continue;
    19. }
    20. else {
    21. flag++;//切换回合
    22. }
    23. if (isWin(x, y) == 0) {
    24. continue;
    25. }
    26. else if (isWin(x, y) == 1) {
    27. printf("黑子获胜\n");
    28. break;
    29. }
    30. else if (isWin(x, y) == 2) {
    31. printf("白子获胜\n");
    32. break;
    33. }
    34. }
    35. }
    •  这里的Sleep函数需要头文件#include ,使用该函数暂停两秒,防止continue后下次循环打印的棋盘将提示信息挡住。
    • 下棋坐标不合法打印提示信息后,进入下次循环重新输入。
    • 成功下棋则flag自增,切换回合。
    • 每次下棋后都要判断输赢,有人赢了则停止循环,否则继续下棋。
    • (其实应该从下棋次数第五次开始判断输赢更合理,读者可以自行添加判断)

    人机下棋

    想要实现人机下棋可以看看我这篇文章《三子棋》 ,里面实现了人机下棋,读者可以自行模仿改进,实现其功能的重要函数可以在这篇文章中学习 rand&srand函数 。 

    完整版: 

    game.h

    1. #include
    2. #include
    3. int map[19][19];//棋盘
    4. int flag;//回合数
    5. //初始化
    6. void init();
    7. //游戏菜单
    8. void menuView();
    9. //打印棋盘
    10. void gameView_ShowMap();
    11. //玩家下棋
    12. int playerMove(int x, int y);
    13. //判断输赢
    14. int isWin(int x, int y);

    game.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"
    3. void init() {
    4. for (int i = 0; i < 19; i++) {
    5. for (int j = 0; j < 19; j++) {
    6. map[i][j] = 0;
    7. }
    8. }
    9. flag = 1;
    10. }
    11. int isWin(int x, int y) {
    12. int i, j;
    13. for (i = 0; i < 19; i++) {
    14. for (j = 0; j < 19; j++) {
    15. if (map[i][j] == 0) {
    16. continue;
    17. }
    18. //横着连成五子
    19. if (j < 15)
    20. if (map[i][j] == map[i][j + 1] && map[i][j] == map[i][j + 2]
    21. && map[i][j] == map[i][j + 3] && map[i][j] == map[i][j + 4])
    22. return map[i][j];
    23. //竖着连成五子
    24. if (i < 15)
    25. if (map[i][j] == map[i + 1][j] && map[i][j] == map[i + 2][j]
    26. && map[i][j] == map[i + 3][j] && map[i][j] == map[i + 4][j])
    27. return map[i][j];
    28. //左斜着连成五子-> " \ "
    29. if (i < 15 && j < 15)
    30. if (map[i][j] == map[i + 1][j + 1] && map[i][j] == map[i + 2][j + 2]
    31. && map[i][j] == map[i + 3][j + 3] && map[i][j] == map[i + 4][j + 4])
    32. return map[i][j];
    33. //右斜着连成五子-> " / "
    34. if (i < 15 && j > 4)
    35. if (map[i][j] == map[i + 1][j - 1] && map[i][j] == map[i + 2][j - 2]
    36. && map[i][j] == map[i + 3][j - 3] && map[i][j] == map[i + 4][j - 4])
    37. return map[i][j];
    38. }
    39. }
    40. return 0;
    41. }
    42. int playerMove(int x, int y) {
    43. if (x >= 0 && x < 19 && y >= 0 && y < 19) {
    44. if (map[x][y] == 0) {
    45. if (flag % 2 == 0)
    46. map[x][y] = 1;//下黑子
    47. else
    48. map[x][y] = 2;//下白子
    49. //落子成功
    50. return 1;
    51. }
    52. else {
    53. //该位置已有棋子
    54. return 0;
    55. }
    56. }
    57. else {
    58. //坐标不合法
    59. return -1;
    60. }
    61. }
    62. void menuView() {
    63. printf("*************************\n");
    64. printf("***** 1. play ******\n");
    65. printf("***** 0. exit ******\n");
    66. printf("*************************\n");
    67. }
    68. void gameView_ShowMap() {
    69. int i, j;
    70. printf(" ");
    71. for (i = 0; i < 19; i++) {//打印横坐标
    72. printf("%3d ",i);
    73. }
    74. printf("\n ");
    75. for (i = 0; i < 19; i++) {
    76. printf("+---");
    77. }
    78. printf("+\n");
    79. for (i = 0; i < 19; i++) {
    80. printf("%2d |", i);//每行输出前先都打印纵坐标
    81. for (j = 0; j < 19; j++) {
    82. printf(" %d ", map[i][j]);
    83. if (j < 18)
    84. printf("|");
    85. }
    86. printf("|\n");
    87. if(i<18)
    88. printf(" |");
    89. if(i==18)
    90. printf(" +");
    91. for (j = 0; j < 19; j++) {
    92. printf("---");
    93. if (j < 18)
    94. printf("+");
    95. }
    96. printf("+\n");
    97. }
    98. }

    text.c

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"
    3. void gameView()
    4. {
    5. init();
    6. int x = 0, y = 0;
    7. int ret = 0;//辅助判断坐标是否合法
    8. while (1) {
    9. gameView_ShowMap();
    10. printf("请输入要下棋的坐标:");
    11. scanf("%d %d", &x, &y);
    12. if (playerMove(x, y) == 0) {
    13. printf("\n!!!该坐标已被占用!!!\n");
    14. Sleep(2000);
    15. continue;
    16. }
    17. else if (playerMove(x, y) == -1) {
    18. printf("\n!!!请输入合法坐标!!!\n");
    19. Sleep(2000);
    20. continue;
    21. }
    22. else {
    23. flag++;//切换回合
    24. }
    25. if (isWin(x, y) == 0) {
    26. continue;
    27. }
    28. else if (isWin(x, y) == 1) {
    29. printf("黑子获胜\n");
    30. break;
    31. }
    32. else if (isWin(x, y) == 2) {
    33. printf("白子获胜\n");
    34. break;
    35. }
    36. }
    37. }
    38. int main()
    39. {
    40. int input = 0;
    41. do
    42. {
    43. menuView();
    44. printf("请选择:");
    45. scanf("%d", &input);
    46. switch (input) {
    47. case 1:
    48. gameView();
    49. break;
    50. case 0:
    51. printf("退出游戏\n");
    52. break;
    53. default:
    54. printf("输入错误,请重新选择.\n");
    55. break;
    56. }
    57. } while (input);
    58. return 0;
    59. }

     测试功能代码

    此代码可以替换int main主函数,用于测试函数功能是否正确,可以减少自行下棋测试时间 

    成功运行输出如下:

    1. int main()
    2. {
    3. int testflag = 0;
    4. //init测试代码
    5. init();
    6. if (flag != 0) {
    7. printf("init()错误");
    8. exit(0);
    9. }
    10. for (int i = 0; i < 19; i++) {
    11. for (int j = 0; j < 19; j++) {
    12. if (map[i][j]) {
    13. printf("init()错误");
    14. exit(0);
    15. }
    16. }
    17. }
    18. printf("init()测试成功\n");
    19. testflag++;
    20. //playerMove测试代码
    21. int result = 1;
    22. result &= playerMove(2, 2);
    23. result &= playerMove(2, 3);
    24. result &= playerMove(2, 4);
    25. result &= playerMove(2, 5);
    26. if (result != 1 || (map[2][2] && map[2][3] && map[2][4] && map[2][5]) != 1) {
    27. printf("playerMove()错误");
    28. exit(0);
    29. }
    30. flag = 1;
    31. result &= playerMove(2, 5);
    32. if (result != 0 || map[2][5] != 1) {
    33. printf("playerMove()错误");
    34. exit(0);
    35. }
    36. printf("playerMove()测试成功\n");
    37. testflag++;
    38. //isWin测试代码
    39. playerMove(2, 1);
    40. if (isWin(2, 1)) {
    41. printf("isWin()错误");
    42. exit(0);
    43. }
    44. playerMove(1, 0);
    45. playerMove(3, 2);
    46. playerMove(4, 3);
    47. playerMove(5, 4);
    48. if (isWin(1, 0) != 2) {
    49. printf("isWin()错误");
    50. exit(0);
    51. }
    52. printf("isWin()测试成功\n");
    53. testflag++;
    54. if (testflag == 3) {
    55. printf("service代码测试成功\n");
    56. }
    57. return 0;
    58. }

  • 相关阅读:
    搞安全方向需要哪些技术基础和技能?
    常用数据库的 API - 开篇
    【HMS core】【IAP Kit】【FAQ】华为支付典型问题集
    运动控制比例随动系统学习笔记
    代码随想录刷题|动态规划理论基础 LeetCode 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯
    使用 Docker 自建一款怀旧游戏之 - 扫雷
    如何在小程序中给会员设置备注
    TwoModalBERT进行角色分类
    Android Studio实现内容丰富的安卓校园新闻浏览平台
    Android CPU Profile/TraceView
  • 原文地址:https://blog.csdn.net/m0_73800602/article/details/133828784