• C语言学习-数组应用-三子棋(4.1)


    目录

    三子棋的设计思路:

    1. 游戏菜单功能的实现

    2. 游戏功能具体实现

     2.1 棋盘的初始化与打印

    2.2 玩家与电脑对战的实现

    2.3 判断胜负平局的实现

    3. 三子棋源码

    写在最后:


    三子棋的设计思路:

    我们创建三个文件拆分三子棋的实现过程:

    一个测试文件(test.c)游戏实现文件(game.c)头文件(game.h)

    我们先对测试文件进行编辑。

    1. 游戏菜单功能的实现

    在 test.c 中写一个主函数:

    1. int main()//主函数尽量放的东西少一点
    2. {
    3. test();//可以通过创建一个函数实现其他功能
    4. return 0;
    5. }

    我们通过刚刚创建的 test 函数实现一些功能:

    1. 玩一把不过瘾,在玩一把

    2. 创建游戏菜单

    3. 创建游戏实现函数

    1. void test()
    2. {
    3. int choice = 0;
    4. do //我们使用一个do while循环,如果玩一把三子棋不过瘾,可以再玩一把
    5. {
    6. menu();
    7. printf("请选择:>");
    8. scanf("%d", &choice);//接收玩家输入的值
    9. switch (choice)
    10. {
    11. case 1:
    12. printf("三子棋游戏开始\n");
    13. game();//我们将游戏的实现分装成一个函数
    14. break;
    15. case 0:
    16. printf("游戏已退出\n");
    17. break;
    18. default:
    19. printf("输入错误,请重新输入\n");
    20. break;
    21. }
    22. } while (choice);
    23. }

    这是我们的游戏菜单:

    1. void menu()//打印游戏菜单界面
    2. {
    3. printf("***************************************\n");
    4. printf("***** 开始游戏:1 退出游戏:0 *****\n");
    5. printf("***************************************\n");
    6. }

    写到这里,我们可以先测试一下代码运行的结果:

    这样,我们就完成了菜单逻辑的制作

    2. 游戏功能具体实现

    接下来我们要具体实现函数 game 。

     2.1 棋盘的初始化与打印

    实现思路:

    首先,我们需要记录玩家和电脑的落子情况

     通过分析,能落子的地方有九个,

    我们可以通过创建一个3*3的数组对其进行记录。

    我们在头文件中用#define定义常量,便于日后观察或修改

     再在测试文件中引用:

    1. #include "game.h"//引用自己的头文件
    2. void game()//三子棋的实现
    3. {
    4. char board[ROW][COL];//存放玩家或电脑的落子情况
    5. }

    接下来我们需要让落子位置初始化,并将三子棋的棋盘打印出来:

    我们将初始化和棋盘打印这两个步骤分装成两个函数并在 game.c 中实现:

     为了能够使用这两个函数,我们需要在头文件中声明:

    1. void init_board(char board[ROW][COL], int row, int col);
    2. void print_board(char board[ROW][COL], int row, int col);

    初始化棋盘的具体实现:

    1. void init_board(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. for (i = 0; i < row; i++)
    5. {
    6. int j = 0;
    7. for (j = 0; j < col; j++)
    8. {
    9. board[i][j] = ' ';//将落子位置初始化成空格
    10. }
    11. }
    12. }

    打印棋盘的具体实现:

    1. void print_board(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. for (i = 0; i < col; i++)
    5. {
    6. printf(" %d ", i + 1);//添加纵坐标
    7. }
    8. printf("\n");
    9. for (i = 0; i < row; i++)
    10. {
    11. int j = 0;
    12. printf("%d", i + 1);//添加横坐标
    13. for (j = 0; j < col; j++)
    14. {
    15. printf(" %c ", board[i][j]);//打印三行,每行三个 %c
    16. if (j < col - 1)//井字棋的棋盘只需要中间两排竖着的分割线
    17. {
    18. printf("|");//打印三行,每行两个‘|’
    19. }
    20. }
    21. printf("\n");
    22. if (i < row - 1)//只需要两行分割线
    23. {
    24. printf(" ");//对齐
    25. for (j = 0; j < col; j++)
    26. {
    27. printf("---");//打印两行,每行三个‘---’
    28. if (j < col - 1)
    29. {
    30. printf("|");//打印两行,每行两个‘|’
    31. }
    32. }
    33. }
    34. printf("\n");
    35. }
    36. }

    最后呈现的结果是这样的:

    2.2 玩家与电脑对战的实现

     接下来就是下棋了,我们把下棋分为两步:

    1. 玩家回合

    2. 电脑回合

    并且每次下完把棋盘打印出来:

    然后将函数在头文件中声明,在 game.c 中实现:

    声明:

    1. void player_move(char board[ROW][COL], int row, int col);
    2. void computer_move(char board[ROW][COL], int row, int col);

     玩家回合的实现:

    1. void player_move(char board[ROW][COL], int row, int col)
    2. {
    3. printf("玩家回合\n");
    4. while (1)
    5. {
    6. printf("请输入要下的坐标:>");
    7. int x = 0;
    8. int y = 0;
    9. scanf("%d %d", &x, &y);
    10. //坐标合法(在棋盘中)
    11. if (x >= 1 && x <= row && y >= 1 && y <= col)
    12. {
    13. if (board[x - 1][y - 1] == ' ')//坐标是空的
    14. {
    15. board[x - 1][y - 1] = '*';
    16. break;//选择成功后就跳出循环
    17. }
    18. else
    19. {
    20. printf("那个位置已经被占了,请重新选择\n");
    21. }
    22. }
    23. else
    24. {
    25. printf("你选的坐标不在棋盘内,请重新选择\n");
    26. }
    27. }
    28. }

    电脑回合的实现:

    1. void computer_move(char board[ROW][COL], int row, int col)
    2. {
    3. printf("电脑回合\n");
    4. while (1)
    5. {
    6. int x = rand() % row;//生成随机数
    7. int y = rand() % col;
    8. if (board[x][y] == ' ')
    9. {
    10. board[x][y] = '#';
    11. break;
    12. }
    13. }
    14. }

    生成随机数时:

    现在就到了最后一步,

    2.3 判断胜负平局的实现

    判断输赢:

    1. void game()//三子棋的实现
    2. {
    3. char ret = 0;//我们通过返回字符判断输赢
    4. char board[ROW][COL];//存放玩家或电脑的落子情况
    5. init_board(board, ROW, COL);//初始化棋盘
    6. print_board(board, ROW, COL);//打印棋盘
    7. while (1)//创建一个循环,直到分出胜负或平局再跳出
    8. {
    9. player_move(board, ROW, COL);//玩家下
    10. print_board(board, ROW, COL);
    11. ret = is_win(board, ROW, COL);
    12. if (ret != 'C')//判断游戏是否继续
    13. {
    14. break;//当ret不等于C时,跳出循环,判断输赢
    15. }
    16. computer_move(board, ROW, COL);//电脑下
    17. print_board(board, ROW, COL);
    18. ret = is_win(board, ROW, COL);
    19. if (ret != 'C')
    20. {
    21. break;
    22. }
    23. }
    24. //判断输赢
    25. if (ret == '*')
    26. {
    27. printf("你赢了\n");
    28. }
    29. else if (ret == '#')
    30. {
    31. printf("电脑获胜\n");
    32. }
    33. else if (ret == 'Q')
    34. {
    35. printf("平局\n");
    36. }
    37. }

    这样,当ret返回 * 是玩家获胜,返回 # 时电脑获胜,都不返回则平局。

    接下来需要实现 is_win 函数:

    (实现函数时,别忘了在头文件中声明哦)

    1. char is_win(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. //判断三行
    5. for (i = 0; i < row; i++)
    6. {
    7. if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    8. {
    9. return board[i][0];
    10. }
    11. }
    12. //判断三列
    13. for (i = 0; i < col; i++)
    14. {
    15. if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    16. {
    17. return board[0][i];
    18. }
    19. }
    20. //判断对角线
    21. if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    22. {
    23. return board[1][1];
    24. }
    25. if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    26. {
    27. return board[1][1];
    28. }
    29. }

    还有平局的情况,可以再分装成一个函数实现:

    1. //平局
    2. if (is_full(board, row, col) == 1)//判断棋盘是否满了
    3. {
    4. return 'Q';
    5. }
    6. return 'C';

    函数 is_full 的实现:

    1. int is_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. {
    11. return 0;
    12. }
    13. }
    14. }
    15. return 1;
    16. }

    现在,三子棋就做完了,我们一起赢一把看看效果:

     学会了吗?

    快去试试吧!

    3. 三子棋源码

    这里是源码:

    1. test.c 文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"//引用自己的头文件
    3. void menu()//打印游戏菜单界面
    4. {
    5. printf("***************************************\n");
    6. printf("***** 开始游戏:1 退出游戏:0 *****\n");
    7. printf("***************************************\n");
    8. }
    9. void game()//三子棋的实现
    10. {
    11. char ret = 0;//我们通过返回字符判断输赢
    12. char board[ROW][COL];//存放玩家或电脑的落子情况
    13. init_board(board, ROW, COL);//初始化棋盘
    14. print_board(board, ROW, COL);//打印棋盘
    15. while (1)//创建一个循环,直到分出胜负或平局再跳出
    16. {
    17. player_move(board, ROW, COL);//玩家下
    18. print_board(board, ROW, COL);
    19. ret = is_win(board, ROW, COL);
    20. if (ret != 'C')//判断游戏是否继续
    21. {
    22. break;//当ret不等于C时,跳出循环,判断输赢
    23. }
    24. computer_move(board, ROW, COL);//电脑下
    25. print_board(board, ROW, COL);
    26. ret = is_win(board, ROW, COL);
    27. if (ret != 'C')
    28. {
    29. break;
    30. }
    31. }
    32. //判断输赢
    33. if (ret == '*')
    34. {
    35. printf("你赢了\n");
    36. }
    37. else if (ret == '#')
    38. {
    39. printf("电脑获胜\n");
    40. }
    41. else if (ret == 'Q')
    42. {
    43. printf("平局\n");
    44. }
    45. }
    46. void test()
    47. {
    48. srand((unsigned int)time(NULL));//通过时间戳生成随机数
    49. int choice = 0;
    50. do //我们使用一个do while循环,如果玩一把三子棋不过瘾,可以再玩一把
    51. {
    52. menu();
    53. printf("请选择:>");
    54. scanf("%d", &choice);//接收玩家输入的值
    55. switch (choice)
    56. {
    57. case 1:
    58. printf("三子棋游戏开始:\n");
    59. game();//我们将游戏的实现分装成一个函数
    60. break;
    61. case 0:
    62. printf("游戏已退出\n");
    63. break;
    64. default:
    65. printf("输入错误,请重新输入\n");
    66. break;
    67. }
    68. } while (choice);
    69. }
    70. int main()//主函数尽量放的东西少一点
    71. {
    72. test();//可以通过创建一个函数实现其他功能
    73. return 0;
    74. }

    2. game.h 文件:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #define ROW 3
    6. #define COL 3
    7. void init_board(char board[ROW][COL], int row, int col);
    8. void print_board(char board[ROW][COL], int row, int col);
    9. void player_move(char board[ROW][COL], int row, int col);
    10. void computer_move(char board[ROW][COL], int row, int col);
    11. char is_win(char board[ROW][COL], int row, int col);

    3. game.c 文件:

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"
    3. void init_board(char board[ROW][COL], int row, int col)
    4. {
    5. int i = 0;
    6. for (i = 0; i < row; i++)
    7. {
    8. int j = 0;
    9. for (j = 0; j < col; j++)
    10. {
    11. board[i][j] = ' ';//将落子位置初始化成空格
    12. }
    13. }
    14. }
    15. void print_board(char board[ROW][COL], int row, int col)
    16. {
    17. int i = 0;
    18. for (i = 0; i < col; i++)
    19. {
    20. printf(" %d ", i + 1);//添加纵坐标
    21. }
    22. printf("\n");
    23. for (i = 0; i < row; i++)
    24. {
    25. int j = 0;
    26. printf("%d", i + 1);//添加横坐标
    27. for (j = 0; j < col; j++)
    28. {
    29. printf(" %c ", board[i][j]);//打印三行,每行三个 %c
    30. if (j < col - 1)//井字棋的棋盘只需要中间两排竖着的分割线
    31. {
    32. printf("|");//打印三行,每行两个‘|’
    33. }
    34. }
    35. printf("\n");
    36. if (i < row - 1)//只需要两行分割线
    37. {
    38. printf(" ");//对齐
    39. for (j = 0; j < col; j++)
    40. {
    41. printf("---");//打印两行,每行三个‘---’
    42. if (j < col - 1)
    43. {
    44. printf("|");//打印两行,每行两个‘|’
    45. }
    46. }
    47. }
    48. printf("\n");
    49. }
    50. }
    51. void player_move(char board[ROW][COL], int row, int col)
    52. {
    53. printf("玩家回合\n");
    54. while (1)
    55. {
    56. printf("请输入要下的坐标:>");
    57. int x = 0;
    58. int y = 0;
    59. scanf("%d %d", &x, &y);
    60. //坐标合法(在棋盘中)
    61. if (x >= 1 && x <= row && y >= 1 && y <= col)
    62. {
    63. if (board[x - 1][y - 1] == ' ')//坐标是空的
    64. {
    65. board[x - 1][y - 1] = '*';
    66. break;//选择成功后就跳出循环
    67. }
    68. else
    69. {
    70. printf("那个位置已经被占了,请重新选择\n");
    71. }
    72. }
    73. else
    74. {
    75. printf("你选的坐标不在棋盘内,请重新选择\n");
    76. }
    77. }
    78. }
    79. void computer_move(char board[ROW][COL], int row, int col)
    80. {
    81. printf("电脑回合\n");
    82. while (1)
    83. {
    84. int x = rand() % row;//生成随机数
    85. int y = rand() % col;
    86. if (board[x][y] == ' ')
    87. {
    88. board[x][y] = '#';
    89. break;
    90. }
    91. }
    92. }
    93. int is_full(char board[ROW][COL], int row, int col)
    94. {
    95. int i = 0;
    96. int j = 0;
    97. for (i = 0; i < row; i++)
    98. {
    99. for (j = 0; j < col; j++)
    100. {
    101. if (board[i][j] == ' ')
    102. {
    103. return 0;
    104. }
    105. }
    106. }
    107. return 1;
    108. }
    109. char is_win(char board[ROW][COL], int row, int col)
    110. {
    111. int i = 0;
    112. //判断三行
    113. for (i = 0; i < row; i++)
    114. {
    115. if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    116. {
    117. return board[i][0];
    118. }
    119. }
    120. //判断三列
    121. for (i = 0; i < col; i++)
    122. {
    123. if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    124. {
    125. return board[0][i];
    126. }
    127. }
    128. //判断对角线
    129. if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    130. {
    131. return board[1][1];
    132. }
    133. if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    134. {
    135. return board[1][1];
    136. }
    137. //平局
    138. if (is_full(board, row, col) == 1)//判断棋盘是否满了
    139. {
    140. return 'Q';
    141. }
    142. return 'C';
    143. }

    写在最后:

    以上就是本篇文章的内容了,感谢你的阅读。

    如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

    如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

    之后我还会输出更多高质量内容,欢迎收看

  • 相关阅读:
    项目版本号大小比较,找出最大版本号
    MySQL 教程:MySQL IN 语句(高级)
    【Python零基础入门篇 · 27】:文件操作
    centos 部署java环境,拷贝jar包并运行
    OpenCV自学笔记十一:形态学操作(一)
    Spring源码解析——Spring事务是怎么通过AOP实现的?
    非关系型数据库(NoSQL)——redis
    docker搭建nginx
    Kotlin 协程 (7/7篇) - 在Android中的使用
    lintcode 553 · 炸弹袭击【中等 数组+bfs+模拟】
  • 原文地址:https://blog.csdn.net/Locky136/article/details/127696187