C语言三子棋小游戏

news2024/12/24 9:21:20

哈喽,大家好,今天我们要利用之前所学习的C语言知识来写一个三子棋小游戏。

目录

1.游戏

2.函数部分

2.1.菜单

2.2.初始化棋盘

2.3.打印棋盘

2.4.玩家下棋

2.5.电脑下棋

2.6.判断输赢

2.7.判断棋盘是否已满

3.完整代码展示


1.游戏

今天我们写的代码分为三个文件来写,分别是:

game.h 用来放函数的声明

game.c 用来放函数的定义

test.c 游戏的主体文件

大概介绍:

进入游戏,首先定义棋盘,对棋盘进行初始化。然后就是进入下棋的过程了,玩家是先手,玩家和电脑要不断重复地下棋,所以要在循环体内进行,玩家下棋,电脑下棋,判断输赢,和打印棋盘都是用函数来完成的

void game()
{
	char board[ROW][COL];
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisPlayBoard(board, ROW, COL);
	//下棋
	
	char ret = 0;
	while(1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret=IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		//电脑下棋
		ComputeMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret=IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}

 下面开始我们的学习吧:

2.函数部分

下面要介绍的是函数部分,因为游戏的代码比较长,将某些功能封装成函数,可以减少代码的重复量。

//菜单
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 PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputeMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//判断棋盘是否满了
int IsFull(char board[ROW][COL], int row, int col);

2.1.菜单

菜单的实现很简单,用户输入1开始游戏,输入0退出游戏

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

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] = ' ';
		}
	}
}

2.3.打印棋盘

打印棋盘的过程是比较麻烦的,下图是棋盘的效果展示图:

 在一个3*3的棋盘中,我们不仅要打印棋盘的数线,也要打印棋盘的横线,还要考虑棋子位置等问题。

 

void DisPlayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0, 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");
		}
	}
}

2.4.玩家下棋

玩家下棋的时候,需要判断输入的坐标是否合法,如果不合法,就需要重复输入。我们用‘*’来表示玩家下的棋子,用‘#’表示电脑下的棋子。

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("玩家下棋:->\n");
	
	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");
		} 
	}
}

2.5.电脑下棋

电脑下棋,需要是电脑产生2个随机数,如何是电脑产生的随机数在棋盘的大小之内呢?

我们可以使电脑产生的随机数对行和列相除取余,如果产生的随机数不合法,就需要让电脑重复产生新的随机数,直到坐标合法

 

void ComputeMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("电脑下棋:>\n");

	while(1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

2.6.判断输赢

判断输赢不仅要判断每一行,每一列,还要判断每一列

我们规定:

玩家赢 返回 '*'
电脑赢 返回 '#'
平局 返回 'Q'
继续 返回 'C'

这样当一方赢了后我们直接返回赢的一方的某个棋子即可

char IsWin(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][1];
		}
	}
	//列
	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[0][0] != ' ')
	{
		return board[0][0];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return board[0][2];
	}
	//平局
	if (IsFull(board, ROW, COL)==1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

2.7.判断棋盘是否已满

在每下完一步棋子后,都需要判断棋盘是否已满,满了的话游戏肯定是不能继续下去的

int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}

3.完整代码展示

game.h文件

#pragma once

#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 PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputeMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//判断棋盘是否满了
int IsFull(char board[ROW][COL], int row, int col);

game.c文件

#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;
	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, 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 PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("玩家下棋:->\n");
	
	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 ComputeMove(char board[ROW][COL], int row, int col)
{
	int x = 0, y = 0;
	printf("电脑下棋:>\n");

	while(1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

int IsFull(char board[ROW][COL], int row, int col)
{
	int i = 0, j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}

//玩家赢-'*'
//电脑赢-'#'
//平局-'Q'
//继续-'C'
 
char IsWin(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][1];
		}
	}
	//列
	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[0][0] != ' ')
	{
		return board[0][0];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
	{
		return board[0][2];
	}
	//平局
	if (IsFull(board, ROW, COL)==1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

test.c文件

#include"game.h"

void game()
{
	char board[ROW][COL];
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisPlayBoard(board, ROW, COL);
	//下棋
	
	char ret = 0;
	while(1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret=IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

		//电脑下棋
		ComputeMove(board, ROW, COL);
		//打印棋盘
		DisPlayBoard(board, ROW, COL);
		//判断输赢
		ret=IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}

	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:->");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("玩游戏\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	
	return 0;
}

下面是玩游戏的过程:

 哈哈,是电脑赢得了本次游戏,如果感到不过瘾的话可以再来一把,哈哈哈

总结:今天我们学习了三子棋小游戏,使用了多文件编程的形式,别看一个简简单单的小游戏,代码实现起来也没有那么容易呢,如果我写的有什么的不好之处,请在文章下方给出你宝贵的意见。如果觉得我写的好的话请点个赞赞和关注哦~😘

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

未知时间信息下雷达运动目标的计算高效重聚焦与估计方法

论文背景 在雷达成像中&#xff0c;回波信号在接收到之前可能已经被多次反射或散射&#xff0c;这样会导致回波信号的时间和频率发生变化。其中&#xff0c;距离向维度上的变化称为距离单元迁移&#xff08;range cell migration&#xff0c;RCM&#xff09;&#xff0c;频率向…

Spring笔记

文章目录 1、什么是Spring&#xff1f;2、如何创建Spring3、Spring简单的读和取操作1.直接在spring-config.xml里面放置对象2.通过配置扫描路径和添加注解的方式添加Bean对象3.为什么需要五个类注解4.从spring中简单读取 Bean对象5.Resource和Autowired的异同 1、什么是Spring&…

Transformer结构细节

一、结构 Transformer 从大的看由 编码器输入、编码器、解码器、解码器输入和解码器输出构成。 编码器中包含了词嵌入信息编码、位置编码、多头注意力、Add&Norm层以及一个全连接层&#xff1b; 解码器中比编码器多了掩码的多头注意力层。 二、模块 2.1 Input Embeddi…

canvas学习之华丽小球滚动电子时钟

教程来自 4-3 华丽的小球滚动效果 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>华丽小球滚动时钟…

【AVL树的模拟实现】

1 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决…

人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现&#xff0c;在人工智能领域&#xff0c;蒙特卡洛方法&#xff08;Monte Carlo Method, MCM&#xff09;被广泛应用于各种问题的求解。本文首先将…

wvp-GB28181-pro录像功能开发环境搭建、配置、使用

开发环境、调试环境搭建 开发wvp平台搭建 离线安装脚本&#xff1a;https://gitcode.net/zenglg/ubuntu_wvp_online_install.git 下载离线安装脚本&#xff0c;完成wvp平台的部署 开发环境要求 操作系统&#xff1a;包管理工具是apt ky10桌面版uos桌面版deepin桌面版ubuntu桌面…

ArmDot.NET Crack

ArmDot.NET Crack ArmDot是一个.NET加密工具&#xff0c;用于保护使用.NET编写的程序。 企业需要保护他们的知识产权&#xff0c;包括他们的算法、产品和使用的资源的源代码。 然而&#xff0c;.NET编译器会生成一个通用的可访问代码。代码中嵌入的资源很容易访问&#xff0c;并…

RocketMQ不同的类型消息

目录 普通消息 可靠同步发送 可靠异步发送 单向发送 三种发送方式的对比 顺序消息 事物消息 两个概念 事务消息发送步骤 事务消息回查步骤 消息消费要注意的细节 RocketMQ支持两种消息模式: 普通消息 RocketMQ提供三种方式来发送普通消息&#xff1a;可靠同步发送、…

剑指Offer题集(力扣)

文章目录 剑指Offer题集&#xff08;[力扣题单](https://leetcode.cn/problemset/all/?listIdlcof&page1)&#xff09;[剑指 Offer 03. 数组中重复的数字](https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)[剑指 Offer 04. 二维数组中的查找](https:…

SSM框架练习一(登录后关联数据表的业务模型)

需要实现的整体功能&#xff1a; 登录反馈信息列表展示查询反馈信息发表反馈 1.数据库设计 创建数据库 创建表结构及其约束 添加测试数据 工具&#xff1a;PHP、Navicat create table tab_user(id int primary key auto_increment,uname varchar(30) not null,pwd varc…

Weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271复现)

文章目录 前言影响版本环境搭建漏洞复现深度利用 前言 CVE-2017-10271漏洞产生的原因大致是Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任意…

从搬砖工到架构师,Java全栈学习路线总结

&#x1f307;文章目录 前言一、前置知识二、 Web前端基础示例&#xff1a;1.文本域2.密码字段 三、后端基础一. Java基础二. 数据库技术三. Web开发技术四. 框架技术五. 服务器部署 四、其他技术五、全栈开发六、综合实践七、学习教程一、前端开发二、后端开发三、数据库开发四…

springboot+jsp乡村中小学校园网站建设

随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;乡村小学校园网当然也不能排除在外&#xff0c;从校园概况、学校风采、招生信息的统计和分析&#xff0c;在过程中会产生大量的…

Maven依赖原则及如何解决Maven依赖冲突

前言 在大数据应用中&#xff0c;现在发现依赖关系非常复杂&#xff0c;在上线之前很长测试&#xff0c;前一段时间在部署udf 出现了导致生产Hiveserver2 宕机问题&#xff0c;出现严重事故。现在就咨询研究一下。Maven虽然已经诞生多年&#xff0c;但仍然是当前最流行的Java系…

Arrays:点燃你的数组操作技巧的隐秘武器。

前言 数组在 Java 中是一种常用的数据结构&#xff0c;用于存储和操作大量数据。但是在处理数组中的数据&#xff0c;可能会变得复杂和繁琐。Arrays 是我们在处理数组时的一把利器。它提供了丰富的方法和功能&#xff0c;使得数组操作变得更加简单、高效和可靠。无论是排序、搜…

【c语言】字符串类型转换 | itoa函数的使用

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …

MySQL innodb介绍

InnoDB引擎的优点是支持兼容ACID的事务&#xff0c;以及参数完整性&#xff08;即对外键的支持&#xff09;。 Oracle公司2005年10月收购了Innovase&#xff1b;Innobase采用双认证授权。它使用GNU发行&#xff0c;也允许其他想将InnoDB结合到商业软件的团体好的授权 mysql5.…

Java 动态原理详解

Java 动态代理是一种非常重要的编程技术&#xff0c;它在很多场景下都有着广泛的应用。本文将介绍 Java 动态代理的实现原理&#xff0c;并附上相应的源码&#xff0c;以帮助读者更好地理解和应用这一技术。 一、什么是 Java 动态代理&#xff1f; Java 动态代理是一种在运行时…

【并发基础】Happens-Before模型详解

目录 一、Happens-Before模型简介 二、组成Happens-Before模型的八种规则 2.1 程序顺序规则&#xff08;as-if-serial语义&#xff09; 2.2 传递性规则 2.3 volatile变量规则 2.4 监视器锁规则 2.5 start规则 2.6 Join规则 一、Happens-Before模型简介 除了显示引用vo…