基于C语言 --- 自己写一个扫雷小游戏

news2024/9/24 21:21:48

C语言程序设计笔记---020

  • 初阶扫雷小游戏(开源)
    • 1、arr_main2.c程序大纲
    • 2、arr_game2.h
    • 3、arr_game2.c
      • 3.1、 自定义初化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )
      • 3.2、 自定义布置雷函数 SetMine( )
      • 3.4、 自定义排查雷函数 FindMine( )
    • 4、结束语

初阶扫雷小游戏(开源)

前言:
游戏规则:
(1)、在打印的数组棋盘里,输入坐标,排雷。
(2)、坐标格式:x(空格) y
(3)、x横坐标,y竖坐标
(4)、当布置的雷,被排除完,则判定胜利
如图所示
在这里插入图片描述

采用模块化编写
arr_game2.c执行主要逻辑程序
arr_game2.h存放头文件或函数声明等程序
arr_main2.c放主函数逻辑程序

1、arr_main2.c程序大纲

首先,从以往玩游戏的经验来谈,我们需要为游戏写一个游戏开始菜单,由玩家选择是否开始游戏。
这里可以借助所学的menu( )自定义函数,设计一个简易的菜单

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

当我们选择1,则开始游戏;当选择0,则退出游戏。
那么就得思考,如何对玩家得选择进行判定
1.利用 scanf( ) 函数获取输入值,将获取的值,借用 do while 循环语句和switch( )选择语句,进行下一步。
2.当选择1,开始游戏则执行game()自定义,游戏主逻辑执行程序
3.当选择0,switch中 进入case 0 : 的入口,执行退出游戏,并且 do while( ),判定为0,则退出程序
4.当玩家误选择非法数值,则default : 提示玩家输入错误

int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("\n*********** 三子棋游戏开始 *************\n\n");
			game();//游戏执行逻辑函数
			break;
		case 0:
			printf("\n退出游戏\n");
			break;
		default:
			printf("\n选择错误请重新选择\n\n");
			break;
		}

	} while (input);

接下来,主要阐述game( )函数内容,游戏的执行逻辑
1.当玩家选择1,开始游戏后,会显示整个以号展现的99棋盘,并且显示出行号与列号,方便玩家输入坐标。
如何实现9*9棋盘的显示呢?
(1)、因为棋盘是一个平面,平面由一条条线组成,线又由一个个点组成,利用所学的数组知识可以联想到,棋盘不过是由一个个字符拼接而成。
(2)、所以首先得定义和初识化两个大小相等,且类型相同的数组(mine和show),mine[ ][ ]数组负责布置雷和排查雷,show[ ][ ]负责将玩家在mine[ ][ ]数组所排查的雷显示出来,即显示排查情况。
(3)、自定义初识化函数 InitBoard( ) ,自定义显示棋盘函数 DisPlayBoard( ) ;
(4)、函数的参数,可想而知,需要数组名(board) — 首元素的地址指定需操作的数组,需要行(ROW)和列(COL)指定操作的元素或坐标或地址;

void game()
{
	//定义两个大小相等,类型相同的数组棋盘
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初识化棋盘
	char set = 0;
	InitBoard(mine, ROWS, COLS, '0');//初识化布置雷棋盘
	InitBoard(show, ROWS, COLS, '*');//初识化排查雷棋盘
	//显示棋盘
	//DisPlayBoard(mine,ROW,COL);//注意:显示只需显示玩家看的9*9棋盘,参数用 ROW 和 COL
	DisPlayBoard(show, ROW, COL);

2.当我们完成棋盘的初识化和显示后,我们需要将雷布置进去,当雷布置好后,玩家才可以排雷;
所以就得写一个自定义布置雷和自定义排查雷的函数,直到玩家踩雷或排查完雷结束。
(1)、自定义布置雷函数 SetMine( ) ;
(2)、自定义排查雷函数 FindMine( ) ;
3.如何判断游戏结束?
那么很容易思考到,玩家可不断的进行排雷,就是反复的调用玩家排雷函数和显示函数,同时不停的判断每一次排雷是否踩中地雷或排完地雷。所以需要一个循环来实现,这里就用while循环,实现不停的下棋。
但是,不停的下棋,始终在死循环,那么就思考利用,break跳出循环,那么跳出的while函数的条件是什么呢?我们可以想到,如99的棋盘,不断的排雷,棋盘可存放的总数一共才99个数,还放了10个雷,那么我们只需要判断,我们排雷的次数,是否等于总数减去我们放的雷,当相等时说明,雷被排完了,游戏结束。

void game()
{
	//定义两个大小相等,类型相同的数组棋盘
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初识化棋盘
	char set = 0;
	InitBoard(mine, ROWS, COLS, '0');//初识化布置雷棋盘
	InitBoard(show, ROWS, COLS, '*');//初识化排查雷棋盘
	//显示棋盘
	//DisPlayBoard(mine,ROW,COL);//注意:显示只需显示玩家看的9*9棋盘,参数用 ROW 和 COL
	DisPlayBoard(show, ROW, COL);
	//布置雷
	SetMine(mine ,ROW,COL);//雷只需要布置在9*9棋盘
	//排查雷
	FindMine(mine,show, ROW, COL);//首先,需要mine数组中排查,布置的雷,然后将排查出的雷,放置在show数组中显示出来,且雷的布置和显示棋盘均在9*9棋盘

arr_main.c程序大纲展示

#include "arr_game2.h"

//显示游戏菜单
void menu()
{
	printf("*****************************************\n");
	printf("************* 1.play game ***************\n");
	printf("************* 0.game over ***************\n");
	printf("*****************************************\n");
}

void game()
{
	//定义两个大小相等,类型相同的数组棋盘
	char mine[ROWS][COLS] = { 0 };
	char show[ROWS][COLS] = { 0 };
	//初识化棋盘
	char set = 0;
	InitBoard(mine, ROWS, COLS, '0');//初识化布置雷棋盘
	InitBoard(show, ROWS, COLS, '*');//初识化排查雷棋盘
	//显示棋盘
	//DisPlayBoard(mine,ROW,COL);//注意:显示只需显示玩家看的9*9棋盘,参数用 ROW 和 COL
	DisPlayBoard(show, ROW, COL);
	//布置雷
	SetMine(mine ,ROW,COL);//雷只需要布置在9*9棋盘
	//排查雷
	FindMine(mine,show, ROW, COL);//首先,需要mine数组中排查,布置的雷,然后将排查出的雷,放置在show数组中显示出来,且雷的布置和显示棋盘均在9*9棋盘

}

int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();//显示游戏菜单
		printf("请输入;>");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			printf("\n************ 扫雷游戏开始 **************\n\n");
			game();//游戏主逻辑函数
			break;
		case 0:
			printf("\n退出游戏\n\n");
			break;
		default:
			printf("\n输入错误,请重新输入\n\n");
			break;
		}
	} while (input);
	return 0;
}

2、arr_game2.h

用于存放所自定义的函数和头文件等声明的程序
通俗易懂,就不多赘述,详见代码注释的说明。

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

//定义显示的棋盘show大小
#define ROW 9
#define COL 9

//定义外围的棋盘mine大小
#define ROWS ROW+2
#define COLS COL+2

//宏定义雷的个数
#define ESAY_MINE 10

//初识化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);

//显示棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col);

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col);

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS],int row, int col);

3、arr_game2.c

用于存放对 arr_main.c 程序大纲做提到的函数进行封装,实现具体的功能的程序
说明:基于arr_main2.c 程序大纲逻辑对代码进行讲解
注意:这里均以99的棋盘为例哦,但是我们需要考虑到边界的元素,当我们输入的坐标在边缘时,如何计算周围的雷的数量呢?
所以我们在arr_game2.h中,宏定义的数组大小可以知道,通过引用比9
9数组大一圈的数组覆盖9*9的棋盘即可。所以我们将引用两个大小相等,类型相同的数组。
为了方便理解,简单画个图:
在这里插入图片描述

3.1、 自定义初化函数 InitBoard( ) 和 自定义显示函数 DisPlayBoard( )

首先,根据需求我们需要一个棋盘才可以正常的扫雷.
如何让棋盘初识化和显示呢?
1.根据所学的二维数组知识,便可以知道,当我们遍历二维数组的每一个元素,使得填充为需要的字符,便可以由InitBoard( ) 达到效果。然后我们将mine数组放置字符 ’ 0 ',将show数组放置字符 ’ * ’ 。
补充:我们以mine数组填充字符0表示不是雷,以字符1表示为雷。以show字符填充字符 ✳号隐藏雷的位置,由玩家输入坐标进行逐步排雷。
注意因为我们使用的是两个大小相等,类型相同的数组,所以增加一个字符型变量,以传参为我们需要的字符

//初识化棋盘
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < rows; i++)//下标0~10
	{
		for (j = 0; j < cols; j++)
		{
			board[i][j] =  set;//由set参数决定显示的棋盘
		}
	}
}

//显示棋盘
void DisPlayBoard(char board[ROWS][COLS], int row, int col)
{
	int i = 0;
	int j = 0;
	printf("\n************** 扫雷 *************\n");
	//打印行号、列号,方便输入坐标
	for (i = 0; i <= col; i++)//打印行号
	{
		printf("%d ",i);
	}
	printf("\n");
	for (i = 1; i <= row; i++)
	{
		printf("%d ",i);//打印列号
		//打印数组元素
		for (j = 1; j <= col; j++)
		{
			printf("%c ",board[i][j]);
		}
		printf("\n");
	}
	printf("\n************** 扫雷 *************\n\n");
}

如图所示
在这里插入图片描述

3.2、 自定义布置雷函数 SetMine( )

我们定义坐标变量,并使用随机值rand函数约束坐标范围,将雷的坐标以while循环的方式存放进mine数组中,当布置一个雷,雷则少一个,所以直接以雷的数量作为循环判断条件即可。

//布置雷
void SetMine(char mine[ROWS][COLS], int row, int col)
{
	int count = ESAY_MINE;
	while (count)//由雷的数量,布置一个少一个,作为判定的条件
	{
		int x = rand() % row + 1;
		int y = rand() % col + 1;
		if (mine[x][y] == '0')//是否被占用
		{
			mine[x][y] = '1';
			count--;
		}
	}
}

如图所示
在这里插入图片描述

3.4、 自定义排查雷函数 FindMine( )

那么接下来,我们如何进行排查雷呢?
首先,我们由玩家循环输入将排查的坐标(x,y),然后判断输入的坐标是否超出9*9扫雷棋盘的范围,若超出,可打印提示语句,重新输入。当符合范围,就判断是否踩中了雷,若踩中雷,break跳出循环,游戏结束。当玩家没有踩中雷,则显示输入坐标处(x,y),周围雷的数量情况。
所以思考怎么计算坐标处周围雷的数量呢?
当然不难想到,当我们知道了一个数组的元素坐标时,可通过简单的加减运算,即可得知周围坐标。
如图所示
在这里插入图片描述
当我们知道了输入坐标周围的元素坐标,那么就可以通过该对应的坐标提取该元素的值,为字符0还是为字符1,联系前文中提到的0/1(非雷/雷),就可知我们mine数组填充0/1来作为是否为雷的巧妙之处了,因为我们计算周围的雷的数量只需要将该对应的元素值加起来就得到了数量情况了。
但是值得注意的是:我们自始自终mine和show数组都是字符型数组,所以在进行加减运算时,要区分字符与十进制数值的关系。

众所周知:
字符 ‘0’ - ‘0’ = 0
‘5’ - ‘0’ = 5
‘9’ - ‘0’ = 9
所以我们将周围元素加一起,再减去8* ‘0’即可。

//返回雷的数量
int  GetMine(char mine[ROWS][COLS],int x,int y)
{
	return (mine[x-1][y-1] + mine[x][y-1] + mine[x+1][y-1] + mine[x+1][y] + mine[x+1][y+1] + mine[x][y+1] + mine[x-1][y+1] + mine[x-1][y]) - 8 * '0';
}

最后通过GetMine( )获取的雷的数量,ret再将它加上一个字符‘ 0 ’,赋值给shou数组,然后作为DisPlayBoard( )的参数,打印出来即可。

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	//如何判断输赢?
	while (1)
	{
		printf("请输入排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <=  col)
		{
			if (mine[x][y] == '1')
			{
				printf("\n很遗憾,您踩中雷了\n\n");
				DisPlayBoard(mine,ROW,COL);
				break;
			}
			else//没猜中雷,返回雷的数量
			{
				int ret = GetMine(mine, x, y);//返回雷的数量
				show[x][y] = ret + '0';//放置再在show数组显示
				DisPlayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("\n输入非法,请重新输入\n");
		}
	}
	if (win == row * col - ESAY_MINE)
	{
		printf("恭喜,您已经成功排完雷\n");
		DisPlayBoard(mine, ROW, COL);

	}
}

但是我们调试发现:
当玩家没有踩中雷时,一直进行排雷,那么如何判断输赢游戏结束呢?
在上文arr_main2.c大纲中提到,当棋盘所有的雷被排查完游戏结束。
即理解为:当棋盘中可以输入排查的坐标位置数量win,当win 小于了row*col(棋盘可下棋坐标棋子的总数量) 减去 地雷数量就跳出循环结束游戏,判定胜利
所以优化代码:

//排查雷
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
	int x = 0;
	int y = 0;
	int win = 0;
	//如何判断输赢?
	//当棋盘所有的雷被排查完
	//即理解为:当棋盘的可排查的棋子坐标位置,win 小于了row*col(棋盘可下棋坐标棋子的总数量) - 地雷数量就跳出循环结束游戏,判定胜利
	while (win <row*col - ESAY_MINE)
	{
		printf("请输入排查的坐标:>");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <=  col)
		{
			if (mine[x][y] == '1')
			{
				printf("\n很遗憾,您踩中雷了\n\n");
				DisPlayBoard(mine,ROW,COL);
				break;
			}
			else//没猜中雷,返回雷的数量
			{
				int ret = GetMine(mine, x, y);//返回雷的数量
				show[x][y] = ret + '0';//放置再在show数组显示
				DisPlayBoard(show, ROW, COL);
			}
		}
		else
		{
			printf("\n输入非法,请重新输入\n");
		}
	}
	if (win == row * col - ESAY_MINE)
	{
		printf("恭喜,您已经成功排完雷\n");
		DisPlayBoard(mine, ROW, COL);

	}
}

最后我们将arr_game2.h中宏定义的雷(ESAY_MINE)的数量改为80,来证明while跳出的条件是正确的。
如图所示
在这里插入图片描述

4、结束语

相信通过这样一个扫雷的小游戏,更具掌握了对数组的操作以及对自定义函数的深刻认识;
如果觉着文章对您有所帮助,请不要吝啬的一赞三连哦,谢谢阅读,不足之处还请多多指教。

扫雷源码获取链接: 扫雷小游戏初阶

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

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

相关文章

Redis安装部署(基于windows平台)

redis简介 键值对存储数据库是NoSQL数据库的一种类型&#xff0c;也是最简单的NoSQL数据库。顾名思义&#xff0c;键值对存储数据库中的数据是以键值对的形式来存储的。常见的键值对存储数据库有Redis、Tokyo Cabinet/Tyrant、Voldemort以及Oracle BDB数据库。 Remote Diction…

1.4 信息安全管理

数据参考&#xff1a;CISP官方 目录 信息安全管理基础信息安全管理体系信息安全管理实践 一、信息安全管理基础 1、信息 信息是一种资产&#xff0c;与其他重要的业务资产一样&#xff0c;对组织业务必不可少&#xff0c;因此需要得到适当的保护。 2、信息的价值 企业…

数据结构和算法入门(时间/空间复杂度介绍--java版)

数据结构和算法入门&#xff08;时间/空间复杂度介绍–java版&#xff09; write in front 作者&#xff1a; 向大佬学习 专栏&#xff1a; 数据结构&#xff08;java版&#xff09; 作者简介&#xff1a;大二学生 希望能学习其同学和大佬的经验&#xff01; 本篇博客简介&…

定时任务调度 xxl-job

框架地址 https://gitee.com/jiaruiguo/xxl-job.git项目说明 调度管理系统 xxl-job-admin 定时任务实现系统 普通系统&#xff1a; xxl-job-executor-sample-frameless 微服务系统&#xff1a;xxl-job-executor-sample-springboot 配置说明 工程名&#xff1a;xxl-job-execut…

中国农村程序员学习此【JavaScript教程】购买大平层,开上帕拉梅拉,迎娶白富美出任CEO走上人生巅峰

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录 在 Switch 语句添加多个相同选项从函数返回布尔值--聪明方法undefined创建 JavaScript 对象通过点号表示法访问对象属性使用方括号表示法访问对象属性通过变量访问对象属性给 JavaScript 对象添加新属性删除…

AD21 PCB设计的高级应用(八)Draftsman的应用

&#xff08;八&#xff09;Draftsman的应用 1.创建Draftsman文档2.Draftsman页面选项设置3.放置绘图数据3.1 装配图3.2 板制造图3.3 钻孔图和钻孔列表3.4 图层堆栈图例3.5 BOM3.6 标注、注释、测量尺寸 4.文档输出4.1 打印或者导出为PDF4.2 添加到Output job Draftsman 是为电…

windows基础命令

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一.目录和文件的操作 1.cd 命令 切换到d盘 2.目录分为相对路径和绝对路径 3. dir命令 用于显示目录和文件列表 4. md 或 mkdir 创建目录 5. rd 用于删…

【编程语言 · C语言 · 共用体】

【编程语言 C语言 共用体】https://mp.weixin.qq.com/s?__bizMzg4NTE5MDAzOA&mid2247491502&idx1&snd531f724641b18619225de4bbcd02998&chksmcfade357f8da6a41f514ba72d817cc029f8f2a89d3753bfe5c547801abb3d2e080554e67d677&payreadticketHJqAIlk_6GWs…

Uncaught SyntaxError: ‘‘ string literal contains an unescaped line break

今天在修改前端页面的时候&#xff0c;页面报错了&#xff0c;提示了这个信息 Uncaught SyntaxError: string literal contains an unescaped line break 问题指向这行代码&#xff0c;这就是通过JS渲染一个easyui的搜索框&#xff0c;仔细确认之后&#xff0c;发现没有任何问…

Go学习第一天

闲聊两句 从事java后端开发8年多&#xff0c;期间也曾零星看过Go语言、Python、Erlang等等&#xff0c;但都未曾认真学习过&#xff0c;恰好公司最近项目需要&#xff0c;之前用Go开发的项目因为同事离职&#xff0c;暂未人来接手&#xff0c;所以老大就找到我和另外一个同事&…

算法自学__背包动态规划

例1 P5020 [NOIP2018 提高组] 货币系统 题目描述 在网友的国度中共有 n n n 种不同面额的货币&#xff0c;第 i i i 种货币的面额为 a [ i ] a[i] a[i]&#xff0c;你可以假设每一种货币都有无穷多张。为了方便&#xff0c;我们把货币种数为 n n n、面额数组为 a [ 1.. …

unity 使用Vuforia扫描物体( ModelTarget 模型目标)

1、下载vuforia插件vufora 2、下载模型生成器Model Target Generator 3、将vuforia插件导入到unity &#xff0c;我使用的unity是2021版本&#xff0c;导出插件时&#xff0c;只显示有两个文件&#xff0c;导入后&#xff0c;会有一个弹框 让更新插件&#xff0c;点击updata&am…

【编程语言 · C语言 · calloc和realloc】

【编程语言 C语言 calloc和realloc】https://mp.weixin.qq.com/s?__bizMzg4NTE5MDAzOA&mid2247491544&idx1&sn72d8f9931cfa7ce7441a3248475ab619&chksmcfade321f8da6a374a5935bb46441a03a007c0589db6b8afa8c1991854d632a3201553e37b0b&payreadticketHGy…

[算法很美打卡第四天] 字符串篇(中)

文章目录 压缩字符串代码 判断两字符串的字符集是否相同代码 旋转词代码 反转单词代码 回文串验证代码 去掉字符串中连接出现的k次的0代码 压缩字符串 代码 package 每日算法学习打卡.算法打卡.八月份;public class test1 {public static void main(String[] args) {String s …

替换linux的文泉驿正黑fonts-wqy-zenhei字体 替换linux默认中文字体

WSL 怎么替换 linux 的文泉驿正黑 fonts-wqy-zenhei 字体 WSL 怎么替换 linux 默认中文字体 在 wsl 中默认是没有 gnome 界面或者 xface 的&#xff0c;但是我需要使用 wsl 开发 electron 或者使用 chrome 浏览器。这个时候系统就会调用默认的系统字体了。 我使用的是 debian…

国产分布式数据库——TDSQL性能分析工具

一、TDSQL概述 TDSQL是腾讯研发的一款兼容MySQL协议的国产分布式数据库&#xff0c;适用于大并发、高性能、大容量的OLTP类场景。TDSQL分为集中式和分布式版本&#xff0c;分布式版可支持分布式事务&#xff0c;但性能不如单机事务&#xff0c;性能会有一定的损耗&#xff0c;…

Android系统的进程管理(创建->优先级->回收)

一、进程的创建 1、概述 Android系统以Linux内核为基础&#xff0c;所以对于进程的管理自然离不开Linux本身提供的机制。例如&#xff1a; 通过fork来创建进行通过信号量来管理进程通过proc文件系统来查询和调整进程状态 等 对于Android来说&#xff0c;进程管理的主要内容…

EMC VNX1系列存储电池状态说明

SPS电池正常的状态为“Present”。 SPS电池故障时的状态为“Faulted”。 更换SPS后&#xff0c;SPS开始充电&#xff0c;此时状态显示为“Not Ready”状态。 充电完成后显示为Present状态。如果充电完成后状态前面有“F”标记&#xff0c;则需要重启对应的控制器以更新SPS…

2023年最新智能优化算法之——切诺贝利灾难优化器 (CDO),附MATLAB代码和文献

切诺贝利灾难优化器Chernobyl Disaster Optimizer (CDO)是H. Shehadeh于2023年提出的新型智能优化算法。该方法是受到切尔诺贝利核反应堆堆芯爆炸而来的启发。在CDO方法中&#xff0c;放射性的发生是由于核的不稳定性&#xff0c;核爆炸会发出不同类型的辐射。这些辐射中最常见…

vue2、vue3生命周期详解以及对比

文章目录 对比vue2-vue3vue3生命周期生命周期的主要阶段详情 vue2 生命周期生命周期钩子函数 总共11个 常用的8个按照这四个阶段我们对应有八个生命周期钩子函数vue生命周期使用场景 对比vue2-vue3 如果熟悉vue2的话&#xff0c;vue3信手拈来&#xff0c;看图 vue3生命周期 on…