• C语言实现三子棋小游戏(控制台版本)


    目录

    🍨前言

    🍨多文件模块化

    🍨菜单界面

    🍨主函数大体框架

    🍨信息存储

             🍨注意下面写的函数基本上都是定义放在game.c而声明放在game.h中。

    🍨初始化工作

    🍨棋盘打印

    🍨玩家下棋

    🍨电脑下棋

    🍨状态判断

    🍨JudState函数的具体实现思路

    🍨完整代码

    🍨game.h中

    🍨game.c中

    🍨test.c中

    🍨敬请期待更好的作品吧~


     

    🍨前言

            读者最好具有一定的C语言基础,本文分享一波用C语言简单地做个三子棋小游戏,希望对你有所帮助,由于笔者水平有限,难免会有纰漏,读者各取所需即可。

    给你点赞,加油加油!

     

    🍨多文件模块化

            分三个文件,game.c放入主要的实现游戏逻辑的函数,game.h放入头文件包含、函数声明、宏常量,而test.c作为主文件。

    我们一点一点来实现。

    🍨菜单界面

            首先,进入游戏不都会有菜单界面嘛,虽然我们现在用的还是“黑框框”,但是好歹也是在写游戏嘛,那就写个菜单函数吧。

            目前也就游玩和退出两个选项。

    1. void menu()
    2. {
    3. printf("*********** 三子棋 **********\n");
    4. printf("*****************************\n");
    5. printf("********** 1. play **********\n");
    6. printf("********** 0. exit **********\n");
    7. printf("*****************************\n");
    8. }

    🍨主函数大体框架

    1. int main()
    2. {
    3. int input = 0;
    4. do
    5. {
    6. menu();
    7. printf("请选择:>");
    8. scanf("%d", &input);
    9. switch (input)
    10. {
    11. case 1:
    12. game();
    13. break;
    14. case 0:
    15. printf("退出游戏!\n");
    16. break;
    17. default :
    18. printf("选择有误,请重新选择!\n");
    19. break;
    20. }
    21. } while (input);
    22. return 0;
    23. }

            使用do…while结构,input接收用户的选择,switch实现分支。

            然后具体的游戏逻辑的实现交由函数game实现,实际上是将逻辑细分后封装成若干个函数后再在game函数中组织。

    🍨信息存储

            我们既然要下棋,那需要把每一步棋都存起来,这里考虑用一个二维字符数组chess存储棋盘上棋的信息,需要注意的是,我们最好使用常量宏来定义数组大小,一来能保证数组大小不易写错,二来方便更改,比如实现三子棋后想要实现五子棋,就不需要到处改,只需要在宏处修改即可。

            所以定义宏ROW和COL分别对应行和列大小(放在头文件game.h中)。

    1. #define ROW 3
    2. #define COL 3
    char chess[ROW][COL];//存储棋盘中棋的信息

             🍨注意下面写的函数基本上都是定义放在game.c而声明放在game.h中。

    🍨初始化工作

            棋盘一开始是空的嘛,也就是说初始时chess中的元素要全为空格咯,这样的话就写一个初始化函数InitChess。

    1. void InitChess(char chess[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. chess[i][j] = ' ';
    10. }
    11. }
    12. }

    🍨棋盘打印

            好了,那棋盘呢?棋盘不需要用数组存吗?不了,我们这里直接把棋盘的打印封装成函数DisplayBoard,打印当前棋盘和棋的信息。

            当然,对于棋盘的设计可以有多种思路,这里笔者使用的是这种类型的棋盘:

     代码:

    1. void DisplayBoard(char chess[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. printf(" %c ", chess[i][j]);
    10. if (j < col - 1)
    11. printf("|");
    12. }
    13. printf("\n");
    14. if(i < row - 1)
    15. for (j = 0; j < col; j++)
    16. {
    17. printf("---");
    18. if (j < col - 1)
    19. printf("|");
    20. }
    21. printf("\n");
    22. }
    23. }

            这样设计即使是五子棋甚至N子棋都能适应,只需要修改宏ROW和COL即可,比如:

     

            接下来就要实现下棋的逻辑了,分别是玩家下棋和电脑下棋。

            注意一下,我们这里使用以下这种坐标表示法:

     

    🍨玩家下棋

            封装一个PlayerMove函数,所谓下棋不就是把chess数组中对应下标的值修改成“棋”嘛,我们这里用*表示玩家下的棋,要注意的是数组下标是从0开始的,而玩家一般都是从(1,1)开始下棋的,如图:

             同时还要记得判断一下输入坐标的有效性,包括是否越界以及当前位置是否已经下过棋(判断空格),输入的坐标有误的话重新输入。

    1. void PlayerMove(char chess[ROW][COL], int row, int col)
    2. {
    3. int x = 0;
    4. int y = 0;
    5. while (1)
    6. {
    7. printf("请输入要下棋的坐标位置:>");
    8. scanf("%d %d", &x, &y);
    9. if (x >= 1 && y >= 1 && x <= COL && y <= ROW && chess[y-1][x-1] == ' ')
    10. {
    11. chess[y-1][x-1] = '*';
    12. break;
    13. }
    14. else
    15. {
    16. printf("坐标无效,请重新输入!\n");
    17. }
    18. }
    19. }

    🍨电脑下棋

            封装一个ComputerMove函数,这里暂时让电脑“笨”一点,使用伪随机数,模拟随机找个空位下棋。

            srand()设置种子在主函数main中设置一次即可。随机生成的坐标位置上不一定是空的,加个循环确保能把棋下进去。

    1. void ComputerMove(char chess[ROW][COL], int row, int col)
    2. {
    3. while (1)
    4. {
    5. int x = rand() % (col - 1);
    6. int y = rand() % (row - 1);
    7. if (chess[y][x] == ' ')
    8. {
    9. chess[y][x] = '#';
    10. break;
    11. }
    12. }
    13. }

            到目前为止,game函数里的逻辑如下:

    1. void game()
    2. {
    3. char chess[ROW][COL];//存储棋盘中棋的信息
    4. InitChess(chess, ROW, COL);//初始化棋的信息
    5. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    6. while (1)
    7. {
    8. PlayerMove(chess, ROW, COL);//玩家下棋
    9. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    10. ComputerMove(chess, ROW, COL);//电脑下棋
    11. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    12. }
    13. }

            现在我们已经实现了下棋,接着我们就要来实现状态更新了。

    🍨状态判断

            我们用一个函数来判断当前游戏情况,并根据情况返回不同的值来表示。

            游戏状态主要有这几种:

            玩家赢       *

            电脑赢       #

            平局          Q

            继续游戏   C

            分别用这几个字符来代表当前游戏状态,每次下完棋后都判断一次。

            只要不是返回'C'就说明游戏结束,跳出循环,进一步再来判断是什么具体情况。

    1. void game()
    2. {
    3. char ret = 0;
    4. char chess[ROW][COL];//存储棋盘中棋的信息
    5. InitChess(chess, ROW, COL);//初始化棋的信息
    6. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    7. while (1)
    8. {
    9. PlayerMove(chess, ROW, COL);//玩家下棋
    10. if ((ret = JudState(chess, ROW, COL)) != 'C')
    11. break;
    12. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    13. ComputerMove(chess, ROW, COL);//电脑下棋
    14. if ((ret = JudState(chess, ROW, COL)) != 'C')
    15. break;
    16. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    17. }
    18. if ('*' == ret)
    19. {
    20. printf("玩家赢!\n");
    21. }
    22. else if ('#' == ret)
    23. {
    24. printf("电脑赢!\n");
    25. }
    26. else
    27. {
    28. printf("平局了!\n");
    29. }
    30. DisplayBoard(chess, ROW, COL);
    31. }

    🍨JudState函数的具体实现思路

            先判断是否有人胜出,分为行、列和正反对角线的的判断,只要三个连着相同并且不是空格就说明有人取胜了,为了省事,直接就返回数组元素,免得用if判断。正好前面设计的*代表玩家赢和#代表电脑赢就对应上了。

            要是没人赢的话就判断一下是否平局了,很简单,写一个函数IsFilled判断一下棋盘满了没有,满了还没人取胜就是平局了,而如果没满的话说明游戏还要继续。

    1. int IsFilled(char chess[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. int j = 0;
    5. int flag = 1;
    6. for (i = 0; i < row; i++)
    7. {
    8. for (j = 0; j < col; j++)
    9. {
    10. if (chess[i][j] == ' ')
    11. flag = 0;
    12. }
    13. }
    14. return flag;
    15. }
    16. char JudState(char chess[ROW][COL], int row, int col)
    17. {
    18. int i = 0;
    19. int j = 0;
    20. //是否有人胜出
    21. //行判断
    22. for (i = 0; i < row; i++)
    23. {
    24. if (chess[i][0] == chess[i][1] && chess[i][1] == chess[i][2] && chess[i][0] != ' ')
    25. {
    26. return chess[i][0];
    27. }
    28. }
    29. //列判断
    30. for (j = 0; j < col; j++)
    31. {
    32. if (chess[0][j] == chess[1][j] && chess[1][j] == chess[2][j] && chess[0][j] != ' ')
    33. {
    34. return chess[0][j];
    35. }
    36. }
    37. //对角线判断
    38. if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[1][1] != ' ' )
    39. {
    40. return chess[1][1];
    41. }
    42. if(chess[0][2] == chess[1][1] && chess[2][0] == chess[1][1] && chess[1][1] != ' ')
    43. {
    44. return chess[1][1];
    45. }
    46. //是平局还是继续
    47. if (IsFilled(chess, ROW, COL))
    48. {
    49. return 'Q';
    50. }
    51. else
    52. {
    53. return 'C';
    54. }
    55. }

    🍨完整代码

    🍨game.h中

    1. #include<stdio.h>
    2. #include<stdlib.h>
    3. #include<time.h>
    4. #define ROW 3
    5. #define COL 3
    6. void InitChess(char chess[ROW][COL], int row, int col);
    7. void DisplayBoard(char chess[ROW][COL], int row, int col);
    8. void PlayerMove(char chess[ROW][COL], int row, int col);
    9. void ComputerMove(char chess[ROW][COL], int row, int col);
    10. char JudState(char chess[ROW][COL], int row, int col);

    🍨game.c中

    1. #include"game.h"
    2. void InitChess(char chess[ROW][COL], int row, int col)
    3. {
    4. int i = 0;
    5. int j = 0;
    6. for (i = 0; i < row; i++)
    7. {
    8. for (j = 0; j < col; j++)
    9. {
    10. chess[i][j] = ' ';
    11. }
    12. }
    13. }
    14. void DisplayBoard(char chess[ROW][COL], int row, int col)
    15. {
    16. int i = 0;
    17. int j = 0;
    18. for (i = 0; i < row; i++)
    19. {
    20. for (j = 0; j < col; j++)
    21. {
    22. printf(" %c ", chess[i][j]);
    23. if (j < col - 1)
    24. printf("|");
    25. }
    26. printf("\n");
    27. if(i < row - 1)
    28. for (j = 0; j < col; j++)
    29. {
    30. printf("---");
    31. if (j < col - 1)
    32. printf("|");
    33. }
    34. printf("\n");
    35. }
    36. }
    37. void PlayerMove(char chess[ROW][COL], int row, int col)
    38. {
    39. int x = 0;
    40. int y = 0;
    41. while (1)
    42. {
    43. printf("请输入要下棋的坐标位置:>");
    44. scanf("%d %d", &x, &y);
    45. if (x >= 1 && y >= 1 && x <= COL && y <= ROW && chess[y-1][x-1] == ' ')
    46. {
    47. chess[y-1][x-1] = '*';
    48. break;
    49. }
    50. else
    51. {
    52. printf("坐标无效,请重新输入!\n");
    53. }
    54. }
    55. }
    56. void ComputerMove(char chess[ROW][COL], int row, int col)
    57. {
    58. while (1)
    59. {
    60. int x = rand() % (col - 1);
    61. int y = rand() % (row - 1);
    62. if (chess[y][x] == ' ')
    63. {
    64. chess[y][x] = '#';
    65. break;
    66. }
    67. }
    68. }
    69. int IsFilled(char chess[ROW][COL], int row, int col)
    70. {
    71. int i = 0;
    72. int j = 0;
    73. int flag = 1;
    74. for (i = 0; i < row; i++)
    75. {
    76. for (j = 0; j < col; j++)
    77. {
    78. if (chess[i][j] == ' ')
    79. flag = 0;
    80. }
    81. }
    82. return flag;
    83. }
    84. char JudState(char chess[ROW][COL], int row, int col)
    85. {
    86. int i = 0;
    87. int j = 0;
    88. //是否有人胜出
    89. //行判断
    90. for (i = 0; i < row; i++)
    91. {
    92. if (chess[i][0] == chess[i][1] && chess[i][1] == chess[i][2] && chess[i][0] != ' ')
    93. {
    94. return chess[i][0];
    95. }
    96. }
    97. //列判断
    98. for (j = 0; j < col; j++)
    99. {
    100. if (chess[0][j] == chess[1][j] && chess[1][j] == chess[2][j] && chess[0][j] != ' ')
    101. {
    102. return chess[0][j];
    103. }
    104. }
    105. //对角线判断
    106. if (chess[0][0] == chess[1][1] && chess[1][1] == chess[2][2] && chess[1][1] != ' ' )
    107. {
    108. return chess[1][1];
    109. }
    110. if(chess[0][2] == chess[1][1] && chess[2][0] == chess[1][1] && chess[1][1] != ' ')
    111. {
    112. return chess[1][1];
    113. }
    114. //是平局还是继续
    115. if (IsFilled(chess, ROW, COL))
    116. {
    117. return 'Q';
    118. }
    119. else
    120. {
    121. return 'C';
    122. }
    123. }

    🍨test.c中

    1. #include"game.h"
    2. void menu()
    3. {
    4. printf("*********** 三子棋 ***********\n");
    5. printf("******************************\n");
    6. printf("********** 1. play ***********\n");
    7. printf("********** 0. exit ***********\n");
    8. printf("******************************\n");
    9. }
    10. void game()
    11. {
    12. char ret = 0;
    13. char chess[ROW][COL];//存储棋盘中棋的信息
    14. InitChess(chess, ROW, COL);//初始化棋的信息
    15. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    16. while (1)
    17. {
    18. PlayerMove(chess, ROW, COL);//玩家下棋
    19. if ((ret = JudState(chess, ROW, COL)) != 'C')
    20. break;
    21. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    22. ComputerMove(chess, ROW, COL);//电脑下棋
    23. if ((ret = JudState(chess, ROW, COL)) != 'C')
    24. break;
    25. DisplayBoard(chess, ROW, COL);//打印棋盘和棋的信息
    26. }
    27. if ('*' == ret)
    28. {
    29. printf("玩家赢!\n");
    30. }
    31. else if ('#' == ret)
    32. {
    33. printf("电脑赢!\n");
    34. }
    35. else
    36. {
    37. printf("平局了!\n");
    38. }
    39. DisplayBoard(chess, ROW, COL);
    40. }
    41. int main()
    42. {
    43. int input = 0;
    44. srand((unsigned int)time(NULL));//设置随机种子
    45. do
    46. {
    47. menu();
    48. printf("请选择:>");
    49. scanf("%d", &input);
    50. switch (input)
    51. {
    52. case 1:
    53. game();
    54. break;
    55. case 0:
    56. printf("退出游戏!\n");
    57. break;
    58. default :
    59. printf("选择有误,请重新选择!\n");
    60. break;
    61. }
    62. } while (input);
    63. return 0;
    64. }


    🍨敬请期待更好的作品吧~

    感谢观看,阁下何不成人之美,关注收藏点赞走一波~

     

     

  • 相关阅读:
    JDBC原生代码
    解析javascript中的for in和for of
    ruby、Python 以及 Swift 语言关于 “Finally” 实现的趣谈
    PHP和JAVA AES加解密问题
    二叉树知识点
    软件设计师案例分析题答案汇总!(4)
    vscode 注释插件koroFileHeader
    诊断用抗原抗体——博迈伦
    【数据分享】2023年我国省市县三级的科技型中小企业数量(Excel/Shp格式)
    华清远见(上海中心)22071
  • 原文地址:https://blog.csdn.net/weixin_61561736/article/details/125490666