当前位置:   article > 正文

[ C语言 ] 用C语言实现小游戏 ---- 三子棋 代码 + 解析_三子棋c语言代码

三子棋c语言代码





前言

本篇文章记录了用C语言实现三子棋小游戏,主要目的是对之前C语言知识学习的巩固,联系各个知识,以及怎么样实际使用各个知识。





一、三子棋的游戏规则

玩家将会看到一个3X3的网格棋盘,默认玩家先下棋,电脑后下棋。

规定:先连成一条直线(3个棋子)的玩家获胜,行,列,对角线均可。若在棋盘下满时仍未分出胜负,则为平局





二、使用到的头文件

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>





定义3*3的棋盘

  1. #define ROW 3
  2. #define COL 3

初始化棋盘:

void InitBoard(char board[ROW][COL],int row,int col);

打印棋盘:

void DisplayBoard(char board[ROW][COL], int row, int col);

玩家下棋:

void player_move(char board[ROW][COL], int row, int col); 

电脑下棋:

void computer_move(char board[ROW][COL], int row, int col);

判断输赢:

  1. //玩家赢 - '*'
  2. //电脑赢 - '#'
  3. //平局 - 'Q'
  4. //继续 - 'C'
  5. char is_win(char board[ROW][COL],int row,int col);

三、游戏的测试

主函数:

  1. int main() {
  2. test();//调用test测试函数
  3. return 0;
  4. }

test函数:

  1. void test() {
  2. int input = 0;
  3. srand((unsigned int)time(NULL));
  4. do
  5. {
  6. menu();
  7. printf("请选择:>");
  8. scanf("%d",&input);
  9. switch (input) {
  10. case 1:
  11. game();
  12. break;
  13. case 0:
  14. printf("退出游戏\n");
  15. break;
  16. default:
  17. printf("选择错误\n");
  18. break;
  19. }
  20. } while (input);
  21. }

解析test函数主要构成:

i>菜单menu()函数:

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

实现效果:

 ii>switch case 语句:实现了玩家通过不同输入选择实现不同的功能。

效果显示:

iii>game()函数:当玩家输入1时,跳入到游戏的实现代码之中。

  1. void game() {
  2. // 数据存储,玩家下棋'*',电脑下棋是'#'
  3. char board[ROW][COL] = {0};//数组的内容 应该是全部空格
  4. InitBoard(board,ROW,COL);// 初始化棋盘
  5. // 打印棋盘
  6. DisplayBoard(board,ROW,COL);
  7. //下棋
  8. char ret = 0;
  9. while (1) {
  10. player_move(board, ROW, COL);
  11. DisplayBoard(board, ROW, COL);
  12. ret = is_win(board, ROW, COL);
  13. if (ret != 'C') {
  14. break;
  15. }
  16. computer_move(board, ROW, COL);
  17. DisplayBoard(board, ROW, COL);
  18. ret = is_win(board, ROW, COL);
  19. if (ret != 'C') {
  20. break;
  21. }
  22. }
  23. if (ret == '*') {
  24. printf("玩家赢\n");
  25. }
  26. else if (ret == '#') {
  27. printf("电脑赢\n");
  28. }
  29. else{
  30. printf("平局\n");
  31. }
  32. }

game()函数里面包括了:打印棋盘函数,初始化棋盘函数,玩家下棋函数,电脑下棋函数,判断输赢函数的调用,已经规定输赢的条件,具体每个函数的实现代码和问题如下。

注:最后有game()函数的逻辑顺序。

四、游戏的实现

游戏的实现逻辑:

(一)打印棋盘

我们首先实现对棋盘的打印:

我们在头文件中规定了 3行3列

  1. #define ROW 3
  2. #define COL 3

自定义函数DisplayBoard实现对棋盘的打印:

预期实现的棋盘模样:

 我们发现里面包含了数据和分割行,实现代码:

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

(二)初始化棋盘函数

定义InitBoard()函数,主要实现代码如下:

  1. void InitBoard(char board[ROW][COL], int row, int col)
  2. {
  3. int i = 0;
  4. int j = 0;
  5. for (i = 0; i < row; i++) { //3
  6. for (j = 0; j < col; j++) { // 3
  7. board[i][j] = ' ';
  8. }
  9. }
  10. }

初始化棋盘全为空格

(三)玩家下棋

自定义函数 player_move 实现,代码如下:

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

这里面包含了很多小问题和解决方案:

1:输入的坐标不在棋盘的范围内怎么办?

答:使用if else 选择语句,如果输入的坐标合法,则输入成功,如果输入的坐标不合法则会提醒“坐标非法,请重新输入!”字样。

if (x >= 1 && x <= row && y >= 1 && y <= col)

2:输入的坐标在棋盘上已被占用怎么办?

这个问题我们需要转化成这个问题解决:

i>怎么判断输入坐标被占用?

答:我们通过对选择语句if else 对改坐标进行判断,由于我们在初始化棋盘时,初始化棋盘全部为空格,如果输入坐标所对应的格子是空格,则说明未被占用,如果输入坐标所对应的格子不是空格,则说明该格子已经被占用。

if (board[x - 1][y - 1] == ' ')

ii>如何正确输入棋子?

如果输入坐标所对应的格子是空格,则可以成功输入,如果不是空格,则会else提醒玩家“该坐标被占用,请重新输入!”字样。利用while循环语句可再次输入正确的未被占用的坐标。

(四)电脑下棋

自定义函数 computer_move 实现,代码如下:

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

这里也包含了几个小问题和解决方案:

1:这里电脑的输入是随机输入,如何实现?

答:这里我们并非是真的随机值,只是利用了时间戳,由于时间在每时每刻的改变,所以在不同的时间,经过处理后的时间我们也无法知道,可当做随机值使用。这里调用了time函数,实现代码如下:

  1. #include <time.h>
  2. srand((unsigned int)time(NULL));

由于在这里强制转化为正整数。

2:如何控制电脑随机输入的值合法?

答:这个问题的意思是,如果不对这个随机值进行处理,那么这个值很可能超出棋盘,所以要对这个值进行控制,由于棋盘规定3行3列,数组下标由0开始,所以随机值只要在0~2之内即可。所以我们对这个随机值进行取模(取余数)处理即可解决此问题:

  1. x = rand() % ROW; // 0 ~ 2
  2. y = rand() % COL; // 0 ~ 2

为了区分玩家和电脑的棋子不同,在此规定

玩家使用 ' * ' , 电脑使用 ' # '

因为这里电脑输入坐标均为随机值,所以不具有判断的能力,读者可以思考一种优化算法,写出一种最快赢下比赛的算法。而不至于出现可能都已经一行出现2个棋子了,随机值可能再下到别处的情况(哈哈 人工“智障”)。

 (五)判断输赢

实现代码:

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

游戏规定,首先完成一行或者一列或者对角线的玩家获胜,在此我们只需要进行三行,三列,对角线的判断以及平局的判断,游戏继续判断。具体是玩家赢还是电脑赢,我们在测试函数test中有规定,不同的玩家对应不同的字符,在此规定:

三行的判断:

  1. for (i = 0; i < row; i++) {
  2. if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
  3. return board[i][1];
  4. }

三列的判断:

  1. for (i = 0; i < col; i++) {
  2. if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
  3. return board[1][i];
  4. }

两条对角线的判断:

  1. //第一条对角线
  2. if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ') {
  3. return board[1][1];
  4. }
  5. //第二条对角线
  6. if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
  7. {
  8. return board[1][1];
  9. }

平局的判断:

游戏规定,当棋盘下满时,还未分出胜负时,则为平局。

因此首先我们思考如何判断棋盘是否下满?

答:在这里我们通过返回值的数字来判断是否下满

自定义函数 is_full函数,具体代码:

  1. int is_full(char board[ROW][COL], int row, int col) {
  2. int i = 0;
  3. int j = 0;
  4. for (i = 0; i < row; i++) {
  5. for (j = 0; j < col; j++) {
  6. if (board[i][j] == ' ') {
  7. return 0;
  8. }
  9. }
  10. }
  11. return 1;
  12. }

代码逻辑:我们通过返回值来判断棋盘是否下满,

如果未被下满,则返回值是0(return 0 )

如果下满我们将返回1(return 1)

小问题:我们如何判断是否下满?

我们遍历数组的过程中,如果发现还有空格存在,说明棋盘还没有被下满,我们立刻返回0,否则说明棋盘没有空格存在,说明已经下满,返回1.

所以我们就可以通过返回值判断平局,代码如下:

  1. if (1 == is_full(board, row, col)) {
  2. return 'Q';
  3. }

如果返回值 == 1 说明 棋盘被下满 我们返回字符  ' Q ' (我们刚刚已经规定Q为平局)

、game()函数

我们再次将game()函数调出进行详解:

  1. void game() {
  2. // 数据存储,玩家下棋'*',电脑下棋是'#'
  3. char board[ROW][COL] = {0};//数组的内容 应该是全部空格
  4. InitBoard(board,ROW,COL);// 初始化棋盘
  5. // 打印棋盘
  6. DisplayBoard(board,ROW,COL);
  7. //下棋
  8. char ret = 0;
  9. while (1) {
  10. player_move(board, ROW, COL);
  11. DisplayBoard(board, ROW, COL);
  12. ret = is_win(board, ROW, COL);
  13. if (ret != 'C') {
  14. break;
  15. }
  16. computer_move(board, ROW, COL);
  17. DisplayBoard(board, ROW, COL);
  18. ret = is_win(board, ROW, COL);
  19. if (ret != 'C') {
  20. break;
  21. }
  22. }
  23. if (ret == '*') {
  24. printf("玩家赢\n");
  25. }
  26. else if (ret == '#') {
  27. printf("电脑赢\n");
  28. }
  29. else{
  30. printf("平局\n");
  31. }
  32. }

根据代码发现主要逻辑顺序:

 这是game()函数内部的主要逻辑顺序,每一步所对应的函数调用和判断也均在图中显示。

、演示

完整代码: 完整代码我放在我的Gitee仓库内,链接如下:

https://gitee.com/Yaulixingyu/c-language/tree/master/三子棋/三子棋

游戏演示:

 

总结

以上就是我对三棋子小游戏的实现,有兴趣的小伙伴可以对代码进行优化,可实现五子棋等,也可以对电脑下棋记性优化,使电脑不再人工“智障”。

哈哈哈~由于文章较长,感谢各位小伙伴的观看,由于本人的技术水平有待提高,如果遇到错误也请及时指正。如果各位小伙伴觉得不错的话,可以点赞关注一波~多谢多谢

下期预告:扫雷  小游戏

链接:[ C语言 ] 扫雷 ------> 用C语言实现game2_小白又菜的博客-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/233794?site
推荐阅读
相关标签
  

闽ICP备14008679号