当前位置: 首页 > article >正文

C语言初阶习题【19】三子棋游戏

1.实现三子棋游戏

2.思路

我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中
main函数在test.c中。

2.1 test.c中

  1. 先写main 函数,在main函数中调用test函数。
int main()
{
	test();
	return 0;
}
  1. test.c函数实现让玩家进行选择是否要进行游戏
    这里用到了do…while语句,先上来打印一个菜单,让玩家进行输入,根据玩家输入进入不同的分支。
void test()
{
	int input = 0;
	
	do
	{
		manu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("您已退出游戏,欢迎下次再来!\n");
				break;
			default:
				printf("您的选择有误,请重新输入:\n");
		}
	} while (input);
}
  1. manu()函数很简单,直接print打印即可。和我们之前的猜数字游戏是一样的思路

void manu(void)
{
	printf("=====================\n");
	printf("=====1:开始游戏=====\n");
	printf("=====0:退出游戏=====\n");
	printf("=====================\n");
}

这里写完,可以把game()函数先屏蔽掉看看效果,输入其他数值直接报错让玩家继续输,输入1直接break,循环继续,输入0就直接退出了。

在这里插入图片描述

2.2 game()的实现

game()函数实现这部分是游戏流程。game()也是放在test.c中。但是涉及到game函数具体实现都会放到game.c中去。
我们先表示棋盘:创建一个 3*3的二维数组,每个元素是一个char类型,'X’表示玩家1、'O’表示玩家2、'空格’表示空白。 我在game.c函数实现中设计了如果是和局的话用‘h’表示
因为只要游戏没有结束,就要一直下棋,所以要用到循环while

  • 游戏流程:
    (1)创建棋盘,并初始化~把所有位置都设为空格
    (2)打印棋盘
    while(1)
    {
    (3)玩家进行落子,让玩家来输入一组坐标(row,col),进行落子
    (4)进行判定,有任何一方获胜或者平局就break;
    (5)电脑进行落子~ 电脑随机落子
    (6)进行判定,有任何一方获胜或者平局就break;
    }
    (7)判定是哪一方获胜或者平局了
  • 代码实现
void game()
{
	//0.创建棋盘
	char chessBoard[ROW_MAX][COL_MAX] = { 0 };


	//1.初始化棋盘
	init(chessBoard, ROW_MAX, COL_MAX);


	//2.打印棋盘
	print(chessBoard, ROW_MAX, COL_MAX);

	char ret = ' ';//这个需要定义在while之外
	while (1)
	{
		//3.玩家下棋
		palyer(chessBoard, ROW_MAX, COL_MAX);
		print(chessBoard, ROW_MAX, COL_MAX);
		ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
		if ( ret!= ' ')
		{
			break;
		}

		//4.电脑下棋
		computer(chessBoard, ROW_MAX, COL_MAX);
		print(chessBoard, ROW_MAX, COL_MAX);
		ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
		if (ret != ' ')
		{
			break;
		}
	}

		if (ret == 'X')
		{
			printf("玩家获胜\n");
		}else if (ret== 'O')
		{
			printf("电脑获胜\n");
		}
		else if(ret== 'h')
		{
			printf("平局\n");
		}
		
	}

2.3 game.c函数实现

我们注意game.c和game.h是配套使用的,game.c中的函数需要在game.h中进行声明。
在这里插入图片描述
在.c文件中需要引入我们自己写的.h头文件,用的是“ ”,一般引用库函数用的< >

#include "game.h"

2.3.1 棋盘初始化

init(chessBoard, ROW_MAX, COL_MAX);
最简单的写法就是使用for循环直接遍历,给每个元素初始化为空格,后面有学到了用memset函数,直接初始化。

memset函数的头文件是<string.h> 。这个的使用可以自己搜下,比较简单有三个参数,第一个是要初始化的元素地址,我们这里就是数组首元素,第二个参数是要初始化的值,我们这里是空格,第三个就是要初始化的长度,

//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{
#if 0
	for (int row = 0; row < MAX_ROW; row++)
	{
		for (int col = 0; col < MAX_COL; col++)
		{
			chessBoard[row][col] = ' ';
		}
	}
#endif
	memset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}

2.3.2 棋盘打印

void print(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
思路:这个地方要考虑到打印我们的棋盘,否则全是空格就看不到任何输出。

void print(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)

{

		for (int row = 0; row < ROW_MAX; row++)
		{
			printf("+---+---+---+\n");
			printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);

		}
		printf("+---+---+---+\n");
}

2.3.2 玩家下棋

  • void palyer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
  • 思路:只要位置不为空就可以下棋,要注意限制玩家输入范围。
  • 代码实现
//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{
	
	printf("玩家下棋:\n");
	int x = 0;
	int y = 0;


	while (1)
	{
		printf("请输入要下棋的坐标:x y\n");
		scanf("%d %d", &x, &y);
		if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX)
		{
			printf("您的输入坐标有误请重新输入:\n");
			continue;
		}
		if (chessBoard[x][y] != ' ')
		{
			printf("您下的位置已经有棋子了。请重新输入:\n");
			continue;
		}
		else
		{
			chessBoard[x][y] = 'X';
			break;
		}
	}
}

2.3.3 电脑下棋

  • void computer(char chessBoard[ROW_MAX][COL_MAX], int row, int col)
  • 思路:电脑需要使用rand()函数生成随机数进行下棋,注意两个点,其一要限制输入0 1 2不能超过3,其二需要配合srand()函数一起使用,srand()需要用到时间戳time()函数,我们这个只需要调用一次放在了test函数中。这个在猜数字游戏里面也有实现过。rand函数的头文件是<stdlib.h> time函数的头文件是<time.h>
  • 代码实现
void test()
{
	int input = 0;
	srand((unsigned int)time(NULL)); //在循环外面
	do
	{
		manu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				//game();
				break;
			case 0:
				printf("您已退出游戏,欢迎下次再来!\n");
				break;
			default:
				printf("您的选择有误,请重新输入:\n");
		}
	} while (input);
}


//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{

	printf("电脑下棋:\n");
	while (1)
	{
		int a = rand() % ROW_MAX;
		int b = rand() % COL_MAX;
		if (chessBoard[a][b] != ' ')
		{
			continue;
		}
		chessBoard[a][b] = 'O';
		break;
	}
	
}

2.3.4 判断输赢

  • char is_Win(char chessBoard[ROW_MAX][COL_MAX], int row, int col)

  • 思路:这里之所以是char类型的返回值,是为了能够方便我们进行判断是谁赢了。判断的思路很简单,判断三行是否一致,三列是否一致,对角线是否一致,棋盘是否下满为和局,这里涉及到一个棋盘是否满的函数,这个函数我们只需要我们的game.c中使用,所以给添加了static,关闭它的外部属性,其他.c文件都不能调用我们这个函数。

  • 代码实现

static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROW_MAX; i++)
	{
		for (j = 0; j < COL_MAX; j++)
		{
			if (chessBoard[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}


char is_Win(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{

	//判断三行
	int i = 0;
	for (i = 0; i < row; i++)
	{
		if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]
			&& chessBoard[i][0] != ' ')
		{
		    	return chessBoard[i][0];
			
		}
	}

	//判断三列
	for (i = 0; i < col; i++)
	{
		if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]
			&& chessBoard[0][i] != ' ')
		{
			return chessBoard[0][i];
	
		}
	}

	//判断对角线

	if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]
		&& chessBoard[0][0] != ' ')
	{
		return chessBoard[0][0];
	}
	if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]
		&& chessBoard[0][2] != ' ')
	{
		return chessBoard[0][2];
	}

	if (is_Full(chessBoard))
	{
		return 'h';//和局
	}
	

	return ' ';//游戏继续
	
}

我在写这部分的时候各种出错,有时候是少了一个等号,有时候是用错了循环变量,调试真的很重要,当发现自己的错误的时候有时候真的哭笑不得,还好有调试功能,可以让我一步一步跟着代码走排查自己的问题。

3.代码实现

  • test.c

#include "game.h"


void manu(void)
{
	printf("=====================\n");
	printf("=====1:开始游戏=====\n");
	printf("=====0:退出游戏=====\n");
	printf("=====================\n");
}

void game()
{
	//0.创建棋盘
	char chessBoard[ROW_MAX][COL_MAX] = { 0 };


	//1.初始化棋盘
	init(chessBoard, ROW_MAX, COL_MAX);


	//2.打印棋盘
	print(chessBoard, ROW_MAX, COL_MAX);

	char ret = ' ';
	while (1)
	{
		//3.玩家下棋
		palyer(chessBoard, ROW_MAX, COL_MAX);
		print(chessBoard, ROW_MAX, COL_MAX);
		ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
		if ( ret!= ' ')
		{
			break;
		}

		//4.电脑下棋
		computer(chessBoard, ROW_MAX, COL_MAX);
		print(chessBoard, ROW_MAX, COL_MAX);
		ret = is_Win(chessBoard, ROW_MAX, COL_MAX);
		if (ret != ' ')
		{
			break;
		}
	}

		if (ret == 'X')
		{
			printf("玩家获胜\n");
		}else if (ret== 'O')
		{
			printf("电脑获胜\n");
		}
		else if(ret== 'h')
		{
			printf("平局\n");
		}
		
	}


void test()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		manu();
		printf("请输入你的选择:\n");
		scanf("%d", &input);
		switch(input)
		{
			case 1:
				game();
				break;
			case 0:
				printf("您已退出游戏,欢迎下次再来!\n");
				break;
			default:
				printf("您的选择有误,请重新输入:\n");
		}
	} while (input);
}


int main()
{


	test();

}
  • game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>

#define ROW_MAX 3
#define COL_MAX 3




//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX],int  row,int  col );

//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col);

//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col);

//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col);

//判断输赢
char is_Win(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col);
  • game.c


#include "game.h"

//棋盘初始化
void init(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{
	memset(chessBoard, ' ', ROW_MAX * COL_MAX * sizeof(char));
}

//棋盘打印
void print(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)

{

		for (int row = 0; row < ROW_MAX; row++)
		{
			printf("+---+---+---+\n");
			printf("| %c | %c | %c |\n", chessBoard[row][0], chessBoard[row][1], chessBoard[row][2]);

		}
		printf("+---+---+---+\n");
}

//玩家下棋
void palyer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{
	
	printf("玩家下棋:\n");
	int x = 0;
	int y = 0;


	while (1)
	{
		printf("请输入要下棋的坐标:x y\n");
		scanf("%d %d", &x, &y);
		if (x<0 || x>=ROW_MAX || y<0 || y>=COL_MAX)
		{
			printf("您的输入坐标有误请重新输入:\n");
			continue;
		}
		if (chessBoard[x][y] != ' ')
		{
			printf("您下的位置已经有棋子了。请重新输入:\n");
			continue;
		}
		else
		{
			chessBoard[x][y] = 'X';
			break;
		}
	}
}


//电脑下棋
void computer(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{

	printf("电脑下棋:\n");
	while (1)
	{
		int a = rand() % ROW_MAX;
		int b = rand() % COL_MAX;
		if (chessBoard[a][b] != ' ')
		{
			continue;
		}
		chessBoard[a][b] = 'O';
		break;
	}
	
}


static int is_Full(char chessBoard[ROW_MAX][COL_MAX])
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROW_MAX; i++)
	{
		for (j = 0; j < COL_MAX; j++)
		{
			if (chessBoard[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}

//判断输赢
//返回X表示玩家获胜
//返回O表示电脑获胜
//返回h表示和局
//返回j表示游戏继续

char is_Win(char chessBoard[ROW_MAX][COL_MAX], int  row, int  col)
{

	//判断三行
	int i = 0;
	for (i = 0; i < row; i++)
	{
		if (chessBoard[i][0] ==chessBoard[i][1] && chessBoard[i][1] == chessBoard[i][2]
			&& chessBoard[i][0] != ' ')
		{
		    	return chessBoard[i][0];
			
		}
	}

	//判断三列
	for (i = 0; i < col; i++)
	{
		if (chessBoard[0][i] == chessBoard[1][i] && chessBoard[1][i] == chessBoard[2][i]
			&& chessBoard[0][i] != ' ')
		{
			return chessBoard[0][i];
	
		}
	}

	//判断对角线

	if (chessBoard[0][0] == chessBoard[1][1] && chessBoard[1][1] == chessBoard[2][2]
		&& chessBoard[0][0] != ' ')
	{
		return chessBoard[0][0];
	}
	if (chessBoard[2][0] == chessBoard[2][2] && chessBoard[2][2] == chessBoard[0][2]
		&& chessBoard[0][2] != ' ')
	{
		return chessBoard[0][2];
	}

	if (is_Full(chessBoard))
	{
		return 'h';//和局
	}
	

	return ' ';//游戏继续
	
}

http://www.kler.cn/a/459725.html

相关文章:

  • Windows 11 系统中npm-cache优化
  • 分布式微服务项目___某污水处理项目
  • java class类对象 加载时机
  • xadmin后台首页增加一个导入数据按钮
  • QT-------------多线程
  • laravel部署到云服务器上,除了首页之外,区域页面找不到路由
  • Maven:Java项目构建与管理的利器
  • 云端-IPv4 VRRP 单备份组配置实验
  • TinaCMS: 革命性的开源内容管理框架
  • 2024 开放原子开发者大会活动回顾|瀚高 IvorySQL 开源数据库在国产软件的开源实践
  • Github 2024-12-27 Java开源项目日报Top10
  • 微信小程序 单选多选radio/checkbox 纯代码分享
  • 【前端,TypeScript】TypeScript速成(五):对象类型
  • MATLAB中使用rationalfit函数进行有理函数拟合的步骤
  • 网络入侵检测系统(IDS)的安装部署
  • 使用uWSGI将Flask应用部署到生产环境
  • 指针与数组:深入C语言的内存操作艺术
  • UniApp 页面布局基础
  • Java 8 及经典面试题全解析
  • 深入探索:使用Java爬虫获取亚马逊商品图片
  • 数据库高安全—openGauss安全整体架构安全认证
  • 自动化文档处理:Azure AI Document Intelligence
  • 保姆级教程Docker部署ClickHouse镜像
  • 阿里云大模型ACP高级工程师认证模拟试题
  • Mysq学习-Mysql查询(4)
  • Substrate Saturday 回顾:如何利用 Polkadot Cloud 扩展 Solana 网络服务?