IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言入门小游戏—三子棋 -> 正文阅读

[C++知识库]C语言入门小游戏—三子棋

一、何为三子棋

??三子棋又称为井字棋,相信大家都玩过这个小游戏,其规则就是哪一方先将相邻的的三枚棋子连在一起便获得胜利,那么今天就由我为大家讲解如何使用C语言实现简单的三子棋游戏吧。

二、解题思路

1.首先确定编写形式

??多文件形式实现无疑是最清晰、最直观的编写形式。

主函数(调用):test.c 测试三子棋游戏(实现游戏的大体逻辑和功能)
模块(被调用):game.c 游戏函数及其功能的实现
头文件(声明):game.h 三子棋游戏的函数声明

我先将头文件展示出来,为大家下来的解题提供明确的思路:

#pragma once
#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 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);
  • 由图可见,一共有三个库函数所需要的头文件以及五个为实现游戏功能而创建的函数;
  • 我认为打印棋盘尤为重要,无论是在何种情况下,我们都需要在成功实现某些功能时打印棋盘检验功能的完整性。

2.设计游戏菜单页面

??游戏菜单必须出现在我们最终生成的结果当中,也就是需要“printf”将其打印出来,而main函数作为一个程序的入口,那么下面这段代码便是在test.c中实现的。

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

void menu()
{
	printf("***********************\n");
	printf("------  1. play  ------\n");
	printf("------  0. exit  ------\n");
	printf("***********************\n");
}

int main()
{
	int input = 0;
	//设置时间戳创建随机数
	srand((unsigned int)time(NULL));

	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;
}
  • 使用do…while循环实现游戏的重复可玩性;
  • switch语句实现游戏的菜单操作,为玩家提供选项;
  • 这里预处理操作中已经引入自定义函数(头文件内已经包含所需要的一切库以及函数声明);

3.打印棋盘

??根据棋盘的样式,我们可以联想到三子棋棋盘应该有九个待输入数据(可存储),且形式为3*3,所以在这里二维数组便是解题关键。 实现打印棋盘功能代码可以放在game.c文件中。

//初始化棋盘功能
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++)
	{
		//数据
		//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		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");
		}
	}
}

  • 初始化棋盘应为空格,方便玩家数据的输入。(注意:'\n’不会打印在结果里,故而此处打印空格);
  • 美化棋盘:待输入数据两端各一个空格;
  • 此时棋盘可以分为n组打印(每组打印一行数据和一行分割线),n为二维数组的列。(注意:此处不使用行数为打印条件是因为在二维数组中,列数可以确定行数,而行数不能确定列数);
  • 简陋棋盘无法完成棋盘的形态转换,所以此处不建议使用

4.游戏环节

??玩家下棋:输入坐标(需要考虑坐标合法性,坐标是否被占用)

//玩家下棋功能
void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	printf("玩家下棋:>\n");

	while (1)
	{
		printf("请输入要下棋的坐标:>");
		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] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,重新输入\n");
		}
	}
}
  • 作为玩家下棋环节应该做到正常坐标输入,即第一行第一列坐标输入应为(1,1),所以我们在判断坐标时应该对其减一达到我们所要的效果。

??简单电脑下棋:随机下棋(利用时间戳

//电脑随机下棋
void computer_move(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋:>\n");
	//%3利用取模运算控制取值范围
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
  • 这里电脑下棋我利用的是时间戳作为随机数,并且利用取模运算控制其数值范围;
  • 设置随机数需要用到srand(unsigned seed)以及time(NULL),所以我们还需要<stdlib.h>和<time.h>两个头文件,为了方便管理,我已经将所需头文件以及其他预处理操作放入game.h文件中。

5.判断输赢(游戏状态)

??游戏过程的功能实现

void game()
{
	char ret = 0;
	//数据的存储需要的二维数组
	char board[ROW][COL] = { 0 };
	//这里可以进行数组的初始化,防止'\n'等因素无法打印造成棋盘的错误
	init_board(board, ROW, COL);
	//打印棋盘
	display_board(board, ROW, COL);
	//玩游戏 
	while (1)//死循环,直到结果跳出
	{
		player_move(board, ROW, COL);
		display_board(board, ROW, COL);

		ret = is_win(board, ROW, COL);
		if (ret != 'R')
			break;

		computer_move(board, ROW, COL);
		display_board(board, ROW, COL);

		ret = is_win(board, ROW, COL);
		if (ret != 'R')
			break;

	}
	//定义特殊字符
	if (ret == '*')
	{
		printf("恭喜你获胜!\n");
	}
	else if (ret == '#')
	{
		printf("弱爆了,败给了人机!\n");
	}
	else if (ret == 'P')
	{
		printf("打成平手,继续训练吧!\n");
	}
	display_board(board, ROW, COL);
}

//玩家赢 - '*'
//电脑赢 - '#'
//平局了 - 'P'
//游戏继续 - 'R'
  • 该代码是属于test.c文件中的函数实现,目的是为了将整个游戏的过程以及游戏最终结果打印出来,实现游戏的实时互动及可见性。

??判断获胜方的函数代码实现

//简陋判断游戏结果
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];
	}
  • 逻辑判断的方式是分为三种状态,第一种为横行三个相连,第二种为纵行三个相连,第三种为两条对角线的判断;
  • 这是一段针对三子棋判断输赢的简陋方法,此处无法实现动态的判断。等博主空闲好好研究之后便会修改上传。

6.判断平局

??平局的关键在于棋盘的空间状态,即判断棋盘是否满了。

//如果棋盘满了,返回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;
}

//判断平局 由判满功能的返回值操作
	if (is_full(board, row, col) == 1)
	{
		return 'P';
	}

	//继续
	return 'R';
}
  • 首先我们可以创建is_full函数对棋盘这个二维数组的是否含有空格判断得出,棋盘此时的状态;
  • 然后我们就可以使用is_full函数的返回值进行游戏结果平局的判断。

7.运行结果

总结:这是一个简单的三子棋游戏,还有部分功能可以实现,以及你自己的想法也可以添加进去;
关键在于基础的函数应用和对二维数组的熟练使用。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:25:04  更:2022-08-06 10:29:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:34:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码