当前位置:网站首页>C语言实现三子棋
C语言实现三子棋
2022-07-29 04:38:00 【zeroGho】
目录
一、规则简介
三子棋是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。

二、游戏逻辑
首先,我们需要一个游戏菜单,通过玩家的输入进行不同的操作,这里就可以使用 switch 语句实现;根据玩家的不同选择,有两种走向,选择 1、玩游戏 0、退出 以及选择错误时需要给玩家提示。
我们还希望这个游戏可以一直玩下去,直到玩家主动选择退出,因此这里采用一个循环语句,由于刚刚说了玩家需要输入选择,这里循环的控制可以直接根据玩家选择进行设置,这里我采用的是 do while 循环,大家也可以尝试使用 while 循环。
程序文件主要有三个,分别是:主函数文件test.c;包含游戏主要功能的源文件game.c;用来引用各种头文件,声明函数的头文件game.h 。
int main()
{
int input = 0;
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏退出\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}三、菜单打印
菜单打印就是简单的输出语句,代码如下:
void menu()
{
printf("**********************\n");
printf("***** 1.play *******\n");
printf("***** 0.exit *******\n");
printf("**********************\n");
}
四、棋盘的创建和初始化
菜单打印完后,就进入到我们的游戏主题 game() 函数,首先是棋盘创建及初始化,我们需要打印一个3x3 的棋盘,首先在头文件中定义全局变量,棋盘的行列,这样方便后续更改。
#include <stdio.h>
#define ROW 3 //行
#define COL 3 //列
void game()
{
char ret = 0;
//生成棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
displayboard(board, ROW, COL);
}初始化棋盘通过函数 initboard() 实现,由于初始化对象是棋盘,因此函数的参数需要:棋盘本身,棋盘行列,代码如下:
void initboard(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] = ' ';
}
}
}在没有下棋时,将棋盘每个位置设为空格
五、棋盘打印
棋盘创建及初始化之后,需要打印出来让玩家看到
棋盘有以下特点:三个棋子行,两个分割行,两个分隔列
// | |
//---|---|---
// | |
//---|---|---
// | |
通过函数 displayboard() 实现,函数参数同样是 棋盘本身及棋盘行列:
void displayboard(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++)
{
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");
}
}这里在打印分割行时设置条件为 i<row-1,j<col-1 因为在棋盘的边缘不需要分割行和分隔列。
打印结果如下:

六、下棋
棋盘生成后就可以开下棋了,由于需要循环下棋,这里也采用循环语句控制:
void game()
{
char ret = 0;
//生成棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
displayboard(board, ROW, COL);
//下棋
while (1)
{
//玩家下
player(board, ROW, COL);
//打印
displayboard(board, ROW, COL);
//判断输赢
ret = win(board, ROW, COL);
if (ret != 'c')
break;
//电脑下
com(board, ROW, COL);
displayboard(board, ROW, COL);
//判断
ret = win(board, ROW, COL);
if (ret != 'c')
break;
}下棋又分为玩家下棋以及电脑下棋,并且每次下棋后,希望能够打印出来让玩家看见。此外,每次下棋,无论玩家还是电脑,都有可能使得游戏结束,可能是玩家赢也可能电脑赢,也可能平局,因此每次下棋后还需要判断游戏的输赢
6.1 玩家下棋
玩家下棋时,通过玩家输入棋盘坐标确定下棋的位置.
注意:玩家输入的坐标是从1-3,但棋盘生成是通过数组完成,因此在代码中坐标是从 0-2
在玩家下棋时,要判断该位置是否已经有棋子,或者是否在棋盘范围内,如果不符合上述条件要求玩家重下,因此这里也需要循环
玩家下棋的代码:
void player(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("该坐标被占用,重新输入\n");
}
else
{
printf("输入错误,重新输入\n");
}
}
}6.2 电脑下棋
电脑下棋要比玩家更简单一些,这里我们通过生成随机数让电脑在棋盘上随机下子
随机数生成需要用到 rand() 和 srand() 函数,同时通过时间戳来设置随机数的起点,因此在头文件 game.h 中需要加上相应的头文件
#include <stdio.h>
#include <stdlib.h> //rand srand
#include <time.h> //time
#define ROW 3 //行
#define COL 3 //列
由于 srand 只使用一次,所有我们在 game 函数循环的外面进行 srand
void game()
{
char ret = 0;
//生成棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
displayboard(board, ROW, COL);
srand((unsigned int)time(NULL)); //随机数起点设置
while (1)
{
//玩家下
player(board, ROW, COL);
//打印
displayboard(board, ROW, COL);
//判断输赢
ret = win(board, ROW, COL);
if (ret != 'c')
break;
//电脑下
com(board, ROW, COL);
displayboard(board, ROW, COL);
//判断
ret = win(board, ROW, COL);
if (ret != 'c')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}通过随机数对行列分别取余,控制随机数范围在 0-2
电脑下棋代码如下:
void com(char board[ROW][COL], int row, int col)
{
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}6.3 输赢判断
获胜共有三种方式,横向,竖向,对角组成一线,以及在棋盘下满时若无人获胜则平局
这里通过不同的返回值来确定输赢及平局
返回 * :玩家获胜
返回 #:电脑获胜
返回 c:无人获胜,且棋盘未满,继续游戏
返回 q:棋盘满了,平局
代码如下:
char 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 < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][1];
}
}
//对角
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (full(board, ROW, COL) == 1)
return 'q';
return 'c';
}这里在判断棋盘是否满时,又另外封装了一个函数,通过返回值判读棋盘是否满了
返回1:满了
返回0:未满
int full(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++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}由于输赢判断函数有返回值,所以在 game 函数中需要一个变量接受该返回值,最后通过判断该变量的值确定输赢:
void game()
{
char ret = 0;//用于接收输赢判断函数返回值的变量
//生成棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
displayboard(board, ROW, COL);
srand((unsigned int)time(NULL));//随机数起点设置
while (1)
{
//玩家下
player(board, ROW, COL);
//打印
displayboard(board, ROW, COL);
//判断输赢
ret = win(board, ROW, COL);
if (ret != 'c')
break;
//电脑下
com(board, ROW, COL);
displayboard(board, ROW, COL);
//判断
ret = win(board, ROW, COL);
if (ret != 'c')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}七、总结
至此,三子棋的基本功能都完成了,我们来看下各个文件中的代码:
首先是头文件 game.h :
# define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void menu();
void game();
void initboard(char board[ROW][COL], int row, int col);
void displayboard(char board[ROW][COL], int row, int col);
void player(char board[ROW][COL], int row, int col);
char win(char board[ROW][COL], int row, int col);
void com(char board[ROW][COL], int row, int col);游戏文件 game.c:
# define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("**********************\n");
printf("***** 1.play *******\n");
printf("***** 0.exit *******\n");
printf("**********************\n");
}
// | |
//---|---|---
// | |
//---|---|---
// | |
void initboard(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 displayboard(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++)
{
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");
}
}
void player(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("该坐标被占用,重新输入\n");
}
else
{
printf("输入错误,重新输入\n");
}
}
}
int full(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++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
char 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 < row; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][1];
}
}
//对角
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (full(board, ROW, COL) == 1)
return 'q';
return 'c';
}
void com(char board[ROW][COL], int row, int col)
{
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
void game()
{
char ret = 0;
//生成棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
displayboard(board, ROW, COL);
srand((unsigned int)time(NULL));
while (1)
{
//玩家下
player(board, ROW, COL);
//打印
displayboard(board, ROW, COL);
//判断输赢
ret = win(board, ROW, COL);
if (ret != 'c')
break;
//电脑下
com(board, ROW, COL);
displayboard(board, ROW, COL);
//判断
ret = win(board, ROW, COL);
if (ret != 'c')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}主函数文件 test.c:
# define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
int main()
{
int input = 0;
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏退出\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}现在让我们来试试游戏吧:

边栏推荐
- Use of torch.optim optimizer in pytorch
- 异常处理:pyemd或PyEMD找不到
- Oracle 插入数据
- Whether the modification of import and export values by ES6 and commonjs affects the original module
- Classes and objects (III)
- Several simple and difficult OJ problems with sequential force deduction
- oracle 更新和删除数据
- MySQL - clustered index and secondary index
- Record the Niua packaging deployment project
- 钉钉对话框文子转换成图片 不能复制粘贴到文档上
猜你喜欢

WebRTC实现简单音视频通话功能

Install the gym corresponding to mujoco in the spinning up tutorial, and the error mjpro150 is reported

谷歌浏览器 打开网页出现 out of memory

Several simple and difficult OJ problems with sequential force deduction

Deploy Jenkins using containers

C language force buckle question 61 of the rotating list. Double ended queue and construction of circular linked list

Redux quick start

The third ACM program design competition of Wuhan University of Engineering

央企建筑企业数字化转型核心特征是什么?

使用容器部署Jenkins
随机推荐
oracle 更新和删除数据
Detailed comparison of break and continue functions
常见的限流方式
MySQL - 深入解析MySQL索引数据结构
[c language] PTA 7-51 sum the first n terms of odd part sequence
Log configuration logback
settings.xml
Shell string segmentation
Classes and objects (I)
Down sampling and up sampling
Laya中的A星寻路
mujoco和mujoco_py安装以及解决libXcursor.so.1:NO such dictionary
[express connection to MySQL database]
Review key points and data sorting of information metrology in the second semester of 2022 (teacher zhaorongying of Wuhan University)
Won't you insist on 71 days? List sorting
STL source code analysis (Hou Jie) notes -- Classification and testing of stl containers
Actual combat of flutter - DIO of request encapsulation (II)
On quotation
Makefile(make)常见规则(二)
Don't insist on 66 days. Weight generates random numbers