当前位置:   article > 正文

C语言实现三子棋

C语言实现三子棋

通过一段时间的学习,我们已经能够较为熟练地使用分支语句循环语句,创建函数,创建数组,创建随机数等。之前我们做过一个扫雷游戏,今天让我们再尝试创作一个三子棋游戏吧~

一、三子棋游戏的思路

三子棋的游戏规则很简单,游戏界面是一个3*3的棋盘,玩家双方依次向棋盘中放置棋子,我的棋子用‘X’表示,对手的棋子用‘O’表示,我们需要让自己的棋连在一起,同时还要阻拦对方的棋子组成连线,当有三个相同的棋子横向相连,纵向相连,或者交叉相连,那么这个棋子的持有者就获胜了

好了,那么既然我们已经了解了三子棋的游戏思路,那让我们试着分析一下,想要用C语言制作出三子棋的游戏,大体需要分成几个步骤?

1.游戏菜单

创造出一个比较美观的游戏菜单,可以选择开始游戏和退出游戏。

2.三子棋的棋盘

创造出一个3*3的三子棋游戏棋盘

3.双方下棋

玩家输入坐标,向三子棋棋盘中放置棋子

(玩家落子需要输入坐标,电脑落子需要srand函数创造随机数)

4.判定胜负

通过对当前棋盘中棋子的计算,来判定是,或者和棋

二、三子棋游戏的游戏文件

与之前的扫雷游戏一样,还是需要分成头文件game.h源文件game.c源文件test.c三个文件。

他们的作用分别是:

  • game.h:作为头文件,它用来存放创造游戏所需要的各种类型的全局变量,并且也用来实现编写代码使所必需的函数说明
  • game.c: 存放各种实现游戏功能所需要的函数。
  • test.c:作为编译的主程序,存放主函数,编写实现游戏功能的主要思想。

(这里使用三个文件只是为了方便,并且修改代码和改进代码时会更快捷,但其实不使用三个也是可以的)

三、实现游戏的各种函数

1.创建游戏菜单

就像我们平常打一个游戏一样,我们自己做出的三子棋游戏也是需要有选择菜单的。如果没有选择菜单就无法明确如何游戏。

  1. void GameInte()
  2. {
  3. printf("**************************\n");
  4. printf("----- 三 子 棋 游 戏 -----\n");
  5. printf("**************************\n");
  6. printf("******* 1.play *******\n");
  7. printf("******* 0.quit *******\n");
  8. printf("**************************\n");
  9. printf("是否游玩?请输入>:");
  10. }

我们需要将菜单函数GameInte在源文件game.c中进行创建和定义,然后再在头文件game.h中对函数进行声明。就像这个样子:

2.完成棋盘初始化

因为需要创建一个3*3的棋盘,所以我们可以创建一个char型的二维数组,board[ROW][COL],(我们把ROW和COL创建成常量,因为是三子棋直接设置成ROW和COL的值都为3就好,如此一来,如果以后像制作五子棋之类的棋盘就会更加简单。像这样

我们只需要用 -- 和 | 组成一个3*3的框架,然后再把棋子依次放入里面就可以了。而放入棋子之前需要把棋子的char值设定为‘  ’,这样才算是空,往里下入棋子后随之改变在棋盘中对应坐标的符号就好了。

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

这样就能将一个二维数组的所有制都初始化为' '啦。

3.打印棋盘

打印棋盘要注意,不能直接把二维数组的所有值都输出就算成功,因为二维数组的初始化我们把所有值都定义为‘ ’了,所以打印出来是不显示的,我们可以选择用 | 和 -- 等符号进行辅助,来打印出一个美观且成型的棋盘。

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

这样就能打印出一个3*3的棋盘啦,并且能够成功的将所有的元素都放进去。

棋盘样例:

4.玩家下棋

(因为玩家下棋是自动输入,而电脑下棋是随机数输出,所以需要放到两个函数中更加清晰易懂并且容易后期改良)

我们需要定义一个函数,实现玩家能够输入坐标,就能改变棋盘上的格局,比如玩家输入1,1,就能够让棋盘上多一个玩家的棋子。并且我们需要限定输入坐标的位置,不能超过也不能少于这个范围,同时也不能下到已经有棋子的位置。

  1. void PlyaChess(char board[ROW][COL], int row, int col)
  2. {
  3. int a;
  4. int b;
  5. while (1)
  6. {
  7. printf("请输入下棋的坐标:>");
  8. scanf("%d %d", &a, &b);
  9. int m = a - 1;
  10. int n = b - 1;
  11. if(a<=0||a>=row+1||b<=0||b>=col+1)
  12. {
  13. printf("输入错误,请重新输入:>");
  14. continue;
  15. }
  16. else if(board[m][n]!=' ')
  17. {
  18. printf("你是想叠罗汉吗?\n");
  19. printf("请重新输入:>\n");
  20. continue;
  21. }
  22. board[m][n] = 'X';
  23. PrintBoard(board, ROW, COL);
  24. break;
  25. }
  26. }

像这样设定两个分支条件语句就能分别控制,制止两种的发生。

5.电脑下棋

电脑下棋就需要用到我们之前所提到的srand()函数和rand来创造随机数,还是在主函数输入srand((unsigned int)time(NULL))这串代码来使随机数rand的种子随时间变化而变化,让它成为真正的随机数,然后使用rand()%rowrand()%col来创造出两个随机数,让电脑在棋子上下棋,遇到有棋子的地方就goto到上面重新生成随机数。

  1. void ComputerChess(char board[ROW][COL], int row, int col)
  2. {
  3. again:
  4. int m = rand() % row;
  5. int n = rand() % col;
  6. Sleep(1000);
  7. if (board[m][n] == ' ')
  8. {
  9. board[m][n] = 'O';
  10. }
  11. else
  12. {
  13. goto again;
  14. }
  15. PrintBoard(board, ROW, COL);
  16. }

(我们可以利用sleep函数添加一个让电脑思考的时间(只是假思考~),这样能让游戏更加带有真实性和参与的感觉。注:需要添加#include <windows.h>头文件

这就是成功的制作出让电脑下棋的步骤啦。

6.判断赢输与和棋

我们可以通过计算棋盘上的行,列,以及交叉的区域中,是否有相连的三个相同符号来确定这局三子棋的最终结果。而对于行,列的计算其实还是比较简单的,我们只需要用两个for循环的嵌套,因为两个嵌套来表示board数组的话,正好是一排一排定义的,所以我们可以第一次用for(i=0;i<row;i++),先在外层循环里定义两个初始值为0的变量分别作为'X'和'O'的计数器,内层嵌套for(j=0;j<col;j++),然后判定每一行的各个元素是否为'X'或'O',如果是'X'则对应的计数器+1,如果是'O'也同理,如果判定出有一行中都为'X'或'O'则宣布谁获胜,游戏结束。

(将两个计数器放在外层循环的目的是:每次外层循环,i变化时都会进入第二列/行的输出,此时需要重新从0开始记起)

接下来让我们再思考一下如何判定交叉区域的输赢:因为定义的是3*3的棋盘,所以只有[1][1]到[3][3]坐标和[1][3]到[3][1]这两种情况,我们仍然可以用for循环来解决。

思路有了,敲代码吧~

判断行获胜:

  1. int WinChess(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. int Asum = 0;
  8. int Bsum = 0;
  9. for (j = 0; j < col; j++)
  10. {
  11. if (board[i][j] == 'X')
  12. {
  13. ++Asum;
  14. if (Asum == 3)
  15. return 1;
  16. }
  17. else if(board[i][j] == 'O')
  18. {
  19. ++Bsum;
  20. if (Bsum == 3)
  21. return 2;
  22. }
  23. }
  24. }

判断列获胜:

  1. for (i = 0; i < row; i++)//判断列获胜
  2. {
  3. int Asum = 0;
  4. int Bsum = 0;
  5. for (j = 0; j < col; j++)
  6. {
  7. if (board[j][i] == 'X')
  8. {
  9. ++Asum;
  10. if (Asum == 3)
  11. return 1;
  12. }
  13. else if (board[j][i] == 'O')
  14. {
  15. ++Bsum;
  16. if (Bsum == 3)
  17. return 2;
  18. }
  19. }
  20. }

判断交叉获胜:

  1. int Asum = 0;
  2. int Bsum = 0;
  3. for (i = 0; i < row; i++)//判断交叉获胜
  4. {
  5. if ((board[i][i] == 'X') || (board[i][row - 1 - i] == 'X'))
  6. {
  7. ++Asum;
  8. if (Asum == 3)
  9. return 1;
  10. }
  11. else if ((board[i][i] == 'O') || (board[i][row - 1 - i] == 'O'))
  12. {
  13. ++Bsum;
  14. if (Bsum == 3)
  15. return 2;
  16. }
  17. }

那么接下来我们要来判断和棋的时候是什么情况,因为判断输赢已经使这个函数变得比较复杂了,所以我们再定义一个新的函数Full,用来判断棋盘是否已经满了,如果满了则返回1,没满则返回0。

  1. int Full(char chessBoard[ROW][COL])
  2. {
  3. for (int row = 0; row < ROW; row++)
  4. {
  5. for (int col = 0; col < COL; col++)
  6. {
  7. if (chessBoard[row][col] == ' ')
  8. {
  9. return 0;
  10. }
  11. }
  12. }
  13. return 1;
  14. }

我们需要利用Full函数的返回值确定是否为满,并且在判断获胜或者失败之前,如果函数已为满,则先判断是否为和棋,这样能够防止程序因为判断不出获胜或失败则return0导致程序继续进行(而此时电脑已经没有地方可以下棋了,会导致游戏终止)

好啦~这次我们已经把所有的准备工作都完成啦,让我们来看一下主函数main是什么样子的吧~

  1. #include"game.h"
  2. int game()
  3. {
  4. //棋盘初始化
  5. BoardCreate(board, ROW, COL);
  6. //打印棋盘
  7. PrintBoard(board, ROW, COL);
  8. while (1)
  9. {
  10. //玩家下棋
  11. PlyaChess(board, ROW, COL);
  12. if (Full(board) == 1)
  13. {
  14. if ((WinChess(board, ROW, COL)) == 1)
  15. {
  16. printf("恭喜玩家获胜!!!");
  17. break;
  18. }
  19. if ((WinChess(board, ROW, COL)) == 0)
  20. {
  21. printf("你和人机势均力敌,你是人机嘛");
  22. break;
  23. }
  24. }
  25. //电脑下棋
  26. ComputerChess(board, ROW, COL);
  27. if ((WinChess(board, ROW, COL)) == 1)
  28. {
  29. printf("恭喜玩家获胜!!!");
  30. break;
  31. }
  32. if ((WinChess(board, ROW, COL)) == 2)
  33. {
  34. printf("你被人机打败了!");
  35. break;
  36. }
  37. }
  38. }
  39. int main()
  40. {
  41. srand((unsigned int)time(NULL));
  42. int a;
  43. do
  44. {
  45. //创造菜单
  46. GameInte();
  47. scanf("%d", &a);
  48. if (a == 1)
  49. {
  50. game();
  51. break;
  52. }
  53. else if (a == 0)
  54. {
  55. printf("退出游戏");
  56. break;
  57. }
  58. else
  59. {
  60. printf("输入错误,请重新输入:\n");
  61. }
  62. } while (a);
  63. }

注意,此时我们在主函数中在判断胜利或失败之前加入的,判断是否为和棋的代码中,又加入了判断玩家是否胜利,因为可能玩家最后下的这一枚棋正好导致了棋子填满并且玩家获胜。加入这段判断就不会导致明明在最后一刻棋子满的时候胜利了,却被说是和棋了。

好了,这次已经解决了所有的函数了,让我们运行一下代码看看也没有什么问题~

行相连胜利:

列相连胜利:

交叉相连胜利:

和棋:

落子最后一枚获胜:

嘿嘿,游戏运行完整无误呢,给大家分享一下完整代码吧~

四、游戏完整代码

1.game.h
  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include <time.h>
  6. #include <windows.h>
  7. #define ROW 3
  8. #define COL 3
  9. char board[ROW][COL];
  10. //创造菜单
  11. void GameInte();
  12. //棋盘初始化
  13. void BoardCreate(char board[ROW][COL], int row, int col);
  14. //打印棋盘
  15. void PrintBoard(char board[ROW][COL], int row, int col);
  16. //玩家下棋
  17. void PlyaChess(char board[ROW][COL], int row, int col);
  18. //电脑下棋
  19. void ComputerChess(char board[ROW][COL],int row, int col);
  20. //判断棋盘是否已满
  21. int Full(char chessBoard[ROW][COL]);
  22. //判断赢输与和棋
  23. int WinChess(char board[ROW][COL], int row, int col);
2.game.c
  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "game.h"
  3. void GameInte()
  4. {
  5. printf("**************************\n");
  6. printf("----- 三 子 棋 游 戏 -----\n");
  7. printf("**************************\n");
  8. printf("******* 1.play *******\n");
  9. printf("******* 0.quit *******\n");
  10. printf("**************************\n");
  11. printf("是否游玩?请输入>:");
  12. }
  13. char BoardCreate(char board[ROW][COL], int row, int col)
  14. {
  15. int i = 0;
  16. int j = 0;
  17. for (i = 0; i < row; i++)
  18. {
  19. for (j = 0; j < col; j++)
  20. {
  21. board[i][j] = ' ';
  22. }
  23. }
  24. }
  25. void PrintBoard(char board[ROW][COL], int row, int col)
  26. {
  27. int i = 0;
  28. int j = 0;
  29. printf(" ----+---+----\n");
  30. for (i = 0; i < row; i++)
  31. {
  32. printf(" | %c | %c | %c | \n", board[i][0], board[i][1], board[i][2]);
  33. printf(" ----+---+----\n");
  34. }
  35. }
  36. void PlyaChess(char board[ROW][COL], int row, int col)
  37. {
  38. int a;
  39. int b;
  40. while (1)
  41. {
  42. printf("请输入下棋的坐标:>");
  43. scanf("%d %d", &a, &b);
  44. int m = a - 1;
  45. int n = b - 1;
  46. if(a<=0||a>=row+1||b<=0||b>=col+1)
  47. {
  48. printf("输入错误,请重新输入:>");
  49. continue;
  50. }
  51. else if(board[m][n]!=' ')
  52. {
  53. printf("你是想叠罗汉吗?\n");
  54. printf("请重新输入:>\n");
  55. continue;
  56. }
  57. board[m][n] = 'X';
  58. PrintBoard(board, ROW, COL);
  59. break;
  60. }
  61. }
  62. int Full(char chessBoard[ROW][COL])
  63. {
  64. for (int row = 0; row < ROW; row++)
  65. {
  66. for (int col = 0; col < COL; col++)
  67. {
  68. if (chessBoard[row][col] == ' ')
  69. {
  70. return 0;
  71. }
  72. }
  73. }
  74. return 1;
  75. }
  76. void ComputerChess(char board[ROW][COL], int row,int col)
  77. {
  78. again:
  79. int m = rand() % row;
  80. int n = rand() % col;
  81. int i = 0;
  82. int j = 0;
  83. int sum = 0;
  84. Sleep(500);
  85. if (board[m][n] == ' ')
  86. {
  87. board[m][n] = 'O';
  88. }
  89. else
  90. {
  91. goto again;
  92. }
  93. PrintBoard(board, ROW, COL);
  94. }
  95. int WinChess(char board[ROW][COL], int row, int col)
  96. {
  97. int i = 0;
  98. int j = 0;
  99. for (i = 0; i < row; i++)//判断行获胜
  100. {
  101. int Asum = 0;
  102. int Bsum = 0;
  103. for (j = 0; j < col; j++)
  104. {
  105. if (board[i][j] == 'X')
  106. {
  107. ++Asum;
  108. if (Asum == 3)
  109. return 1;
  110. }
  111. else if(board[i][j] == 'O')
  112. {
  113. ++Bsum;
  114. if (Bsum == 3)
  115. return 2;
  116. }
  117. }
  118. }
  119. for (i = 0; i < row; i++)//判断列获胜
  120. {
  121. int Asum = 0;
  122. int Bsum = 0;
  123. for (j = 0; j < col; j++)
  124. {
  125. if (board[j][i] == 'X')
  126. {
  127. ++Asum;
  128. if (Asum == 3)
  129. return 1;
  130. }
  131. else if (board[j][i] == 'O')
  132. {
  133. ++Bsum;
  134. if (Bsum == 3)
  135. return 2;
  136. }
  137. }
  138. }
  139. int Asum = 0;
  140. int Bsum = 0;
  141. for (i = 0; i < row; i++)//判断交叉获胜
  142. {
  143. if ((board[i][i] == 'X') || (board[i][row - 1 - i] == 'X'))
  144. {
  145. ++Asum;
  146. if (Asum == 3)
  147. return 1;
  148. }
  149. else if ((board[i][i] == 'O') || (board[i][row - 1 - i] == 'O'))
  150. {
  151. ++Bsum;
  152. if (Bsum == 3)
  153. return 2;
  154. }
  155. }
  156. return 0;
  157. }
3.test.c
  1. #include"game.h"
  2. int game()
  3. {
  4. //棋盘初始化
  5. BoardCreate(board, ROW, COL);
  6. //打印棋盘
  7. PrintBoard(board, ROW, COL);
  8. while (1)
  9. {
  10. //玩家下棋
  11. PlyaChess(board, ROW, COL);
  12. if (Full(board) == 1)
  13. {
  14. if ((WinChess(board, ROW, COL)) == 1)
  15. {
  16. printf("恭喜玩家获胜!!!");
  17. break;
  18. }
  19. if ((WinChess(board, ROW, COL)) == 0)
  20. {
  21. printf("你和人机势均力敌,你是人机嘛");
  22. break;
  23. }
  24. }
  25. //电脑下棋
  26. ComputerChess(board, ROW, COL);
  27. if ((WinChess(board, ROW, COL)) == 1)
  28. {
  29. printf("恭喜玩家获胜!!!");
  30. break;
  31. }
  32. if ((WinChess(board, ROW, COL)) == 2)
  33. {
  34. printf("你被人机打败了!");
  35. break;
  36. }
  37. }
  38. }
  39. int main()
  40. {
  41. srand((unsigned int)time(NULL));
  42. int a;
  43. do
  44. {
  45. //创造菜单
  46. GameInte();
  47. scanf("%d", &a);
  48. if (a == 1)
  49. {
  50. game();
  51. break;
  52. }
  53. else if (a == 0)
  54. {
  55. printf("退出游戏");
  56. break;
  57. }
  58. else
  59. {
  60. printf("输入错误,请重新输入:\n");
  61. }
  62. } while (a);
  63. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号