利用C语言实现三子棋游戏

文章目录

  • 1.游戏界面
  • 2.游戏内容
    • 2.1 棋盘类型
    • 2.2棋盘的初始化
    • 2.3 打印棋盘的界面展示
  • 3.游戏操作
    • 3.1 玩家操作
    • 3.2 电脑操作
    • 3.3 胜负判定
  • 4.代码整合

1.游戏界面

无论写任何程序,我们都需要先去了解它的大概框架,这里我们先把它的初始界面写出来。一个游戏的初始界面会有菜单可供选择,这里我写了一个最基础的游戏菜单,只支持开始游戏和退出游戏。为了能够在不退出游戏的情况下一直游玩,所以这里我写了一个do while循环来让游戏一直进行下去。

#include <stdio.h>
void menu()
{
	printf("*************************\n");
	printf("******* 1.play    *******\n");
	printf("******* 0.exit    *******\n");
	printf("*************************\n");
	
}
int main()
{
	int input = 0;
	do
	{
		menu()//菜单
		printf("请选择>");
		scanf"%d",&input);
		switch(input)
		{
			case 1:
			game();
			break;
			case 0:
			printf("退出游戏!\n");
			break;
			default:
			break;
		}
	}while(input);
	return 0;
}

2.游戏内容

2.1 棋盘类型

写完游戏的界面就轮到了游戏的内容了,让我们来想想三子棋有什么特点,最先想到就是它那3*3的棋盘了,为了实现这个棋盘我们要利用数组来实现。用什么类型的数组呢?这里我会用字符类型的数组,毕竟下棋用数字来作为棋子还是不容易区分的。

void game()
{
	//创建棋盘
	char chess[4][4] = {0};
}

2.2棋盘的初始化

选择了用字符数组来作为棋盘,初始化我会用‘ ’(空格)来初始化。空格初始化的好处就是不可见,当我们下好棋子后用相应的字符去覆盖掉空格就可以了。
这里我用4*4的数组是为了后续普通用户在用下标下棋时,不用考虑数组下标是0开始的,增加用户的受众。
为什么用多文件编写代码,多文件的编写可以便于后续的修改,多文件可以让代码的可读性更高。
注意头文件game.h放的是函数的声明,game.c放的是函数的定义 test.c是对程序的测试

//game.h
#include <stdio.h>
//以row为行,col为列

void InitChess(char chess[4][4],int row,int col);

//game.c
#include "game.h"
void InitChess(char chess[4][4],int row,int col)
{
	for(int i = 1;i<4;++i)
	{
		for(int j = 1;j<4;++j)
		{
			chess[i][j] = ' ';
		}
	}
}

//test.c
#include "game.h"
void game()
{
	//创建棋盘
	char chess[4][4] = {0};
	//初始化棋盘
	InitChess(chess,4,4);
}

对函数拓展性的优化,这里的棋盘已经被固定,如果后续我们想要修改棋盘的大小是很麻烦的,所以我们可以定义标识常量。

//game.h
#include <stdio.h>
//以row为行,col为列
#define Row 4
#define Col 4

void InitChess(char chess[Row][Col],int row,int col);

//game.c
#include "game.h"
void InitChess(char chess[Row][Col],int row,int col)
{
	for(int i = 1;i<row;++i)
	{
		for(int j = 1;j<col;++j)
		{
			chess[i][j] = ' ';
		}
	}
}

//test.c
#include "game.h"
void game()
{
	//创建棋盘
	char chess[Row][Col] = {0};
	//初始化棋盘
	InitChess(chess,Row,Col);
}

2.3 打印棋盘的界面展示

如果我们直接打印这个数组是什么也看不到的,为了让游玩的人可以轻松知道棋盘各个点的坐标,我们要把棋盘打印成这个样子。
打印棋盘

void ChessBoard(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			printf(" %c ", chess[i][j]);
			if (j < col - 1)//否则打印最后一个'|',导致右端封闭
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 1; j < col; ++j)
			{
				printf("--- ");
			}
			printf("\n");
		}

	}
}

3.游戏操作

3.1 玩家操作

三子棋的游戏操作就是在3*3的方格当中选一个未被下过的方格中落子。
当前游戏并不支持双人对战,所以只能实现人机对战。下面为玩家操作:

void Gamer(char chess[Row][Col], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("选择落子坐标>\n");
		printf("坐标之间用空格区分\n");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x<1 || x>Row - 1 || y<1 || y>Col - 1)
		{
			printf("坐标不合法\n");
		}
		//判断所选坐标是否被占据
		else if (chess[x][y] != ' ')
		{
			printf("该坐标被占据\n");
		}
		else
		{
			chess[x][y] = 'O';
			printf("落子成功\n");
			break;
		}
	}
}

3.2 电脑操作

电脑的逻辑和玩家一样,这里我们让电脑随机下棋。

void Computer(char chess[Row][Col], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % (row - 1) + 1;
		y = rand() % (col - 1) + 1;
		if (chess[x][y] != ' ')
		{
			//
		}
		else
		{
			chess[x][y] = 'X';
			break;
		}
	}
}

因为这了我们用了rand函数,所以我必须在前面写上srand来给rand函数提供随机种子,为此我们还需要用到time为srand提供数字来帮助它输出随机种子.
记得加上相应的头文件

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:
			break;
		}
	}while(input);
	return 0;
}

3.3 胜负判定

在三子棋当中,任何以方的棋子连成一条线就会判断为获胜,无论是一行还是一列还是斜方向。因为只有少量的情况。我能把所有获胜的情况全部都枚举出来就可以了。
关于返回值,因为我们要根据棋盘字符的连线来判断谁是赢家。
规定:返回 ‘O’表示玩家赢,‘X’表示电脑赢 'D’表示平局 'C’表示游戏继续

char Winer(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' ')
		{
			return chess[i][1];
		}
	}
	for (int j = 1; j < col; ++j)
	{
		if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' ')
		{
			return chess[1][j];
		}
	}
	if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' ')
	{
		return chess[1][1];
	}
	if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' ')
	{
		return chess[1][3];
	}
	//平局,判断棋盘是不是已经满了
	if (IsFull(chess, row, col))
	{
		return 'D';
	}
	return 'C';
}

判断棋盘是否已经下满

bool IsFull(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			if (chess[i][j] == ' ')
				return false;
		}
	}
	return true;
}

4.代码整合

关于三子棋的简单游戏逻辑就是这么多了,下面我们要把我们写到的函数整合到一起。

//game.h
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>//rand和srand的头文件
#include <time.h>//time的头文件
#define Row 4
#define Col 4

void InitChess(char chess[Row][Col], int row, int col);

void ChessBoard(char chess[Row][Col], int row, int col);

void Gamer(char chess[Row][Col], int row, int col);

void Computer(char chess[Row][Col], int row, int col);

char Winer(char chess[Row][Col], int row, int col);

bool IsFull(char chess[Row][Col], int row, int col);

//game.c

#include "game.h"

void InitChess(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			chess[i][j] = ' ';
		}
	}
}

void ChessBoard(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			printf(" %c ", chess[i][j]);
			if (j < col - 1)//否则打印最后一个'|',导致右端封闭
				printf("|");
		}
		printf("\n");
		if (i < row - 1)
		{
			for (int j = 1; j < col; ++j)
			{
				printf("--- ");
			}
			printf("\n");
		}

	}
}

void Gamer(char chess[Row][Col], int row, int col)
{
	int x = 0;//横坐标
	int y = 0;//纵坐标
	while (1)
	{
		printf("选择落子坐标>\n");
		printf("坐标之间用空格区分\n");
		scanf("%d %d", &x, &y);
		//判断坐标是否合法
		if (x<1 || x>Row - 1 || y<1 || y>Col - 1)
		{
			printf("坐标不合法\n");
		}
		//判断所选坐标是否被占据
		else if (chess[x][y] != ' ')
		{
			printf("该坐标被占据\n");
		}
		else
		{
			chess[x][y] = 'O';
			printf("落子成功\n");
			break;
		}
	}
}

void Computer(char chess[Row][Col], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		x = rand() % (row - 1) + 1;
		y = rand() % (col - 1) + 1;
		if (chess[x][y] != ' ')
		{
			//
		}
		else
		{
			chess[x][y] = 'X';
			break;
		}
	}
}

char Winer(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		if (chess[i][1] == chess[i][2] && chess[i][2] == chess[i][3] && chess[i][1] != ' ')
		{
			return chess[i][1];
		}
	}
	for (int j = 1; j < col; ++j)
	{
		if (chess[1][j] == chess[2][j] && chess[2][j] == chess[3][j] && chess[1][j] != ' ')
		{
			return chess[1][j];
		}
	}
	if (chess[1][1] == chess[2][2] && chess[2][2] == chess[3][3] & chess[1][1] != ' ')
	{
		return chess[1][1];
	}
	if (chess[1][3] == chess[2][2] && chess[2][2] == chess[3][1] && chess[2][2] != ' ')
	{
		return chess[1][3];
	}
	//平局,判断棋盘是不是已经满了
	if (IsFull(chess, row, col))
	{
		return 'D';
	}
	return 'C';
}

bool IsFull(char chess[Row][Col], int row, int col)
{
	for (int i = 1; i < row; ++i)
	{
		for (int j = 1; j < col; ++j)
		{
			if (chess[i][j] == ' ')
				return false;
		}
	}
	return true;
}

//test.c
#include "game.h"

void game()
{
	//创建棋盘
	char chess[Row][Col] = { 0 };
	//初始化棋盘
	InitChess(chess, Row, Col);
	char w = 0;
	while (1)
	{
		//打印棋盘
		ChessBoard(chess, Row, Col);
		//玩家操作
		Gamer(chess, Row, Col);
		//输赢判断
		w = Winer(chess, Row, Col);
		if (w != 'C')
			break;
		//电脑操作
		Computer(chess, Row, Col);
		//输赢判断
		char w = Winer(chess, Row, Col);
		if (w != 'C')
			break;
	}
	ChessBoard(chess, Row, Col);
	if (w == 'D')
		printf("平局\n");
	else if (w == 'O')
		printf("玩家获胜\n");
	else
		printf("电脑获胜\n");
}
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:
			break;
		}
	} while (input);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/775244.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自动化设备上位机设计 二

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 namespace 自动化上位机设计 {public partial class Form1 : Form{public Form1(){InitializeComponent();timer1.Enabled true;timer1.Tick Timer1_Tick;}private void Timer1_Tick(object? sender, EventArgs e)…

「媒体邀约」天津媒体资源?媒体邀约宣传报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 天津拥有丰富的媒体资源&#xff0c;利用这些资源进行有效…

数智化配补调:零售品牌增长新引擎

随着科技的不断进步和消费者需求的日益个性化、多元化&#xff0c;传统服装行业正面临着前所未有的挑战与机遇。在这个快速变化的时代&#xff0c;如何精准把握市场脉搏&#xff0c;实现库存的高效管理&#xff0c;成为了服装品牌生存与发展的关键。数智化配补调策略应运而生&a…

Java后端每日面试题(day3)

目录 Spring中Bean的作用域有哪些&#xff1f;Spring中Bean的生命周期Bean 是线程安全的吗&#xff1f;了解Spring Boot中的日志组件吗&#xff1f; Spring中Bean的作用域有哪些&#xff1f; Bean的作用域&#xff1a; singleton&#xff1a;单例&#xff0c;Spring中的bean默…

重载一元运算符

自增运算符 #include<iostream> using namespace std; class CGirl { public:string name;int ranking;CGirl() { name "zhongge"; ranking 5; }void show() const{ cout << "name : "<<name << " , ranking : " <…

卫星轨道平面简单认识

目录 一、轨道平面 1.1 轨道根数 1.2 应用考虑 二、分类 2.1 根据运行高度 2.2 根据运行轨迹偏心率 2.3 根据倾角大小 三、卫星星座中的轨道平面 四、设计轨道平面的考虑因素 一、轨道平面 1.1 轨道根数 轨道平面是定义卫星或其他天体绕行另一天体运动的平面。这个平…

小白 | Linux安装python3

一、更新包列表 首先&#xff0c;确保你的包管理器是最新的&#xff1a; sudo apt update 二、安装 Python 3 安装 Python 3 以及常用的开发工具 sudo apt install python3 python3-pip python3-venv 三、验证安装 python3 --version

如何在 SwiftUI 中熟练使用 sensoryFeedback 修饰符

文章目录 前言背景介绍平台支持仅支持watchOS支持watchOS和iOS 基本用法预定义样式根据触发器值选择样式使用场景当值更改时触发使用条件闭包触发使用反馈闭包触发 可以运行 Demo总结 前言 SwiftUI 引入了新的 sensoryFeedback 视图修饰符&#xff0c;使我们能够在所有 Apple …

【数据结构】(6.2)堆的应用——Top-K问题(C语言)

系列文章目录 文章目录 系列文章目录问题引入一、TopK 问题 是什么&#xff1f;二、TopK 问题解决思路2.1 TopK 思路2.2 随机产生数字2.2 完整代码2.3 验证结果 问题引入 TopK 问题 (在一堆数据里面找到前 K 个最大 / 最小的数)。 一、TopK 问题 是什么&#xff1f; 生活中也…

Linux_fileio学习

参考韦东山老师教程&#xff1a;https://www.bilibili.com/video/BV1kk4y117Tu?p12 目录 1. 文件IO函数分类2. 函数原型2.1 系统调用接口2.2 标准IO接口 3. fileio内部机制3.1 系统调用接口内部流程3.1 dup函数使用3.2 dup2函数使用 4. open file4.1 open实例4.2 open函数分析…

【matlab】智能优化算法——基准测试函数

智能优化算法的基准测试函数是用于评估和优化算法性能的一组标准问题。这些测试函数模拟了真实世界优化问题的不同方面&#xff0c;包括局部最小值、全局最优解、高维度、非线性、不连续等复杂性。以下是对智能优化算法基准测试函数的详细归纳&#xff1a; 测试函数的分类&…

任天堂称未来第一方游戏不会使用生成式AI

虽然EA、育碧、暴雪、Embracer等西方游戏厂商都大力支持生成式AI技术&#xff0c;但日本老牌游戏公司任天堂并不会追随这一步伐。任天堂已经确认该公司未来的第一方游戏不会使用生成式AI技术。 在公司最近的投资人问答会上&#xff0c;任天堂描绘了公司未来游戏愿景。在谈到AI技…

秋招突击——7/5——设计模式知识点补充——适配器模式、代理模式和装饰器模式

文章目录 引言正文适配器模式学习篮球翻译适配器 面试题 代理模式学习面试题 装饰器模式学习装饰模式总结 面试题 总结 引言 为了一雪前耻&#xff0c;之前腾讯面试的极其差&#xff0c;设计模式一点都不会&#xff0c;这里找了一点设计模式的面试题&#xff0c;就针对几个常考…

图书馆数据仓库

目录 1.数据仓库的数据来源为业务数据库&#xff08;mysql&#xff09; 初始化脚本 init_book_result.sql 2.通过sqoop将mysql中的业务数据导入到大数据平台&#xff08;hive&#xff09; 导入mysql数据到hive中 3.通过hive进行数据计算和数据分析 形成数据报表 4.再通过sq…

一次建表语句触发的ORA-600报错分析

​ 某次在客户Oracle数据库执行一条建表语句时&#xff0c;报出ORA-600错误。 报错代码如下&#xff1a; ORA-00600: 内部错误代码, 参数: [rwoirw: check ret val], [], [], [], [], [], [], [], [], [], [], [] 相关的建表语句如下&#xff1a; ​ 在报错发生后&#xff0c;…

研0学习Python基础4

1.数组是一种存储大量同性质数据的连续内存空间&#xff0c;只要使用相同的变量名称&#xff0c;便可以连续访问 每一组数据。由于数组元素的便利性&#xff0c;使得大多数程序中都可以看到数组的身影。数组是一 个带有多个数据且模式相同的元素集合。比如&#xff0c;数值所…

Python + 在线 + 文生音,音转文(中文文本转为英文语音,语音转为中文文本)

开源模型 平台&#xff1a;https://huggingface.co/ars-语言转文本: pipeline("automatic-speech-recognition", model"openai/whisper-large-v3", device0 ) hf: https://huggingface.co/openai/whisper-large-v3 github: https://github.com/openai/wh…

详细的讲解一下网络变压器应用POE ,AT BT AF BF的概念,做电路连接指导分析

网络变压器在应用POE&#xff08;Power over Ethernet&#xff09;技术时&#xff0c;承担着重要的角色。它不仅负责数据的传输&#xff0c;同时也为网络设备提供电力。在IEEE 802.3标准中&#xff0c;定义了几个与POE相关的标准&#xff0c;包括802.3af、802.3at、802.3bt等&a…

AWS云服务器的竞争优势

亚马逊网络服务&#xff08;AWS&#xff09;作为全球最大的云计算平台&#xff0c;在激烈的市场竞争中一直保持领先地位。相较于其他云服务提供商&#xff0c;AWS云服务器具有多方面的显著优势&#xff0c;使其成为众多企业和开发者的首选&#xff0c;我们结合九河云的分析一起…

2024攻防演练:亚信安全新一代WAF,关键时刻守护先锋

实网攻防 网络安全如同一面坚固的盾牌&#xff0c;保护着我们的信息资产免受无孔不入的威胁。而其中&#xff0c;WAF就像网络安全的守门员&#xff0c;关键时刻挺身而出&#xff0c;为您的企业筑起一道坚实的防线。 攻防不对等 防守方实时应答压力山大 在攻防对抗中&#xf…