c语言——三子棋

基本框架

三个文件:

其中.cpp文件用于游戏具体函数设计,.h文件为游戏的函数声明,test.cpp文件用于测试游戏运行。

 需要用到的头文件:

#include <stdio.h>
#include <stdlib.h>//rand&srand
#include <time.h>//时间相关

框架运行

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

}
int main()
{
	int input;
	
	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;
}

运行结果:

棋盘

棋盘是一个3*3的平面,可以用二维数组接收,编译器不支持变长数组,我们可以用define定义数组的下标(行和列),之后有大用。

#define COL 3
#define ROW 3

打印:

 为什么没有对齐呢?这是因为字符数组初始化为0等价于\0,而\0是不会显示出来的,所以,我们再添加一个初始化函数。

 初始化函数

因为游戏可以反复游玩,我们不妨设置一个初始化函数,将棋子置于初始状态('  '字符)。

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

可以发现这次棋盘很标准了,但有点刻意的风味,如果想要一个10*10的棋盘,又要重新设计吗?应对此种情况,我们试着改进棋盘。

棋盘改进

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)//末行不用分割
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

 看着挺复杂其实很简单,只要找出重复的部分再进行循环和判断就能打印出你想要的样子!

 玩家下棋

玩家下棋有两个注意点,判断坐标是否合法和坐标是否被占用。为此我们需要设计一个循环语句。坐标范围从1开始而不是从0开始是因为让玩家觉得合理。

void player_move(char board[ROW][COL], int row, int col)
{
	int x;
	int y;
	while (1)
	{
		printf("请输入要下棋的坐标:>");
		scanf("%d %d", &x, &y);
		if (y <= col && x <= row)
		{
			if (board[x-1][y-1] == ' ')
			{
				board[x-1][y-1] = '*';
				break;
			}
			else
			{
				printf("该坐标被占用,请重新输入\n");
			}
		}
		else
		{
		printf("坐标非法,重新输入\n");
		}
	}
}

测试: 

 电脑下棋

需要用随机函数rand生成随机数和srand设置初始点使之电脑能随机在棋盘上下棋。

srand放在主函数里,循环体前,只需执行一次。 

void computer_move(char board[ROW][COL], int row, int col)
{
	while (1)
	{
		int x = rand() % 3;//0~2
		int y = rand() % 3;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

胜负评判

接着需要我们评判双方获胜条件,即三子连成一条线的情况。

这里我们直接无脑评判就行,如果三处相同且不为空格则说明一方胜利

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

这里有个取巧的方法,可以直接用我们棋子所代表的字符作为返回值进行判断。

是否平局

平局需要单独判断,我们可以封装一个函数,遍历看棋盘是否已满就行了。

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;
}

这里的static是只对本文件可见,因为它只用于我们的胜负评判。

接下来我们对主函数的game函数再增添胜负评判,每次落子之后进行评判,根据对应的返回值输出相应的结果。

运行结果:

完整代码

//game.c
#include "game.h"
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)//末行不用分割
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
	printf("\n");
}
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 player_move(char board[ROW][COL], int row, int col)
{
	int x;
	int y;
	while (1)
	{
		printf("请输入要下棋的坐标:>");
		scanf("%d %d", &x, &y);
		if (y <= col && x <= row)
		{
			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)
{
	while (1)
	{
		int x = rand() % 3;
		int y = rand() % 3;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

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][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[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';
}
//.h
#define _CRT_SECURE_NO_WARNINGS 1
#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);
//test.c
#include"game.h"
void menu()
{
	printf("*********************************\n");
	printf("********      1. play    ********\n");
	printf("********      0. exit    ********\n");
	printf("*********************************\n");
}
void game()
{
	char board[ROW][COL] = { 0 };
	init_board(board, ROW, COL);
	display_board(board, ROW, COL);
	char ret;
	while (1)
	{
	player_move(board, ROW, COL);
	display_board(board, ROW, COL);
	ret = is_win(board, ROW, COL);
	if (ret != 'C')
		break;
	computer_move(board, ROW, COL);
	display_board(board, ROW, COL);
	ret = is_win(board, ROW, COL);
	if (ret != 'C')
		break;
	}
	if (ret == 'Q')
	{
		printf("平局\n");
	}
	if (ret == '*')
	{
		printf("玩家胜\n");
	}
	 if (ret == '#')
	{
		printf("电脑胜\n");
	}
}
int main()
{
	int input;
	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;
}

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

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

相关文章

【BASH】回顾与知识点梳理(十四)

【BASH】回顾与知识点梳理 十四 十四. 文件与目录的默认权限与隐藏权限14.1 文件预设权限&#xff1a;umaskumask 的利用与重要性&#xff1a;专题制作 14.2 文件隐藏属性chattr (配置文件案隐藏属性)lsattr (显示文件隐藏属性) 14.3 文件特殊权限&#xff1a; SUID, SGID, SBI…

《剑指offer》(6)其他算法

先计算下三角&#xff0c;再遍历一次计算上三角。 class Solution: def multiply(self , A: List[int]) -> List[int]: #长度判断 n len(A) if n < 1: return [] B [1]*n #计算乘矩阵的下三角&#xff0c;B中的每一个数都是A的前一个数和B的前一个数相乘 for i in ran…

Linux系统中的自旋锁(两幅图清晰说明)

总结&#xff1a; 多CPU下的自旋锁采取的是忙等待&#xff08;原地打转&#xff09;机制&#xff0c;虽然忙等待的线程占用了它所在的cpu&#xff0c;但其他线程仍可放到其他CPU上执行。所以自旋锁上锁和解锁之间的临界区代码要尽量的短&#xff0c;最好不要超过5行&#xff0c…

【Linux拓展】ncurses库的安装和使用 {ncurses库的安装方法,ncurses库的使用手册,基于终端的贪吃蛇游戏}

一、简介 ncurses库是一个用于创建基于终端的交互式应用程序的库。它提供了一套API&#xff0c;用于处理终端界面的输入和输出&#xff0c;以及控制终端的光标位置、颜色、窗口等。 使用ncurses库&#xff0c;您可以在终端中创建复杂的文本界面&#xff0c;包括窗口、菜单、按…

能化校对软件:提高招标文件质量的创新解决方案

智能化校对软件是一种创新的解决方案&#xff0c;可以进一步提高招标文件的质量和准确性。 以下是一些智能化校对软件的创新功能和优势&#xff1a; 1.自然语言处理(NLP)技术&#xff1a;智能化校对软件利用NLP技术来理解和分析文本&#xff0c;识别和纠正更复杂的语法和语义错…

chapter14:springboot与安全

Spring Boot与安全视频 Spring Security, shiro等安全框架。主要功能是”认证“和”授权“&#xff0c;或者说是访问控制。 认证&#xff08;Authentication&#xff09;是建立在一个声明主体的过程&#xff08;一个主体一般指用户&#xff0c;设备或一些可以在你的应用程序中…

集合工具类 Collections:提升集合操作效率

文章目录 多元素添加&#xff1a;addAll 方法随机置换&#xff1a;shuffle 方法自定义对象排序&#xff1a;sort 方法总结 在Java的集合框架中&#xff0c;Collections 是一个包含了许多操作集合的静态方法的工具类。通过使用 Collections 类提供的方法&#xff0c;我们能够更加…

利用 3D 地理空间数据实现Cesium的沉浸式环境

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可编辑的3D应用场景 为了将大量异构 3D 地理空间数据处理和分散到各行各业的地理空间应用程序和运行时引擎&#xff0c;Cesium 创建了 3D Tiles&#xff0c;这是一种用于高效流式传输和渲染大量异构数据集的开放标准。3D Tile…

CEC2013(MATLAB):淘金优化算法GRO求解CEC2013的28个函数

一、淘金优化算法GRO 淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;由Kamran Zolf于2023年提出&#xff0c;其灵感来自淘金热&#xff0c;模拟淘金者进行黄金勘探行为。淘金优化算法&#xff08;Gold rush optimizer&#xff0c;GRO&#xff09;提…

尚硅谷大数据项目《在线教育之采集系统》笔记004

视频地址&#xff1a;尚硅谷大数据项目《在线教育之采集系统》_哔哩哔哩_bilibili 目录 P047 P048 P049 P050 P051 P052 P053 P054 P055 P056 P047 /opt/module/datax/job/base_province.json [atguigunode001 ~]$ hadoop fs -mkdir /base_province/2022-02-22 [atgu…

干货 | 详述 Elasticsearch 向量检索发展史

1. 引言 向量检索已经成为现代搜索和推荐系统的核心组件。 通过将复杂的对象&#xff08;例如文本、图像或声音&#xff09;转换为数值向量&#xff0c;并在多维空间中进行相似性搜索&#xff0c;它能够实现高效的查询匹配和推荐。 图片来自&#xff1a;向量数据库技术鉴赏【上…

Hugging Face 的文本生成和大语言模型的开源生态

[更新于 2023 年 7 月 23 日: 添加 Llama 2。] 文本生成和对话技术已经出现多年了。早期的挑战在于通过设置参数和分辨偏差&#xff0c;同时控制好文本忠实性和多样性。更忠实的输出一般更缺少创造性&#xff0c;并且和原始训练数据更加接近&#xff0c;也更不像人话。最近的研…

c51单片机16个按键密码锁源代码(富proteus电路图)

注意了&#xff1a;这个代码你是没法直接运行的&#xff0c;但是如果你看得懂&#xff0c;随便改一改不超过1分钟就可以用 #include "reg51.h" #include "myheader.h" void displayNumber(unsigned char num) {if(num1){P10XFF;P10P11P14P15P160;}else if…

论文讲解——TPU-MLIR: A Compiler For TPU Using MLIR

论文讲解——TPU-MLIR: A Compiler For TPU Using MLIR https://arxiv.org/pdf/2210.15016.pdf概览模型转换TranslationCanonicalizeLoweringLayerGroup BufferizationCalibration QuantizationCorrectness Check相关资料 https://arxiv.org/pdf/2210.15016.pdf 本文将对TPU…

vue3 动态导入src/page目录下的所有子文件,并自动注册所有页面组件

main.js添加一下代码&#xff1a; const importAll (modules) > {Object.keys(modules).forEach((key) > {const component key.replace(/src/, /).replace(.vue, );const componentName key.split(/).slice(-2, -1)[0] -page;app.component(componentName, modules…

RocketMQ 5.x如何使用GRPC方式发送消费消息

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 RocketMQ版本 5.1.0 背景 我们都知道RocketMQ 5.x新增了proxy模式部署方式&#xff0c;也就是支持了GRPC的消费方式消费&#xff0c;所以今天我们来试试 本次…

php通过各种函数判断0和空php实例

php通过各种函数判断0和空php实例 本文给大家介绍php同各种函数判断0和空的方法&#xff0c;在文章给大家补充介绍了php 语法里0不等于null为空的解决办法 补充&#xff1a;下面给大家介绍下php 语法里0不等于null为空的解决办法 今天遇到这样一个问题是这样的: php 语句里,我…

Nevron Diagram for .NET Crack

Nevron Diagram for .NET Crack Nevron Diagram for.NET可帮助您快速轻松地在.NET Windows窗体和ASP.NET应用程序中集成和显示复杂的图表。这是一个完整的绘图解决方案&#xff0c;包含许多交互功能、形状、自动布局和令人惊叹的视觉效果&#xff0c;并配备了现成的控件&#x…

Linux常规操作命令

日升时奋斗&#xff0c;日落时自省 目录 1、vim 1.1、工作模式 1.2、末行模式操作相关命令 1.2.1、保存退出操作 1.2.2、查找替换 1.3、输入模式操作相关命令 1.3.1、移动相关命令 1.3.2、删除和剪切命令 1.3.3、复制操作 1.3.4、撤销 2、head 3、tail 4、ps 5、…

策略模式【Strategy Pattern】

刘备要到江东娶老婆了&#xff0c;走之前诸葛亮给赵云&#xff08;伴郎&#xff09;三个锦囊妙计&#xff0c;说是按天机拆开解决棘手问题&#xff0c; 嘿&#xff0c;还别说&#xff0c;真是解决了大问题&#xff0c;搞到最后是周瑜陪了夫人又折兵呀&#xff0c;那咱们先看看…