我们游戏总体的思路如下:
目录
1.游戏总体的逻辑 以及 开始操作:game.c
2.编写游戏中所需要用到的函数:work.c
初始化棋盘
打印并制作棋盘
开始下棋
玩家下棋:
电脑下棋:
如何判断输赢
在这里我们这样判断不同的情况
判断行:
判断列:
判断对角线:
3.我们自己定义的头文件game.h
总览三子棋代码
game.c:
work.c:
game.h:
1.游戏总体的逻辑 以及 开始操作:game.c
编写一个选择界面:
menu()
{
printf("************************\n");
printf("*********1. play********\n");//注意我们这里用 1 表示开始玩 而 非零 在vs表示为真
printf("*********0. exit********\n");//0表示为假 这样也方便了我们后续操作的书写
printf("************************\n");
}
因为要玩游戏嘛 这个游戏我们肯定无论如何都要运行一次 所以我们采用do-while循环 这样游戏就肯定会让你判断一次是否开始游戏了! 大家来看:
int main()
{
int input;
srand((unsigned int)time(NULL));//这里要用到随机值这个知识点后面会给大家讲到
do
{
menu(); //把menu()放在循环里面也是为了当游戏已经判断出输赢
printf("请选择:>"); //当work
scanf("%d", &input);
switch (input)
{
case 0:
{
printf("您已退出游戏!");
break;
}
case 1:
{
work();
break;
}
default:
{
printf("输入错误请重新输入!\n");
printf("------------------------\n");//这里之所以打出一条线来 是为了美观 大家看
break; //下图
}
}
} while (input);
return 0;
}
? ?这里 input 的用法很关键 也很特别 大家看 while 循环?和?switch选择语句所用到的判断条件都是
input 当你选择 0?时?因为break 跳出的是 switch选择语句?出来后进行 while?的判断 0 为假 程序自然就结束了
? ?当你选择的是 1 时 work()工作完返回来 break 跳出?来到 while 的判断 为真 继续循环
再次显示menu() 的界面 给玩家选择是否再玩一局!
怎么样? 这样的设计是不是很巧妙
这样时不是看上去美观些许
到这里游戏开始操作的程序就是这些了 让我们继续!
初始化棋盘
棋盘的初始化我们可以使用memset函数
memset函数:
memset()函数原型是extern void *memset(void *buffer, int c, int count) ?????? buffer:为指针或是数组,
????????????? c:是赋给buffer的值,
?????? count:是buffer的长度.(摘自 落叶随风)
memset(board, ' ', sizeof(board));//初始化棋盘
这里我们初始化棋盘 是为了后续棋盘的打印 如果不初始化棋盘就会是这样的
因为棋盘的二维数组是一个局部变量 里面的值都是随机的 所以打印出来才会出现这样的现象!?
打印并制作棋盘
在制作棋盘前 我们首先得了解 棋盘长什么样子
大家可以这样?看看 其中黄色和蓝色各是一种 种类 大家也注意到蓝色最后一排是没有的
其中黄色 由这些成分组成? ?%c? |? ?每打印一个 空格+%c 就要打印一个 | 但是最后一列没有
蓝色部分 由这些成分组成? --- | 每打印三个 -?就要打印一个 | 同样最后一列没有
在制作棋盘之前我们要在我们定义的 game.h 里声明这个函数:
#define ROW 3
#define COL 3//因为程序中要多次应用到行和列的数字 所以我们把它define
void display_borad(char board[ROW][COL], int row, int col);//打印并制作棋盘
//因为只是拿这个函数用于打印并制作棋盘并不需要它返回什么 所以我们定义为 void 类型
//传入我们初始化好的二位数组 行 列
game.c? 里面是这样调用函数的
display_borad(board, ROW, COL);//打印并制作棋盘
好的现在已经开始写我们的代码:
void display_borad(char board[ROW][COL], int row, int col)
{
int i;
int j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++) //打印黄色的部分 不会打印最后一列的 | 所以当我们的j循环到
{ //最后列就让他不打印所以 用 if 语句来判断是否打印
printf(" %c ", board[i][j]);
if (j < col - 1)printf("|");
}
printf("\n"); //黄色部分结束后要进行换行
if (i < row - 1) //这里的if 语句 是用来判断整个蓝色部分打不打印 而我们最后
{ //一行是不打印的所以我们同样也用 if语句 来进行判断
for (j = 0; j < col; j++)
{
printf("---"); //这里是打印蓝色的部分 而当我们打印到最后也与之前同理 用
if (j < col - 1)printf("|");//用if 语句来进行判断 是否打印
}
printf("\n");//同样这里也是需要换行的
}
}
}
//大家可以对照着理解一下
%c | %c | %c
----|----|---- //这里面的-字体好像没有我的vs的大 所以写了4个 哈哈哈哈哈
%c | %c | %c
----|----|----
%c | %c | %c
好的这样我们的棋盘就制作并很好的打印出来了
开始下棋
因为我们下棋是和电脑下棋 而下棋肯定是你走一步 我走一步 所以呢 这肯定是一个循环的过程 而循环结束的标志就是其中一方赢了 然后break出来 并打印结果 这就是我们总体的一个思路 让我们来看看怎么实现它吧
玩家下棋:
当然在开始前我们还是需要在我们定义的 game.h 里面先声明一下这个函数的
void player_move(char board[ROW][COL], int row, int col);//玩家下棋
接下来是我们程序的运行:
//玩家走
void player_move(char board[ROW][COL], int row, int col) //我们设置为玩家的棋子是符号 '*'
{
int x, y;
printf("请选择您的棋子位置:>");
//判断棋子有效性
while (1) //这里设置循环的目的是为了当我们输入的坐标无效时 让玩家循环回来重新输入
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= ROW && y >= 1 && y <= COL) //ROW=3 COL=3
{
if (board[x - 1][y - 1] == ' ') //因为玩家可能并不知知道我们的棋盘(二维数组)的
{ //下标是从 0 开始的 所以玩家输入的数据范围可能是
board[x - 1][y - 1] = '*'; //1~3 所以玩家输入进去的数字 是比我们的下标的数据
break; //范围大 1 的 所以我们这里要减 1
}
else
{
printf("您输入的位置已经被占用 请重新输入!\n"); //这里是为了保证我们输入的坐标
} //里面是空的 所以我们用 if 判断
}
else
{
printf("您输入的位置无效 请重新输入!\n"); //判断棋子的有效性
}
}
}
因为当我们的玩家下完棋后 我们肯定要给他看一看他下的那一步 棋盘现在是什么样子的
同样电脑下完棋我们也要显示棋盘是什么样子
先给大家看看这个是什么样子的吧 后面会仔细的说清楚 嘿嘿
//开始下棋
while (1)
{
char ret;
player_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C') //判断输赢
{ //*-玩家赢
if (ret == '*') //#-电脑赢
{ //Q-平局
printf("恭喜你赢了!\n"); //C-游戏继续
printf("----------------\n");
break;
}
else if (ret == '#')
{
printf("很遗憾!电脑赢了\n");
printf("----------------\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
com_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C')
{
if (ret == '*')
{
printf("恭喜你赢了!\n");
break;
}
else if (ret == '#')
{
printf("很遗憾!电脑赢了\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
}
}
电脑下棋:
在这里电脑下棋 我们给他设置成随机的数字 所以要用到 srand函数 和 rand函数
这里就给大家讲讲这个随机的数字怎么生成的
rand函数 是用来生成一个随机数? 头文件是<stdio.h> 返回类型是整型
返回 0~Rand_Max(32767)中的一个数
srand函数相当于是给rand函数生成一个起始点 就是让rang函数不再是从0开始到Rand_max 如果你给rand函数设置的起始点是固定的那么好几次生成的随机数
srand(1);
int x = rand();
for (int i = 0; i < 5; i++)//这里五次输出 都是 41
{ //如果说你在使用rand函数之前没有使用srand函数 那么结果和srand(1)
printf("%d\n", x); //是一样的
}
所以我们要给srand函数里传入 一个变化的值 这个时候就要用到 time函数
time函数:
time函数这样定义的 这个函数的返回的类型是 time_t (就好比是int char)这个类型是一个无符号整型? 但是不同平台这个类型的定义是不同的 我用的是 vs 而在vs里面是一个有符号的长整型?
?所以这里用的时候记得 给time函数进行强制转换 (如果你用的也是vs的话)?
因为srand函数要求的是 我们给它传入的数要是一个无符号的数
其中time_t它返回从1970年1月1日零时零分零秒到目前为止所经过的时间
最后有一点 在我们使用这个函数之前 我们还要应用
srand函数:
这个函数他是这样的?void?srand(unsigned seed)
他要求传入一个无符号的数?
因为我们要让这个随机数是变化的 而rand函数 srand函数 time函数通常结合在一起使用
最终拿出来就是这样的 srand((unsign int)time(NULL)?)? NULL的意思就是表示空的意思
你可以写 0?
因为我们的主函数是一定会执行的所以我们就把 srand函数放到主函数里面去?
对了 在使用它们之前出了 引头文件<time.h>还有一个<stdlib.h>哦!?
好的 说完这个我们就可以开始编写 电脑下棋的部分了
同样我们还是要在我们定义的game.h里面先声明
void com_move(char board[ROW][COL], int row, int col);//电脑下棋
让我们看看work.c该怎么写:
void com_move(char board[ROW][COL], int row, int col)
{
printf("电脑下:>\n");
while (1)
{
int x = rand() % row; //这里我们设定的是3×3的棋盘 这里它模3 那么得到的结果就是在0~2之间
int y = rand() % col; //如果定义的是4×4 也是一样的道理
if (board[x][y] == ' ') //电脑也是需要判断选出的坐标是否被占用的 但是呢 不需要提示
{ //毕竟我们也不能提示我们的电脑看啊
board[x][y] = '#';
break;
}
}
}
到这里我们的下棋部分就写完了 接下来是我们的判断输赢部分
如何判断输赢
同样我们还是要在我们的game.h里面声明一下
char is_win(char board[ROW][COL], int row, int col);//判断输赢
//这里我们之所以定义返回类型是字符型 是让我们在判断输赢的根据不同的情况返回不同的字符
//然后进一步判断是哪一方获得了胜利
大家玩过三子棋的都知道 我们的三子棋判断输赢需要判断 行 、列 和 对角线
在这里我们这样判断不同的情况
//*-玩家赢
//#-电脑 要注意什么情况返回哪个字符 这里我用的是这样的方法
//Q-平局 请大家往下看!
//C-游戏继续
判断行:
int i, j;
for (i = 0; i < row; i++)
{
int flag = 0;
for (j = 0; j < col - 1; j++)//因为每次判断都和同一行的下一个 所以比较的时候 次数要比
{ //列数小 1
if (board[i][j] == board[i][j + 1]&&board[i][j]!=' ')
{ //应为每次下棋不管 是电脑还是玩家 我们都要检查是否有
flag++; //人胜利 所以检查的时候有些位置还是空的 这些肯定三个
} //相等的话是不可取的 所以空的地方即使相等不能算进去
}
if (flag == ROW - 1) //这里我们定义的flag如果等于了比较的次数 就说明两次的比较
{ //都是相等的 这一行的三个就是相等的
if (board[i][j] == '*')
return '*'; //循环结束后坐标是放在这一行中间的位置 所以我们直接看
else //这个的字符是什么 就可以判断出是谁赢了
return '#';
}
}
判断列:
其实行和列里面比较的思路是一样的 只不过
比较行 是行变化 拿同行中每一列进行比较
比较列 是列变化 拿同列中每一行进行比较
for (j = 0; j < col; j++)
{
int flag = 0;
for (i = 0; i < row - 1; i++) //这些地方的道理是和比较行的道理是相同的
{
if (board[i][j]==board[i+1][j]&&board[i][j]!=' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*') //这里最后循环后的到的就是一列中间那个位置
return '*';
else
return '#';
}
}
判断对角线:
大家都知道一个四边形有两条对角线 而两条对角线的起点和终点都是不同的 所以内 他们的循环过程肯定是不同的首先我们看第一条:
第一条:
int flag = 0; //因为之前的flag是定义在循环里面 所以在循环外面是不能够用的 所以要重
for (i = 0, j = 0; i < row - 1 && j < col - 1; i++, j++)//新定义
{
if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
flag++; //因为对角线的坐标 无论是横坐标还是竖坐标都是变换的 所以我把他们的循环
} //设置在了一起 另一条对角线也是一样的道理 只是起始点和终点不同罢了
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
第二条:
flag = 0;
for (i = 0, j = col - 1; i < row - 1 && j>0; i++, j--)
{
if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
flag++;
}
} //无论是第一条还是最后一条我们都要注意 终点的设置不是对角线
if (flag == ROW - 1) //的最后一个 而是最后一个的前一个 我们每次都是拿一个坐标去和
{ //它的下一个坐标进行比较 如果我们拿最后一个的话 访问就会越界
if (board[i][j] == '*') //也就出错了
return '*';
else
return '#';
}
?
到这里棋盘里的比较就没有了?
之前的比较过程中 我们一直返回的都是某一方获得胜利的 而 游戏继续 其实很好写出来 就是需要注意 它放置的位置
大家都知道 如果一个程序 return 了 那么他后面的所有程序就不会在运行了
所以我们的游戏继续的程序一定要放在最后才行 先给大家看一下我写的游戏继续的代码
大家就知道是为什么了??
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
我是 遍历(大致意思是很多组数据我一个一个去试 最后找到正确的一个)整个二维数组来找是否有空字符 如果有 那么就返回字符C 后面的程序就不会执行了
所以!我们游戏继续的程序的位置很重要 如果放在前面任意一个位置的话我们有些地方还没比较内 它找到空字符就返回了 这样肯定是不行的 所以 我把这个放在了最后!?
大家都知道如果三子棋是平局的话那么整个棋盘肯定是被填满的 是不会有空字符的所以大家 看这个判断输赢函数的最后:
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')//游戏继续程序 返回字符C
return 'C';
}
}
return 'Q'; //所有return都没执行那么游戏为平局!
我在最后的位置加上 return 'Q' 这样的话如果前面? 游戏继续没有执行 return 的话就说明这个数组里面已经没有空字符了数组里面已经填满我们下的棋子了??毕竟我们遍历的是整个数组
这样我们判断输赢的函数就写完了 给大家看看整体是什么样子吧
//判断输赢
char is_win(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++) //判断每一行
{
int flag = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] == board[i][j + 1]&&board[i][j]!=' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
}
for (j = 0; j < col; j++) //判断每一列
{
int flag = 0;
for (i = 0; i < row - 1; i++)
{
if (board[i][j]==board[i+1][j]&&board[i][j]!=' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
}
int flag = 0;
for (i = 0, j = 0; i < row - 1 && j < col - 1; i++, j++) //判断第一条对角线
{
if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
flag = 0;
for (i = 0, j = col - 1; i < row - 1 && j>0; i++, j--)//判断第二条对角线
{
if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
for (i = 0; i < row; i++) //游戏是否要继续
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'Q'; //游戏最终为平局
}
到这里我们所有的三子棋的所需要的函数都写完了 我们来总结一下:
- 打印并制作棋盘
- 玩家下棋
- 电脑下棋
- 判断输赢
因为我们每次使用我们都声明了他们也看看 我们现在的game.h是什么样的吧:
3.我们自己定义的头文件game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void display_borad(char board[ROW][COL], int row, int col);//打印并制作棋盘
void player_move(char board[ROW][COL], int row, int col);//玩家下棋
void com_move(char board[ROW][COL], int row, int col);//电脑下棋
char is_win(char board[ROW][COL], int row, int col);//判断输赢
我们把所有需要引得头文件 声明得函数 都放在这里面 我们得另外两个程序 就只需要引我们自己的这个头文件 就相当于是把所用需要的东西都引了一遍 这样是不是方便很多 并且有助于我们写代码时保持头脑清晰?
最后的最后我们来看之前给大家看过的这个:
while (1)
{
char ret; //我们那这个来接受我们判断输赢函数返回的字符
player_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C') //判断输赢
{ //*-玩家赢
if (ret == '*') //#-电脑赢
{ //Q-平局
printf("恭喜你赢了!\n"); //C-游戏继续
printf("----------------\n");
break;
} //我们设置C是游戏继续只要函数返回的不是
else if (ret == '#') //C那就说明一定有一种结果
{ //是C我们就不进行操作让下棋这个循环继续直
printf("很遗憾!电脑赢了\n"); //直到得到我们的结果
printf("----------------\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
com_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C')
{
if (ret == '*')
{
printf("恭喜你赢了!\n");
break;
}
else if (ret == '#')
{
printf("很遗憾!电脑赢了\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
}
}
到这里内 我们整个游戏的搭建就算是完工了 Oh Yeah!
后面是我们三子棋代码的全部 对了这个三子棋版本可以设置棋盘大小的哦
设置的同时就不再是三子棋 就变成四子 五子 六子了 嘻嘻嘻!
总览三子棋代码
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
menu()
{
printf("************************\n");
printf("*********1. play********\n");
printf("*********0. exit********\n");
printf("************************\n");
}
void work()
{
printf("----------------\n");
printf("您已经进入游戏!\n");
char board[ROW][COL];
memset(board, ' ', sizeof(board));//初始化棋盘
display_borad(board, ROW, COL);//打印并制作棋盘
//开始下棋
while (1)
{
char ret;
player_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C') //判断输赢
{ //*-玩家赢
if (ret == '*') //#-电脑赢
{ //Q-平局
printf("恭喜你赢了!\n"); //C-游戏继续
printf("----------------\n");
break;
}
else if (ret == '#')
{
printf("很遗憾!电脑赢了\n");
printf("----------------\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
com_move(board, ROW, COL);
display_borad(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'C')
{
if (ret == '*')
{
printf("恭喜你赢了!\n");
break;
}
else if (ret == '#')
{
printf("很遗憾!电脑赢了\n");
break;
}
else
{
printf("此局为平局!\n");
printf("----------------\n");
break;
}
}
}
}
int main()
{
int input;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 0:
{
printf("您已退出游戏!");
break;
}
case 1:
{
work();
break;
}
default:
{
printf("输入错误请重新输入!\n");
printf("------------------------\n");
break;
}
}
} while (input);
return 0;
}
work.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
//打印并制作棋盘
void display_borad(char board[ROW][COL], int row, int col)
{
int i;
int j;
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 player_move(char board[ROW][COL], int row, int col)
{
int x, y;
printf("请选择您的棋子位置:>");
//判断棋子有效性
while (1)
{
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 com_move(char board[ROW][COL], int row, int col)
{
printf("电脑下:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断输赢
char is_win(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)//判断每一行
{
int flag = 0;
for (j = 0; j < col - 1; j++)
{
if (board[i][j] == board[i][j + 1]&&board[i][j]!=' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
}
for (j = 0; j < col; j++) //判断每一列
{
int flag = 0;
for (i = 0; i < row - 1; i++)
{
if (board[i][j]==board[i+1][j]&&board[i][j]!=' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
}
int flag = 0;
for (i = 0, j = 0; i < row - 1 && j < col - 1; i++, j++)//判断第一条对角线
{
if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
flag = 0;
for (i = 0, j = col - 1; i < row - 1 && j>0; i++, j--)//判断第二条对角线
{
if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
flag++;
}
}
if (flag == ROW - 1)
{
if (board[i][j] == '*')
return '*';
else
return '#';
}
for (i = 0; i < row; i++)//游戏是否要继续
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 'C';
}
}
return 'Q';//游戏最终为平局
}
game.h:
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
void display_borad(char board[ROW][COL], int row, int col);//打印并制作棋盘
void player_move(char board[ROW][COL], int row, int col);//玩家下棋
void com_move(char board[ROW][COL], int row, int col);//电脑下棋
char is_win(char board[ROW][COL], int row, int col);//判断输赢
好的 到这里我们这篇三子棋 博客 就写完了 有写得不好的地方还请各位大牛们指正!
新的一年祝大家新年快乐 万事如意 都能进到自己心仪的大厂 哈哈哈哈哈哈哈
|