当前位置:网站首页>C语言实现三子棋游戏(详解)
C语言实现三子棋游戏(详解)
2022-07-29 03:51:00 【yin_尹】
文章目录
一.三子棋游戏简介
三子棋相信大家应该都玩过,在这里还是简单介绍一下吧!
是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。只要将自己的三个棋子走成一条线,就获胜了
二.游戏实现流程叙述
打印菜单,提示玩家进行选择,在这里,我们设置的是:
选择1,玩游戏
选择0,退出游戏
选择其他数字,提示输入错误,让用户重新输入打印棋盘
玩家下棋
电脑下棋
判断输赢
三.C语言代码实现
1.整体框架简述及代码展示
最终实现游戏的完整代码,我们放在三个文件中,方便对我们的代码进行管理。
这三个文件分别是:
(1)test.c
用于对游戏逻辑的测试
(2)game.h
游戏实现相关的函数声明,符号声明,头文件的包含
(3)game.c
游戏实现相关函数的实现
然后我们在这里把三个文件里的全部代码先展示给大家参考,然后给大家详细解释:
(1)test.c
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("****** 1. play *******\n");
printf("****** 0. exit *******\n");
printf("**********************************\n");
}
void play_game()
{
char ret = '0';
char board[ROW][COL] = {
0 };
init_board(board, ROW, COL);//初始化数组
print_board(board, ROW, COL);//打印棋盘
while (1)
{
player_move(board, ROW, COL);//玩家下棋
print_board(board, ROW, COL);//打印棋盘
//判断输赢
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
computer_move(board, ROW, COL);//电脑下棋
print_board(board, ROW, COL);//打印棋盘
//判断输赢
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("你赢了\n");
else if (ret == '#')
printf("电脑赢\n");
else if (ret == 'Q')
printf("平局\n");
}
int main()
{
srand((unsigned int)time(NULL));//设置随机数生成器
int elect = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &elect);
switch (elect)
{
case 1:
play_game();
break;
case 0:
printf("退出游戏!!!\n");
break;
default:
printf("选择错误,请重新选择!!!\n");
break;
}
} while (elect);
return 0;
}
(2)game.h
#define _CRT_SECURE_NO_WARNINGS
#define ROW 3 //ROW——行
#define COL 3 //COL——列
#include <stdio.h>
#include <stdlib.h>//srand需要的头文件
#include <time.h>//time函数需要的头文件
//函数声明
void init_board(char board[ROW][COL], int row, int col);//初始化数组
void print_board(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);//电脑下棋
char is_win(char board[ROW][COL], int row, int col);//判断输赢
(3)game.c
#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 print_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");
}
}
}
//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
printf("请输入要下棋的坐标:");
scanf("%d %d", &x, &y);
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");
}
}
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:\n");
while (1)
{
int x = rand() % row;//rand函数产生的随机数范围比较大我们给他%上3
int y = rand() % col;//范围正好就是0---2
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//如果棋盘满了,返回1,不满返回0;
static 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';
}
2.游戏整体逻辑的实现测试
我们先在test.c文件对三子棋游戏的整体流程进行一个实现,测试一下逻辑是否正确:
#include <stdio.h>
void menu()
{
printf("**********************************\n");
printf("****** 1. play *******\n");
printf("****** 0. exit *******\n");
printf("**********************************\n");
}
void play_game()
{
printf("玩游戏\n");
}
int main()
{
int elect = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &elect);
switch (elect)
{
case 1:
play_game();
break;
case 0:
printf("退出游戏!!!\n");
break;
default:
printf("选择错误,请重新选择!!!\n");
break;
}
} while (elect);
return 0;
}
在这里游戏实现的函数我们先不具体实现,用一句话代替,因为现在只是先测试一下逻辑:

看一下结果:
逻辑正确,接下来分步进行各功能实现。
3.游戏具体过程实现
(1)打印棋盘
我们先来看一下棋盘长什么样:
分析一下,我们是不是可以用一个二维数组来模拟棋盘,每个元素初始化为空格‘ ’,但是我们看到,每个棋盘之间有分隔线,所以我们还得打印一下分隔线。
看一下最终我们代码打印的棋盘:
一般棋盘的大小时3X3的,但是,如果我们有一天觉得3X3的棋盘太小,玩着不过瘾,想改变一下棋盘大小,怎么办呢,是不是的把所有的3都一个个改成5呢,为了方便改棋盘大小,我们干脆在头文件game.h中用#define定义一个标识符常量,这样,以后修改棋盘大小就方便了。
在头文件game.h中:
#define ROW 3 //ROW——行
#define COL 3 //COL——列
当然我们要想在 test.c 或 game.c 中使用的话,需要包含一下改头文件,但是注意,包含我们自己定义的头文件,需要使用 ” “而不是 < >:
今后想修改棋盘大小,直接把这两个数字修改即可。
既然我们要用一个二维数组,首先我们要定义一个3X3的二维数组然后作为参数传过去:
实现初始化数组函数init_board():
接下来我们就来实现一下打印棋盘的函数 print_board():

看下效果:
我们使用多文件管理,记得把函数声明放在game.h中
函数print_board(),init_board()实现放在game.c中。
(2)设计函数实现玩家下棋
首先我们规定一下吧,玩家的棋子用” * “表示,电脑的棋子用” # “表示。
那怎么让玩家下棋呢,我们让玩家输入一个坐标,然后在这个坐标上放一颗棋子。
如果用坐标的话,我们不得不考虑几个问题了:
1. 玩家输入的坐标是否越界了?
2. 玩家输出了坐标是否已经被使用了?
3. 对于玩家来说,他可能不知道数组的下标是从0开始的,所以玩家输入(1,1),我们需要帮助他放到数组下标为(0,0)的位置上去。
解决方法:
当坐标,越界或已经被占用时,让用户重新输入;
对用户输入的坐标(x,y),把两个数都减1就行了
实现函数:
当然,也不要忘了再game.h中声明一下。
看效果:
好了,玩家下棋的任务就完成了。
(3)设计函数实现电脑下棋
怎么让电脑下棋呢?
我们可以使用rand函数生成两个随机数,表示电脑要下棋的坐标,如果坐标合适,就在该位置放一个” # “.
注意使用rand函数生成随机数之前需要调用srand设置一个随机数生成器,关于rand函数的详细用法大家可以下去了解一下。
设计函数:
看下效果吧:
好了,电脑下棋的函数就完成了。
(4)设计函数判断输赢
要判断输赢的话,我们可以这样规定一下,如果判断输赢的函数 is——win
返回 “ * ”,则玩家赢,
返回“ # ”,电脑赢,
返回“ C ”,游戏继续;
返回“ Q ”,平局。
//判断输赢
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';
}
在这里又用到一个函数来判断棋盘是否满了:
//如果棋盘满了,返回1,不满返回0;
static 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;
}
到这里,所有的函数就实现完了,我们来玩一把:
当然这个代码还是有很多可以改进的地方,大家有兴趣可以自己尝试一下!!!
如果有写的不好的地方,欢迎指正!!!
边栏推荐
- 数据挖掘——关联分析例题代码实现(下)
- sql
- nacos注册中心
- What you see and think in Microsoft
- [原理] 横向渗透的几种方式
- Typescript from entry to mastery (XVIII) joint type and type protection
- 5年多工作经验,工资给15k,要是你,你会接受吗?
- 1. Header file - Comment - namespace - standard input / output stream
- Let variable declaration feature of ES6 new feature and its case
- SQL window function
猜你喜欢

(newcoder 15079)无关(容斥原理)

Getting started with caspin

Beijing post network research 2015 problem2

实例搭建Flask服务(简易版)

Instance setup flask service (simple version)

消费行业数字化升级成 “刚需”,weiit 新零售 SaaS 为企业赋能!

SQL window function

(nowcoder22529c) diner (inclusion exclusion principle + permutation and combination)

Typescript from getting started to mastering (XVI) configuration file - first knowledge of compileroptions configuration item

The digitalization of the consumer industry is upgraded to "rigid demand", and weiit's new retail SaaS empowers enterprises!
随机推荐
Typescript from entry to mastery (XXI) generic types in classes
Shopify卖家:EDM营销就要搭配SaleSmartly,轻松搞定转化率
1985-2020 (8 Editions) global surface coverage download and introduction
Raft protocol - process demonstration
3. Solve pychart's error unresolved reference 'selenium' unresolved reference 'webdriver‘
向日葵远程控制为何采用BGP服务器?自动最优路线、跨运营商高速传输
(newcoder 15079) irrelevant (inclusion exclusion principle)
SQL窗口函数
Typescript from getting started to mastering (XXII) namespace namespace (I)
[BGP] small scale experiment
OPENSQL快速学习
Big manufacturers finally can't stand "adding one second", and companies such as Microsoft, Google meta propose to abolish leap seconds
Why is continuous integration and deployment important in development?
Deep understanding of browser caching mechanism (HTTP)
Zhihuijun, a genius of Huawei, made a modular mechanical keyboard, which caused an earthquake in the geek circle. Netizens: This is the real customization
新零售O2O 电商模式解析
Since 2019, you must have stopped using this marketing strategy
Android view system and custom view Series 1: (kotlin version)
谁能详细说下mysqlRC下的半一致读和怎么样减少死锁概率?
Sunflower senior product director technology sharing: "how to apply national remote control" in AD domain environment