目录

一、建立源文件与头文件

二、呈现初始化菜单和玩家的选择面板

三、呈现初始化棋盘

四、玩家下棋

五、电脑下棋

六、判断输赢

七、从人工智障变成人工智能

八、代码总结


序言:想必大家都应该玩过三字棋吧,这是我们童年时期都喜欢玩的小游戏,因为对局简单,没事的时候就来玩几局,当我们学习了c语言了,我们怎么来用c语言来实现这个简单的小游戏呢,现在就由我来分享如何用c语言来实现三字棋的实现过程。

一、建立源文件与头文件

由于game函数中需要定义和引用的函数较多,因此需要定义一个.h为后缀的头文件来声明各个函数,还有库函数使用所需的头文件,以及需要定义的常量,game.c文件在该源文件中实现游戏过程中具体的函数,test.c在该源文件里实现三字棋的主体流程。

二、呈现初始化菜单和玩家的选择面板

游戏菜单的打印以及玩家的选择界面都放在main函数中,先搭建一个菜单函数menu(),再搭建一个供玩家选择的函数test(),这里想要实现的是玩家输入为1则开始游戏,输入为0则退出游戏。再将test()与menu()都放在main的主函数中,代码实现如下:

void menu() {      //游戏界面printf("**********菜单********\n");printf("****1->play****0->exit\n");printf("**********************\n");
}
void test() {     int input = 0;do{scanf("%d", &input);if (input == 1)printf("游戏开始\n");switch (input){case 1:game()break;case 0:printf("退出游戏\n:");break;default:printf("输入错误,请重新输入\n:");break;}} while (input);
}
int main() {menu();test();return 0;
}

代码说明:在test()函数当中,我运用了do.....while语句来实现游戏的进入与结束,保证游戏界面至少进入一次,用swich分支来实现如果输入0,游戏结束,输入1,输入其他数字,就会提醒输入错误,请重新输入,游戏开始,游戏内容由game()函数实现游戏逻辑。

三、呈现初始化棋盘

在玩家输入1之后,游戏开始。那么,为了更直观的游戏体验,开始我想让玩家能看到一个空棋盘,并且之后能在这个空棋盘上落子。那么,这该如何实现呢?

请看下面一段初始化代码;

void init_board(char arr[ROW][COL],int row,int col) {int i = 0;int j = 0;for (i = 0; i < row; i++) {for (j = 0; j < col; j++) {arr[i][j] = ' ';}}

说明:通过两层for循环对棋盘的内容进行初始化,初始化是打印“ ”。

下面这一段代码就是来进行打印棋盘的操作了:

void display_board(char board[ROW][COL], int row, int col) {int i = 0;for (i = 0; i < row; i++){//数据printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);//---|---|---if(i<row-1)printf("---|---|---\n");}
}

注意:这两段代码都是写在game.c文件中,在game.h文件中要记得声明,在game()函数中进行调用。

不过大家有没有发现一个问题;我写的这一个代码,它只能打印三乘三方格,如果把game.h文件中的#define ROW 3 改为#define ROW 10,#define COL 3 改为#define COL 10,结果就会发生改变:

所以还需要将代码调整一下,如果改为10,就可以打印10乘10方格。代码如下

void display_board(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){//数据int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");//---|---|---if (i < row - 1){for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}

代码说明:(这张图我借鉴的): 

这样修改的话就可以随意改几乘几的方格了,不过今天我要写的是3乘3方格,这样棋盘界面也完成了,最终打印结果如图:

四、玩家下棋

初始化阶段我们已经把二维数组board中所有元素赋成了空格,因此,想要实现玩家落子,只需要让玩家输入一个坐标(几行几列),改变这个坐标上的元素为新的元素(这个元素便可视为是一个棋子,我们定义这个棋子为X,便于随后的判断输赢),再用一次display_board()函数即可呈现出带有玩家落子的棋盘。

void playermove(char board[ROW][COL], int row, int col) {int x = 0, y = 0;printf("玩家下棋:\n");ax:while (1){printf("请玩家输入落子的行和列:\n");scanf("%d-%d", &x, &y);//1.坐标的合法性//2.坐标是否被占用if ((x >= 1 && x <= row) && (y >= 1 && y <= col)) {if (board[x - 1][y - 1] == ' ') {board[x - 1][y - 1] ='X';break;}else {printf("该坐标已经被占用,请重新输入:");goto ax;}}else {printf("该坐标非法,请重新输入:");goto ax;}}
}

五、电脑下棋

电脑落子和玩家落子同理,都是通过变换数组元素来实现的(这里我们定义电脑的子为字符Y,便于随后的判断输赢), 但玩家可以输入一个坐标,而电脑该如何实现呢?这里我们可以发现,如果电脑能生成一个随机坐标,并且这个坐标在棋盘范围以内,就可以很好的实现了。这里我们要用到c语言中生成随机数的知识。

我们要运用到生成随机数的代码,这是生成随机数的代码:

//注意 game.h文件中要包含生成随机数的头文件。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{srand((unsigned int)time(NULL));int rad=rand();}

如果我们想要获得区间(a,b)的随机数,可以通过rad=rand()%(b-a+1)+a来实现。

下面就是电脑下棋的代码:

void computer_move(char board[ROW][COL], int row, int col)
{printf("电脑下棋:\n");//随机数0~32726//%3-->随机数0~2while (1){int x = rand() % row;int y = rand() % col;if (board[x][y] == ' '){board[x][y] = 'Y';break;}}
}

运行结果:

六、判断输赢

再判断输赢之前,我还要先写一个是否溢出的代码;

 int is_full(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){if (board[i][j] ==' '){return 0;}}}

判断输赢也是游戏的重要的机制,下面我来写一个判断游戏输赢的代码:

char is_win(char board[ROW][COL], int row, int col)
{int i = 0;//判断三行不为空,是‘x’或‘y’,返回哪个值就谁赢。for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}
//判断三列for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}
//判断对角线if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//判断平局if (is_full(board, row, col) == 1){return 'Q';}//继续return 'C';
}

1、三字棋的规则就是当一行或一列,或一对角字符一样,则获胜者就出现了,当电脑和玩家下完棋后,分别判断三行三列或对脚线内容是否相等,如果有出现相等的就返回其中的字符内容

2、返回代表值‘X’为玩家获胜,返回‘Y’则电脑获胜,返回‘Q’表示平局,返回‘C'表示未分胜负,也未平局。

最终在game()里面写一个打印结果

if (ret == 'X'){printf("玩家赢\n");}else if (ret == 'Y'){printf("电脑赢\n");}else if (ret == 'Q'){printf("平局\n");}display_board(board, ROW, COL);}

最终测试结果为:

七、从人工智障变成人工智能

大家可能对我这个标题有疑问?

不是已经做完了吗,为什么还要再做,这其实是对电脑下棋的一个优化,之前电脑下棋是用随机数来进行的,根本不会有“人”的思维进行对抗,现在我要把电脑落子从“人工智障”升级为能够防守玩家的落子,增强游戏的可玩性,具体代码如下:

我将电脑写的代码进行了修改,也在网上借鉴了一些大佬的代码:

void computer_move(char arr[ROW][COL], int row, int col, int* n, int* m)//防守向
{printf("电脑走\n");int x = 0;int y = 0;if ((*m) < 2)//玩家下子小于2时,随机下{while (1){srand((unsigned int)time(NULL));x = rand() % row;y = rand() % col;if (arr[x][y] == ' '){arr[x][y] = 'Y';(*n)++;return;}}}else//防守玩家下棋路线{int i = 0;for (i = 0; i < row; i++)//横二{if (arr[i][0] == arr[i][1] && arr[i][1] == 'X' && arr[i][2] == ' '){arr[i][2] = 'Y';(*n)++;return;}if (arr[i][0] == arr[i][2] && arr[i][2] == 'X' && arr[i][1] == ' '){arr[i][1] = 'Y';(*n)++;return;}if (arr[i][1] == arr[i][2] && arr[i][2] == 'X' && arr[i][0] == ' '){arr[i][0] = 'Y';(*n)++;return;}}for (i = 0; i < col; i++)//竖二{if (arr[0][i] == arr[1][i] && arr[1][i] == 'X' && arr[2][i] == ' '){arr[2][i] = 'Y';(*n)++;return;}if (arr[0][i] == arr[2][i] && arr[2][i] == 'X' && arr[1][i] == ' '){arr[1][i] = 'Y';(*n)++;return;}if (arr[1][i] == arr[2][i] && arr[2][i] == 'X' && arr[0][i] == ' '){arr[0][i] = 'Y';(*n)++;return;}}if (arr[0][0] == arr[1][1] && arr[1][1] == 'X' && arr[2][2] == ' ')//斜二{arr[2][2] = 'Y';(*n)++;return;}else if (arr[0][0] == arr[2][2] && arr[2][2] == 'X' && arr[1][1] == ' '){arr[1][1] = 'Y';(*n)++;return;}else if (arr[2][2] == arr[1][1] && arr[1][1] == 'X' && arr[0][0] == ' '){arr[0][0] = 'Y';(*n)++;return;}if (arr[2][0] == arr[1][1] && arr[1][1] == 'X' && arr[0][2] == ' ')//反斜二{arr[0][2] = 'Y';(*n)++;return;}else if (arr[2][0] == arr[0][2] && arr[2][2] == 'X' && arr[1][1] == ' '){arr[1][1] = 'Y';(*n)++;return;}else if (arr[0][2] == arr[1][1] && arr[1][1] == 'X' && arr[2][0] == ' '){arr[2][0] = 'Y';(*n)++;return;}while (1)//如果都没有,随机下{x = rand() % row;y = rand() % col;if (arr[x][y] == ' '){arr[x][y] = 'Y';(*n)++;return;}}}//
}

原理:我的思路是这样进行的,当玩家下子小于2时,电脑还是跟之前一样随机落子,一旦玩家下子大于等于2时,电脑开始进行防守模式,寻找玩家有无再下一颗子的取胜序列,如有就堵住玩家,没有就继续下,那我们就开始来和电脑开始对战吧!

结果如下:(电脑是不是开始防守你的棋子了)

八、代码总结

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu() {printf("**********菜单********\n");printf("****1->play****0->exit\n");printf("**********************\n");
}
void game()
{char ret = 0;int n = 0;int m= 0;//数据的存储需要一个3*3的二维数组char board[ROW][COL] = {" "};init_board(board, ROW, COL);display_board(board, ROW, COL);while (1) {playermove(board, ROW, COL);display_board(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C')break;computer_move(board, ROW, COL,&n,&m);display_board(board, ROW, COL);ret = is_win(board, ROW, COL);if (ret != 'C')break;}if (ret == 'X'){printf("玩家赢\n");}else if (ret == 'Y'){printf("电脑赢\n");}else if (ret == 'Q'){printf("平局\n");}display_board(board, ROW, COL);}//玩家赢 - 'X'
//电脑赢 - 'Y'
//平局了 - 'Q'
//游戏继续 - 'C'void test() {int input = 0;do{scanf("%d", &input);if (input == 1)printf("游戏开始\n");switch (input){case 1:game();break;case 0:printf("退出游戏\n:");break;default:printf("输入错误,请重新输入\n:");break;}} while (input);
}
int main() {menu();test();return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void init_board(char board[ROW][COL],int row,int col) {int i = 0;int j = 0;for (i = 0; i < row; i++) {for (j = 0; j < col; j++) {board[i][j] = ' ';}}
}
//void display_board(char board[ROW][COL], int row, int col) {
//  int i = 0;
//      for (i = 0; i < row; i++)
//      {
//          //数据
//          printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//          //---|---|---
//          if(i<row-1)
//              printf("---|---|---\n");
//      }
//}
void display_board(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){//数据int j = 0;for (j = 0; j < col; j++){printf(" %c ", board[i][j]);if (j < col - 1)printf("|");}printf("\n");//---|---|---if (i < row - 1){//printf("---|---|---\n");for (j = 0; j < col; j++){printf("---");if (j < col - 1)printf("|");}printf("\n");}}
}
void playermove(char board[ROW][COL], int row, int col) {int x = 0, y = 0;printf("玩家下棋:\n");ax:while (1){printf("请玩家输入落子的行和列:\n");scanf("%d-%d", &x, &y);//1.坐标的合法性//2.坐标是否被占用if ((x >= 1 && x <= row) && (y >= 1 && y <= col)) {if (board[x - 1][y - 1] == ' ') {board[x - 1][y - 1] ='X';break;}else {printf("该坐标已经被占用,请重新输入:");goto ax;}}else {printf("该坐标非法,请重新输入:");goto ax;}}
}
//void computer_move(char board[ROW][COL], int row, int col)
//{
//  printf("电脑下棋:\n");
//  //0~32726
//  //%3-->0~2
//  /*while (1)
//  {*/
//      srand((unsigned int)time(NULL));
//      int x = rand() % row;
//      int y = rand() % col;
//      if (board[x][y] == ' ')
//      {
//          board[x][y] = 'Y';
//      }
//  /*}*/
//}
void computer_move(char arr[ROW][COL], int row, int col, int* n, int* m)//防守向
{printf("电脑走\n");int x = 0;int y = 0;if ((*m) < 2)//玩家下子小于2时,随机下{while (1){srand((unsigned int)time(NULL));x = rand() % row;y = rand() % col;if (arr[x][y] == ' '){arr[x][y] = 'Y';(*n)++;return;}}}else//防守玩家下棋路线{int i = 0;for (i = 0; i < row; i++)//横二{if (arr[i][0] == arr[i][1] && arr[i][1] == 'X' && arr[i][2] == ' '){arr[i][2] = 'Y';(*n)++;return;}if (arr[i][0] == arr[i][2] && arr[i][2] == 'X' && arr[i][1] == ' '){arr[i][1] = 'Y';(*n)++;return;}if (arr[i][1] == arr[i][2] && arr[i][2] == 'X' && arr[i][0] == ' '){arr[i][0] = 'Y';(*n)++;return;}}for (i = 0; i < col; i++)//竖二{if (arr[0][i] == arr[1][i] && arr[1][i] == 'X' && arr[2][i] == ' '){arr[2][i] = 'Y';(*n)++;return;}if (arr[0][i] == arr[2][i] && arr[2][i] == 'X' && arr[1][i] == ' '){arr[1][i] = 'Y';(*n)++;return;}if (arr[1][i] == arr[2][i] && arr[2][i] == 'X' && arr[0][i] == ' '){arr[0][i] = 'Y';(*n)++;return;}}if (arr[0][0] == arr[1][1] && arr[1][1] == 'X' && arr[2][2] == ' ')//斜二{arr[2][2] = 'Y';(*n)++;return;}else if (arr[0][0] == arr[2][2] && arr[2][2] == 'X' && arr[1][1] == ' '){arr[1][1] = 'Y';(*n)++;return;}else if (arr[2][2] == arr[1][1] && arr[1][1] == 'X' && arr[0][0] == ' '){arr[0][0] = 'Y';(*n)++;return;}if (arr[2][0] == arr[1][1] && arr[1][1] == 'X' && arr[0][2] == ' ')//反斜二{arr[0][2] = 'Y';(*n)++;return;}else if (arr[2][0] == arr[0][2] && arr[2][2] == 'X' && arr[1][1] == ' '){arr[1][1] = 'Y';(*n)++;return;}else if (arr[0][2] == arr[1][1] && arr[1][1] == 'X' && arr[2][0] == ' '){arr[2][0] = 'Y';(*n)++;return;}while (1)//如果都没有,随机下{x = rand() % row;y = rand() % col;if (arr[x][y] == ' '){arr[x][y] = 'Y';(*n)++;return;}}}//
}//输入棋盘的返回值,如果为空,则返回0,不为空,则返回1。int is_full(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){if (board[i][j] ==' '){return 0;}}}return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{int i = 0;for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' '){return board[i][0];}}for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' '){return board[0][i];}}if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//判断平局if (is_full(board, row, col) == 1){return 'Q';}//继续return 'C';
}

game.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void init_board(char board[ROW][COL], int row, int col);//初始化棋盘
void display_board(char board[ROW][COL], int row, int col);//打印棋盘
void playermove(char board[ROW][COL], int row, int col);//玩家下棋
void computer_move(char board[ROW][COL], int row);///电脑下棋
static int is_full(char board[ROW][COL], int row, int col);//判断棋盘是否已满
char is_win(char board[ROW][COL], int row, int col);//判断输赢

后面的有点多,大家理解思路就行,后面的不需要仔细阅读,经过十几个小时的学习才写出这篇博客,也是为了巩固知识,加深对知识的理解。

博客就到这里就结束了,希望可以帮助大家,希望大家可以点个赞噢!

C语言人机大战之三字棋博弈相关推荐

  1. C语言人机大战之决战三子棋之巅

    文章目录 C语言人机大战之三子棋 一.游戏规则 二.游戏实现 (1)游戏界面 (2)游戏ing 初始化棋盘 打印棋盘 玩家落子 电脑落子 判断输赢 棋盘满否 三.代码总结 (1)game.h (2)t ...

  2. 四子棋 java_java智能四子棋人机大战游戏设计(附项目,以及原创PSD,设计文档)...

    本项目是使用java技术+自创"假设下子"算法开发的人机大战四子棋游戏客户端. 具体项目,以及原创PSD,设计文档,在文件末尾的百度云连接. 一. 小组说明: 组名:CST 组长: ...

  3. 五指棋人机大战之ai篇

    话说之前把ui篇说了,接下来就是整个游戏的核心部分了. 废话不多说,完成AI部分总共有几个难点 1. 计算机如何落子 2. 判断胜负 在阐述代码之前,先上流程图.备注一下:玩家先手(黑子) 电脑白子 ...

  4. 哥们哥们,人机大战晓得吧玩家对战晓得吧,简易三子棋,呕心沥血500行代码手把手带你制作第一个小游戏,可以保存收藏以后接着看哟,最后有源码哦

    目录 前言 一.游戏想要有意思,函数不可少,整活的函数 二.三子棋的游戏界面 三.三子棋的功能步骤分析      1.菜单     2.三子棋实现的总体框架     3.棋盘创建     4.棋盘初始 ...

  5. 【c语言】 我使用c语言基础做了一个老少皆宜的”国民小游戏(三字棋)“

    C语言实现三字棋小游戏 前言 游戏效果 游戏实现 前言 本三字棋小游戏是依靠二维数组为核心来实现的,可以更加好理解掌握c语言数组的概念知识,依靠做小游戏项目,把学到了知识在输出出来加已巩固,最后有源代 ...

  6. c语言初学者 三字棋

    首先我们要顺理下任务 1.我们要先写个界面游戏的输入端 2.打印棋盘 3.人机的自动输入,玩家的输入 4.判断输赢 5.一键三连. 我比较懒就用这拼音来表达各个函数 1界面  jiemai来表达函数 ...

  7. [c语言]三字棋小游戏及大学开始学习c语言感悟

    我是一名普普通通大一计算机新生,一直想用c语言写一个简单的小游戏.看了比特鹏教学视频后,终于决定来写写这个代码,话不多说,马上开始 (11.21)更新 发现新bug,修改后重新上传代码 bug为平局时 ...

  8. 【C语言实现五子棋、三子棋人机对战,包含电脑人工智能对战(可攻可守)】(非标题党)

    C语言--五子棋.井字棋人机对"战" 针对C语言学习过程中的五子棋.三子棋实现记录 五子棋人机对战 C语言--五子棋.井字棋人机对"战" 实际效果 一.头文件( ...

  9. C语言三字棋优化,实现ROW*COL个格子,ZI字棋

    三字棋优化 ,主要是针对棋局大小及方式的优化,可实现ROW*COL个格子,ZI字棋.也即棋盘方式,与下法都可以变化. 其中game.c中分别写了纯三字棋>优化>ROW*COL三字棋> ...

最新文章

  1. Java最全的思维导图汇总!速度收藏!
  2. 当有键盘时如何在开始编辑时使UITextField向上移动?
  3. asp.net内置对象
  4. [基础题]4、设计一个家政服务规范: 洗衣服, 扫地, 买菜, 做饭
  5. 浅谈Spring事务隔离级别
  6. LAMP下http跳转到 https
  7. 转: SVN和Git的一些用法总结
  8. word 产生很多temp 不显示_Word与PPT互转,怎样才能30秒内搞定?教程来了
  9. win10计算机无限弹网页,Win10老弹出窗口怎么回事?Win10持续闪现神秘窗口现象的解决办法...
  10. 央行数字货币离我们还有多远?
  11. 每天进步一点之灵魂拷问14之网络连接2
  12. 人性的弱点 --卡耐基
  13. [数值微分]数值微分的误差分析
  14. 解决SSH连接不上的问题
  15. SNP注释神器——VEP(生信)
  16. 了解CSS盒模型、页面布局在UI设计中的作用
  17. 高级程序员和低级程序员
  18. 解决win10安装virtualBox没有host-only设置问题
  19. Dreamweaver CS5支持Html5
  20. 抖音群控教你怎么做好短视频

热门文章

  1. 莫欺少年穷,看看这10个顶级大公司最初的模样
  2. 微商php源码,Thinkphp内核微商新零售平台源码
  3. Java中this关键字和super关键字用法
  4. 碱基序列的最长公共子串(Finding a Shared Motif)
  5. dos命令实现循环求和
  6. 单例模式和多例模式详解
  7. MOOC浙大数据结构课后题记录——PTA数据结构题目集(全)
  8. win11系统用户账户控制总是弹出来?
  9. 【基础算法训练】—— 字符串
  10. Jacobi 和 Gauß-Seidel 迭代方法