当前位置:网站首页>用C写小游戏(三子棋)
用C写小游戏(三子棋)
2022-08-02 07:37:00 【深夜吞食】
前言
在我们学习过程中一直记语法还有各种概念不妨会让我们难免会心生厌烦,但是我们换个方向想想,我们学的内容是否可以给我们带来一些乐趣呢?唉,没错就是游戏。从会玩游戏到制作游戏,想想兴趣是不是就提升上来了。下面就来看看用纯C的知识来实现一款经典的小游戏三子棋,所涉及的知识点不多循环,数组,宏定义,当然还有随机数生成的方法。下面就看看具体怎么实现吧。
实现的基本要素
1. 菜单
每当我们进入游戏的时候是不是都会有菜单显示给予玩家选择,要不然玩家进入一个黑框提示没有,接下来干嘛都不知道。菜单就像一个引路人一样,指引玩家了解怎样进行游戏。
int Meun()
{
printf("********************************\n");
printf("**** 1.play 0.exit ****\n");
printf("********************************\n");
}
有了菜单让我们来看看main函数实现
int main()
{
int input = 0;
do
{
Meun();
printf("请选择:>");
scanf("%d",&input);
switch(input)
{
case 1:
break;
case 0:
printf("游戏已退出\n");
break;
default:
printf("请选择 1 或者 0.\n");
break;
}
}
}while(input);
return 0;
}
这样设计是为了可以玩了一盘结束后可以进行自行选择是否再进行游戏。
2. 棋盘大小,及其初始化
2.1 棋盘大小
为了防止主函数main过于臃肿,我们把游戏的主体都放入game()这个函数中;
我们先创建一个二维数组,这个二维数组我们可以这样设计
#define ROW 3
#define COL 3
void game()
{
char board[ROW][COL];
}
宏定义在以后我们可以随意改变棋盘的大小,而不至于在写固定数字后面在改变棋盘的时候头大。
2.2 初始化棋盘
将棋盘全部初始化为空格表示为空
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
3. 打印棋盘

打印的方法有两种:第一种 纯打印
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 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 DisplayBoard(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 < col - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
4. 玩家与电脑的博弈
4.1 电脑下棋
在这里电脑下棋的设计我们简单一些,让其生成随机的棋子即可,在这里我们要生成随机数就要引入两个头文件
#include <stdlib.h>
#include <time.h>
rand函数生成的随机数是伪随机数,就是每次函数函数回来调用时生成的数字都是相同的。这样的随机数就不是我们想要的,但是要怎么解决这个问题呢?我们就要利用srand这个函数了设好随机数种子。在main函数里面开始设计即可:
srand((unsigned int)time(NULL));
设计好了随机数我们就来看看电脑下棋主体
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
x = rand() % row; //模上row是为了生成0到row之间的数值
y = rand() % col; 模上col是为了生成0到col之间的数值
if (board[x][y] == ' ')
{
board[x][y] = 'X'; //让电脑下的棋为X
break;
}
}
}
4.2 玩家下棋
我们给予玩家下棋的范围是有限的,就是棋盘大小范围内,超出棋盘范围我们就给予重新输入,还有就是在原来占有棋子的也不能下子,也需要重新输入。
玩家不像我们知道数组的下标都是从0开始,因此我们在玩家输入的坐标都要小于1。具体看下面代码:
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
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] = 'O';
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,超出范围");
}
}
4.3 判断输赢
玩家与电脑的下棋的时候有下面几种情况:
- 玩家获胜。
- 电脑获胜。
- 平局。
- 输赢未定。
不妨这样玩家与电脑每次下一次棋我们就判断一下,创建一个判断输赢的Iswin函数每下一次棋就判断一下,并返回一个字符值。
这个返回值因人而异可以随便设计,在这里我可以这样如果玩家赢我们返回玩家棋子’O’,电脑赢我们返回电脑棋子’X’,若是平局我们返回平局单词首字母’D’,若是输赢未定我们返回’Q’。
char Iswin(char board[ROW][COL], int row, int col)
{
//水平3个子一样
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];
}
}
//竖直3子一样
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][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 'D';
}
现在我们看看game函数的部分逻辑
void game()
{
//三子棋的过程
char board[ROW][COL]; //棋盘数组的创建
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
//下棋
while (1)
{
system("cls");
DisplayBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'D')
break;
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'D')
break;
}
if (ret == 'X')
{
printf("玩家赢\n");
}
else if (ret == 'O')
{
printf("电脑赢\n");
}
else if(ret == 'Q')
{
printf("平局\n");
}
}
游戏整体代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void Meun()
{
printf("********************************\n");
printf("**** 1.play 2.exit ****\n");
printf("********************************\n");
}
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(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 < col - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
x = rand() % row; //模上row是为了生成0到row之间的数值
y = rand() % col; 模上col是为了生成0到col之间的数值
if (board[x][y] == ' ')
{
board[x][y] = 'X'; //让电脑下的棋为X
break;
}
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
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] = 'O';
}
else
{
printf("坐标被占用,请重新输入\n");
}
}
else
{
printf("坐标非法,超出范围");
}
}
char Iswin(char board[ROW][COL], int row, int col)
{
//水平3个子一样
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];
}
}
//竖直3子一样
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][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 'D';
}
void game()
{
//三子棋的过程
char board[ROW][COL]; //棋盘数组的创建
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
//下棋
while (1)
{
system("cls");
DisplayBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'D')
break;
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'D')
break;
}
if (ret == 'X')
{
printf("玩家赢\n");
}
else if (ret == 'O')
{
printf("电脑赢\n");
}
else if(ret == 'Q')
{
printf("平局\n");
}
}
int main()
{
int input = 0;
do
{
Meun();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("游戏已退出\n");
break;
default:
printf("请选择 1 或者 0.\n");
break;
}
}while (input);
return 0;
}
边栏推荐
猜你喜欢

【Unity3D】初学加密技巧(反破解)

MySQL常见索引类型

pnpm install出现:ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies

Metasploit (MSF) Basic Super Detailed Edition

Comprehensive experiment of MPLS and BGP

Kind of weird!Access the destination URL, the host can container but not

Buried development process

WebRTC系列-SDP之编码信息收集

【CV】OpenVINO installation tutorial

ROS文件系统以及相关命令
随机推荐
RIP综合实验
HCIP第二天
MySQL事务(transaction) (有这篇就足够了..)
metabase访问adb mysql 如何控制会话时区??
Introduction to mysql operation (4) ----- data sorting (ascending, descending, multi-field sorting)
pnpm + workspace + changesets 构建你的 monorepo 工程
HCIP第三天
(2022 Nioke Duo School 5) C-Bit Transmission (Thinking)
7.联合索引(最左前缀原则)
MySQL压缩包方式安装,傻瓜式教学
@RequestParam使用
Probability Theory and Mathematical Statistics
2022-08-01 第四小组 修身课 学习笔记(every day)
Introduction to Totem Pole and Push-Pull Circuits
apt & apt-get commands
3D激光slam:LeGO-LOAM---地面点提取方法及代码分析
uni.navigateBack 中的坑
How to export multiple query results at once in SQL server 2014?
postgres 水平分表,自动创建分区,按时间分表
Neural network