• 三子棋小游戏(万字详解)可以自定义棋盘大小


    三子棋小游戏(万字详解)可以自定义棋盘大小

    我想对于五子棋,大多数游戏玩家早已经不陌生,毕竟陪伴了大家的同年时光,想想那五个一排的对齐顺序(上下五个一排,对角线五个一排的对齐方式)即充满了愉快,有考验着玩家的机智与实力,忍耐力............

    笔者儿时对于游戏早已向往已久,可惜现在已经过了玩游戏的年龄,不再喜欢上了游戏,而是对于游戏开发.....想要有着浅浅的认知,打算用游戏开发来替代玩游戏的梦想!

    梦想还是要有的,万一实现了呢???

    少年强,则国强,那么少年的智力,就用小小的游戏来测试一下吧!

    话不多说,下面来进入我们的正题:如何实现三子棋小游戏??

    或许刚开始的小白有着一脸的茫然,不知道该怎么去下手!但是对于三子棋,没有多大的难度,只不过就是借用了函数,数组,for循环,while循环,switch...case结构等基础知识,来进行书写出来的简单游戏代码!

    下面请看:笔者带领大家去体验一下三子棋小游戏的书写过程!

    若是读者觉得合适,还请热度给予笔者,让笔者更有动力去书写更多的游戏代码!

    首先:我们需要有着自己的构思:在vs2019,或者vs2022中创建三个文件,分别实现:

    test.c文件进行测试三子棋小游戏!

    game.h文件进行对三子棋小游戏的函数声明!

    game.c文件对三子棋小游戏的实现!

    下面就是进入正文部分!

    要想进行玩游戏,首先,我们需要有一个菜单,来进行对我们是否玩游戏的一个体验部分

    输入1,进行玩游戏,输入0:退出游戏!

    下面请看笔者代码片段:

    1. //打印三子棋的菜单
    2. #include
    3. void menu()
    4. {
    5. printf("**********************************\n");
    6. printf("******** 1.play ***********\n");
    7. printf("******** 0.exit ***********\n");
    8. printf("**********************************\n");
    9. }
    10. void game()
    11. {
    12. printf("三子棋游戏\n");
    13. }
    14. int main()
    15. {
    16. int input = 0;
    17. do
    18. {
    19. menu();
    20. printf("请输入选择:》\n");
    21. scanf_s("%d", &input);
    22. switch(input)
    23. {
    24. case 1:
    25. game();
    26. break;
    27. case 0:
    28. printf("退出游戏\n");
    29. break;
    30. default :
    31. printf("输入错误,请重新选择\n");
    32. break;
    33. }
    34. } while (input);
    35. }

    在这个菜单menu部分,并没有多大的难度,也相信读者一看也就能看明白,只不过就是思维的欠缺!在这里面,实现了多次输入判断,在C语言中,系统默认0为假,非0为真(1和其他非0数是真)。

    在do.....while循环中,用从键盘输入值input的数字大小来判断是否玩游戏,如果是非0,则输入错误,请重新选择,如果是1,则进行三子棋小游戏,如果是0,则退出游戏,符合C语言语法,而且还符合三子棋小游戏的代码!并且还能实现多组输入,直到输入0时,退出游戏!

    在switch.....case:      ;break;结构,实现了对输入的input进行选择判断,从而有着不同的printf输出结果.

    菜单的运转结果如下所示:

    第一步:三子棋小游戏的菜单已经搭建完成,并且是我们想要的,因此我们需要进入第二步:棋盘的搭建

    在搭建棋盘中,我们肯定不能搭建的跟现实中的棋盘一模一样,毕竟.......嗯,实力不允许!

    文章定名为三子棋小游戏,那就以打印3*3棋盘为列,来给大家分析一下棋盘的代码写法

    在上述代码段中,我们大家需要知道:

    1. void game()
    2. {
    3. printf("三子棋游戏\n");
    4. }

    在这个里面不会只有printf("三子棋游戏\n");在里面,毕竟这个是不现实的,因为我们需要借用这个来实现对菜单menu的调试,判断是否合适,是否为我们想要的菜单,下面就需要我们对其进行更改!

    笔者想要的是这种棋盘,看着简短清晰:

     下面请看这种棋盘的创建思路:

     要实现对这种棋盘的实现,并且能将玩家跟电脑的下棋给记录下来,因此,我们需要借助数组,来实现这个功能,但是,创建什么类型的数组呢??是int类型,还是char类型??但是参考上面,发现由‘*’与‘#’组成,因此用char类型的数组比较合适!

    因此我们需要定义一共3*3的数组,定义并初始化数组char board[3][3]={0};但是看一下棋盘的格式,里面都是看不见的内容.......是空格,因此这样给数组进行初始化,就出现了误差!

    因此打印棋盘时候,显得有点难度,但是我们仅仅是对于3*3棋盘而言,对于其他类型的棋盘,我们又应该怎样去定义?

    因此,我们需要用到自定义函数  #define  ,用来自定义函数的大小,

    1. void display_board(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. for (i = 0; i < row; i++)
    5. {
    6. //数据
    7. printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    8. //---|---|---
    9. if(i1)
    10. printf("---|---|---\n");
    11. }
    12. }

    在这段代码里面,ROW为行COL为列,这样一个3*3简单棋盘就给打印出来,大家注意printf函数里面输出的部分,及其for循环的逻辑,这段代码看着没有什么错误地方,但是运转出来的结果却是.....

     但是最后的结果却是出现了一丢丢小小的误差!尴尬,我想读者也能看出来,如此不明显的对齐方式,其实这个没有对齐的差距主要体现在,数组在定义并初始化数组char board[3][3]={0}....出现了问题....

    大是还有一个错误,那就是体现在,仅仅改变行,但是对于列:我们却把这个程序给写死了,根本改变不了列的大小,简单来说就是,不管列输入的值是多少,到最后打印出来的结果都是三列,因为......

    printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);

    在这个代码块中,我们写的代码出现了错误,将列的那几次循环出现了写死的现象,在该代码中是不允许出现的情况!

    下面来看笔者对于错误的分析过程:其实这个原因并不是笔者之前的代码出现错误,而是.....

    我们需要借助一个函数来实现对棋盘的对齐!

    因此:笔者更改后的代码为:

    1. void display_board(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. for (i = 0; i < row; i++)
    5. {
    6. //数据
    7. //printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    8. int j = 0;
    9. for (j = 0; j < col; j++)
    10. {
    11. printf(" %c ", board[i][j]);
    12. }
    13. printf("\n");
    14. //---|---|---
    15. if (i < row - 1)
    16. {
    17. //printf("---|---|---\n");
    18. for (j = 0; j < col; j++)
    19. {
    20. printf("---");
    21. }
    22. printf("\n");
    23. }
    24. }
    25. }

    经过这样过程,运转出来的结果为:

    虽然跟先前的那个乱棋盘相比较显得好看了不少,但是还有一点稍微的瑕疵在里面,:最后一个棋盘,下面出现了多余的部分,这并不是我们想要的,因此,需要借用if语句表判断来用!

    更改后的代码结果为:

    1. void display_board(char board[ROW][COL], int row, int col)
    2. {
    3. int i = 0;
    4. for (i = 0; i < row; i++) //外层决定了我们需要打印多少行
    5. {
    6. //数据
    7. //printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    8. int j = 0;
    9. for (j = 0; j < col; j++) //内层决定了我们每一行需要打印多少次
    10. {
    11. printf(" %c ", board[i][j]);
    12. if (j < col - 1)
    13. printf("|");
    14. }
    15. printf("\n");
    16. //---|---|---
    17. if (i < row - 1)
    18. {
    19. //printf("---|---|---\n");
    20. for (j = 0; j < col; j++)
    21. {
    22. printf("---");
    23. if (j < col - 1)
    24. printf("|");
    25. }
    26. printf("\n");
    27. }
    28. }
    29. }

    其实对比上一个代码段的区别,主要在于if语句里面的内容,if语句主要控制,最后一组里面的内容打印过程

    到此,棋盘已经打印好!观看下图,发现这个才是我们想要的棋盘,符合我们的预期。

    3*3棋盘如图所示:

    5*5棋盘如图所示:

     

     对于棋盘,我们可以通过#define 来实现自我调节大小,通过只改变define后面一处数字的大小,就能实现棋盘的简单打印,因此,方便了许多!

    因此总的来说,棋盘已经打印完成,下面开始进行对下一阶段的分析:

    进入玩游戏的环节:怎样才能更好的玩游戏呢??

    笔者所想的便是:玩家走一步,电脑也跟着走一步,就这样开始玩起来............

    对于玩家下棋,怎样下棋??

    其实对于玩家来说,下棋是下在数组里面!输入的是玩家想要下棋的坐标!在棋盘上打印的是‘‘*’(字符星号)(电脑下棋也一样,只不过是借用了时间戳来实现随机下棋,在棋盘上打印的是‘#’(字符井号))!

    但是对于玩家,需要又一下几点要求:

    1.判断玩家输入的坐标是否合法(主要体现在是否超过棋盘的大小范围)

    判断和解决问题方法:

    用if语句来实现 对输入坐标的大小,与棋盘的大小进行比较

    2.坐标是否被占用,毕竟电脑下棋,玩家下棋,万一放到了一样的坐标里面,将会...............

    判断和解决问题方法:

    对于坐标是否被占用,在这里需要我们进行手动判断,用if语句表判断,只有被输入的坐标位置是‘   ’,空格,我们才能下棋,否则将会出现提示!

    3.借助数组来下棋(二维数组的第一个下标为:[0][0],但是玩家并不一定知道,大部分玩家默认的第一行一列的坐标为:[1][1],因此,我们需要对数组的坐标进行些许调整!)并且玩家输入的坐标大小还不能超过棋盘的每一行每一列,这样才能实现三子棋的正确运行!

    判断和解决问题方法:

    对于下棋输入坐标,我们需要进行,将玩家输入的行  列坐标分别都进行-1(减1)处理,这样就能将玩家输入的坐标转化为数组的坐标,因此便于来实现下棋的落子问题!

    因此笔者进行代码的添加更改以后,总结出下面代码段,来供大家参考借鉴:

    1. void player_move(char board[ROW][COL], int row, int col)
    2. {
    3. int x = 0;
    4. int y = 0;
    5. printf("玩家下棋:>\n");
    6. while (1)
    7. {
    8. printf("请输入要下棋的坐标:>");
    9. scanf("%d %d", &x, &y);
    10. //1.坐标的合法性
    11. //2.坐标是否被占用
    12. if (x >= 1 && x <= row && y >= 1 && y <= col)
    13. {
    14. if (board[x - 1][y - 1] == ' ')
    15. {
    16. board[x - 1][y - 1] = '*';
    17. break;
    18. }
    19. else
    20. {
    21. printf("该坐标被占用,请重新输入\n");
    22. }
    23. }
    24. else
    25. {
    26. printf("坐标非法,重新输入\n");
    27. }
    28. }
    29. }

    在这里面,用了while循环来实现玩家对下棋坐标的多组输入!

    在该段代码,用if语句嵌套if语句,实现多组判断相互交错模式,简洁易懂!

    玩家下棋,输入要下棋的坐标,将输入‘*’(字符星号)

     下面将进行电脑下棋,电脑实现下棋,也是下在了数组里面!也不能实现坐标不合法,被占用现象....

    但是电脑下棋需要进行判断,如果下一步就能赢得话,将会在哪儿下棋,如果下棋赢不了的话,那就得分析别人下棋可能会赢,如果发现别人下棋马上就要赢了,那首先就得堵别人,如果别人赢不了,我有机会赢得话,就得先自己下.............所以电脑要进行一些列的分析,然后才能进行正确的下棋!

    但是要是进行如此去操作,将会将电脑设置的太复杂(阿尔法狗系列),暂时不是笔者想要的程度,笔者仅仅是想实现对电脑能够随机下棋就可以,因此就借助了时间戳:rand 和srand俩个函数,来实现对电脑上面唯一时刻保持变换的东西进行改变,从而实现电脑随机下棋的目的预判!

    电脑随机下棋方法,用时间戳来将电脑在棋盘上哪里空着就在那里下棋!

    下面是笔者进行电脑下棋的逻辑:

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

    在这里面,最为重要的就是while循环里面的代码块!

    下面笔者来分析一下:

    1. while (1)
    2. {
    3. int x = rand() % row;
    4. int y = rand() % col;
    5. if (board[x][y] == ' ')
    6. {
    7. board[x][y] = '#';
    8. break;
    9. }
    10. }

    while(1);1为非0,判断结果即为真,一直可以进行循环,    int x = rand() % row;   int y = rand() % col;    利用时间戳进行:行列坐标的输入,所输入的值一定比行列坐标小,并且还大于等于0;利用取余运算符,实现了对坐标输入是否合法性的判断;在循环中,if语句进行了判断,如果电脑随机生成的坐标为‘  ’空格,则进行输出‘#’(井号),如果不是‘  ’空格,将会再次进行循环,随机生成坐标,然后再次if语句判断.........一直进行下去,直到输入成功!!

     在这里我们可以看出来,玩家跟电脑都已经下棋成功!

     一直到此,棋盘已经下满,并且玩家已经赢了,第一行全部为玩家棋子,所以.......

    下面将进行预判!

    规则:

    每一行,每一列,或者对角线都是一样的,一方将会赢!

    一共四个状态:判断输赢(玩家赢,电脑赢),平局(棋盘满),游戏继续

    设一个函数,来判断棋盘的情况!然后就这样..........

    玩家赢输出‘*’(星号);

    电脑赢输出'#'(井号);

    平局了输出‘Q’;

    游戏继续输出‘C’;

    因此,总的方面已经概况,至于其他详细细节请参考总代码!

    1. //如果棋盘满了,返回1
    2. //不满,返回0
    3. static int is_full(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. if (' ' == board[i][j])
    12. {
    13. return 0;
    14. }
    15. }
    16. }
    17. return 1;
    18. }
    19. char is_win(char board[ROW][COL], int row, int col)
    20. {
    21. int i = 0;
    22. for (i = 0; i < row; i++)
    23. {
    24. if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    25. {
    26. return board[i][0];
    27. }
    28. }
    29. for (i = 0; i < col; i++)
    30. {
    31. if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    32. {
    33. return board[0][i];
    34. }
    35. }
    36. if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    37. {
    38. return board[1][1];
    39. }
    40. if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    41. {
    42. return board[1][1];
    43. }
    44. //判断平局
    45. if (is_full(board, row, col) == 1)
    46. {
    47. return 'Q';
    48. }
    49. //继续
    50. return 'C';
    51. }

    在这里面,实现了对以上情况的具体分析,因版本内容所致,笔者将不再进行过多的讲述,更多详细细节,请联系笔者!

    对于上述截图,我想读者都能看出来,该游戏已经能够成功的实现出来,并且符合我们的要求!

    下面将是玩三子棋小游戏是整个代码,以供读者参考借鉴

    test.c文档内容

    1. #define _CRT_SECURE_NO_WARNINGS 1
    2. #include "game.h"
    3. void menu()
    4. {
    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. //数据的存储需要一个3*3的二维数组
    14. char board[ROW][COL] = { 0 };
    15. init_board(board, ROW, COL);
    16. display_board(board, ROW, COL);
    17. //玩游戏
    18. while (1)
    19. {
    20. player_move(board, ROW, COL);
    21. display_board(board, ROW, COL);
    22. ret = is_win(board, ROW, COL);
    23. if (ret != 'C')
    24. break;
    25. computer_move(board, ROW, COL);
    26. display_board(board, ROW, COL);
    27. ret = is_win(board, ROW, COL);
    28. if (ret != 'C')
    29. break;
    30. }
    31. if (ret == '*')
    32. {
    33. printf("玩家赢\n");
    34. }
    35. else if (ret == '#')
    36. {
    37. printf("电脑赢\n");
    38. }
    39. else if (ret == 'Q')
    40. {
    41. printf("平局\n");
    42. }
    43. display_board(board, ROW, COL);
    44. }
    45. //玩家赢 - '*'
    46. //电脑赢 - '#'
    47. //平局了 - 'Q'
    48. //游戏继续 - 'C'
    49. int main()
    50. {
    51. int input = 0;
    52. srand((unsigned int)time(NULL));
    53. do
    54. {
    55. menu();
    56. printf("请选择:>");
    57. scanf_s("%d", &input);
    58. switch (input)
    59. {
    60. case 1:
    61. game();
    62. break;
    63. case 0:
    64. printf("退出游戏\n");
    65. break;
    66. default:
    67. printf("选择错误,重新选择!\n");
    68. break;
    69. }
    70. } while (input);
    71. return 0;
    72. }

    game.h文档内容

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #define ROW 10 //行 ,可以自定义数值的大小
    6. #define COL 10 //列 ,可以自定义数值的大小
    7. //初始化棋盘
    8. void init_board(char board[ROW][COL], int row, int col);
    9. //打印棋盘
    10. void display_board(char board[ROW][COL], int row, int col);
    11. //玩家下棋
    12. void player_move(char board[ROW][COL], int row, int col);
    13. //电脑下棋
    14. void computer_move(char board[ROW][COL], int row, int col);
    15. //判断游戏状态
    16. char is_win(char board[ROW][COL], int row, int col);

    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. 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. //void display_board(char board[ROW][COL], int row, int col)
    16. //{
    17. // int i = 0;
    18. // for (i = 0; i < row; i++)
    19. // {
    20. // //数据
    21. // printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    22. // //---|---|---
    23. // if(i
    24. // printf("---|---|---\n");
    25. // }
    26. //}
    27. void display_board(char board[ROW][COL], int row, int col)
    28. {
    29. int i = 0;
    30. for (i = 0; i < row; i++)
    31. {
    32. //数据
    33. //printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    34. int j = 0;
    35. for (j = 0; j < col; j++)
    36. {
    37. printf(" %c ", board[i][j]);
    38. if (j < col - 1)
    39. printf("|");
    40. }
    41. printf("\n");
    42. //---|---|---
    43. if (i < row - 1)
    44. {
    45. //printf("---|---|---\n");
    46. for (j = 0; j < col; j++)
    47. {
    48. printf("---");
    49. if (j < col - 1)
    50. printf("|");
    51. }
    52. printf("\n");
    53. }
    54. }
    55. }
    56. void player_move(char board[ROW][COL], int row, int col)
    57. {
    58. int x = 0;
    59. int y = 0;
    60. printf("玩家下棋:>\n");
    61. while (1)
    62. {
    63. printf("请输入要下棋的坐标:>");
    64. scanf_s("%d %d", &x, &y);
    65. //1.坐标的合法性
    66. //2.坐标是否被占用
    67. if (x >= 1 && x <= row && y >= 1 && y <= col)
    68. {
    69. if (board[x - 1][y - 1] == ' ')
    70. {
    71. board[x - 1][y - 1] = '*';
    72. break;
    73. }
    74. else
    75. {
    76. printf("该坐标被占用,请重新输入\n");
    77. }
    78. }
    79. else
    80. {
    81. printf("坐标非法,重新输入\n");
    82. }
    83. }
    84. }
    85. //
    86. //电脑随机下棋
    87. //
    88. void computer_move(char board[ROW][COL], int row, int col)
    89. {
    90. printf("电脑下棋:>\n");
    91. //0~32726
    92. //%3-->0~2
    93. while (1)
    94. {
    95. int x = rand() % row;
    96. int y = rand() % col;
    97. if (board[x][y] == ' ')
    98. {
    99. board[x][y] = '#';
    100. break;
    101. }
    102. }
    103. }
    104. //如果棋盘满了,返回1
    105. //不满,返回0
    106. static int is_full(char board[ROW][COL], int row, int col)
    107. {
    108. int i = 0;
    109. for (i = 0; i < row; i++)
    110. {
    111. int j = 0;
    112. for (j = 0; j < col; j++)
    113. {
    114. if (' ' == board[i][j])
    115. {
    116. return 0;
    117. }
    118. }
    119. }
    120. return 1;
    121. }
    122. char is_win(char board[ROW][COL], int row, int col)
    123. {
    124. int i = 0;
    125. for (i = 0; i < row; i++)
    126. {
    127. if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
    128. {
    129. return board[i][0];
    130. }
    131. }
    132. for (i = 0; i < col; i++)
    133. {
    134. if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
    135. {
    136. return board[0][i];
    137. }
    138. }
    139. if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    140. {
    141. return board[1][1];
    142. }
    143. if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    144. {
    145. return board[1][1];
    146. }
    147. //判断平局
    148. if (is_full(board, row, col) == 1)
    149. {
    150. return 'Q';
    151. }
    152. //继续
    153. return 'C';
    154. }

    在这里笔者用了三个文件,一个头文件game.h  ;两个源文件game.c,test.c来实现该三子棋的代码!

    到此为止,该段已经结束!

  • 相关阅读:
    idea护眼主题推荐
    2023年第三届智能制造与自动化前沿国际会议(CFIMA 2023)
    thinkphp6控制器不存在appcontrollerAdmin问题解析及解决
    Apk_动态调试方案
    DayDayUp:计算机技术与软件专业技术资格证书之《系统集成项目管理工程师》课程讲解之十大知识领域之4核心—项目质量管理
    第十八章:Swing自述
    【漏洞复现-uwsgi-目录穿越】vulfocus/uwsgi-cve_2018_7490
    java 分布式游戏服务器框架,集群游戏服务器框架,游戏服务器网关框架 ioGame 网络游戏服务器框架
    ​构建自定义 AXI4-Stream FIR 滤波器
    跟我学Python图像处理丨傅里叶变换之高通滤波和低通滤波
  • 原文地址:https://blog.csdn.net/weixin_64308540/article/details/126039652