0


C语言”三子棋“升级版(模式选择+”模拟智能“下棋)

前言

人生如棋,落子无悔!你还记得我们的童年游戏“三子棋”吗?你想过有一天我们能用C语言写出“三子棋吗?相信你已经迫不及待了,下面就跟小编一起过关斩将“破棋局”!

在这里插入图片描述

文章目录

一、游戏规则:

三点一线决胜负!

二、效果展示

三、项目拆分

这里建议大家在写项目时,将项目拆分为多个模块来实现:

​​

将项目拆分有以下优点:

1、大变小,使部分功能可重用。

2、分离关注点,将来每个团队、每个人只需要关注、维护系统的一部分模块或一个子系统,提升开发效率。

3、代码结构更加清晰,便于项目调试。

四、游戏设计思路

一、 游戏交互界面

  1. 创建游戏菜单
  2. 游戏模式选择
  3. 创建游戏交互主体

二、三子棋游戏

  1. 创建三子棋盘
  2. 初始化棋盘
  3. 打印棋盘

1.简单模式

  1. 玩家下棋
  2. 判断输赢
  3. 电脑下棋
  4. 判断输赢

2.困难模式

  1. 电脑模拟智能下棋
  2. 判断输赢
  3. 玩家下棋
  4. 判断输赢

五、游戏交互界面

1.创建游戏菜单

为了能给用户更好的游戏交互体验,我们首先需要设计一个可视化菜单。主要功能是对游戏进程进行选择,其它装饰效果大家可以花点心思,脑洞大开随性设计。

这里就简单介绍一下我设计的游戏菜单:

先看效果:

这里我简单添加了一个文字向中间汇聚打印的效果,主要用到

Sleep()

函数,

system("cls")

系统清屏命令。

代码展示:

voidmenu(){//创建两个数组char arr1[]="------------Welcom to game!!!------------";char arr2[]="*****************************************";int left =0;int right =strlen(arr1)-1;while(left <= right){
        arr2[left]= arr1[left];
        arr2[right]= arr1[right];printf("%s\n", arr2);//休息1秒Sleep(50);system("cls");//执行系统命令//清空屏幕
        left++;
        right--;}printf("%s\n", arr2);Sleep(300);printf("************  1.开始游戏  ************\n");printf("************  0.退出游戏  ************\n");}

2.游戏模式选择

由于在游戏中添加了AI元素,所以将游戏分为了简单模式困难模式。所以我们还需要一个游戏模式选择界面。
代码展示:

intmodel(){int choice =0;while(1){printf("----------------------------------------\n");printf("--------------1.简单模式---------------\n");printf("--------------2.困难模式---------------\n");printf("----------------------------------------\n");printf("请选择:>");scanf("%d",&choice);if(choice ==1){printf("\n只有菜鸡才会选择简单模式!!!\n");printf("\n你准备好了吗?游戏要开始喽!!!");Sleep(2000);break;}if(choice ==2){printf("\n你能赢得了电脑吗?\n");printf("你可能不会输,但也不一定会赢!!!");printf("\n你准备好了吗?游戏要开始喽!!!");Sleep(3000);break;}else{printf("输入错误,请重新选!\n");}}return choice;}

好奇的小伙伴可能会问了,为什么此函数需要返回值?我们顺藤摸瓜,带着疑问继续往下看👇

3.搭建游戏交互主体

还记得上次的猜数字游戏吗?三子棋的游戏交互主体也是如出一辙。

代码展示:

intmain(){int input =0;srand((unsignedint)time(NULL));do{
        
        count =1;//保证每一把开始count=1,//使AI模式下,电脑第一次在中间落子(后面详细介绍)menu();printf("请选择:>");scanf("%d",&input);switch(input){case1://三子棋游戏game(model());//这里就用到了函数的链式访问break;case0:printf("退出游戏\n");break;default:printf("选择错误,重新选择\n");Sleep(1000);break;}}while(input);return0;}

效果展示:

还记得model()函数的返回值吗?

在这里

game(model())

表示将玩家模式选择的结果传递给

game()

函数。因为游戏的执行过程被封装在

game()

当中,我们需要在游戏中决定游戏执行方向,所以需要一个返回值记录玩家的选择结果,最后将选择结果交给游戏函数。

六、游戏实现

1.游戏主体逻辑框架-game()

在实现游戏之前,先给出封装后的游戏逻辑框架——

void game(int choice)

当然这个框架不是一下就能搭建好的,我们一般是先搭建一部分,然后随着对游戏功能的不断拓展将框架逐渐完善。这里给出是为了大家更好的理解游戏设计。

我们游戏的设计就是按照下面的思路逻辑,先捋清游戏设计思路以及游戏的相关功能,再对各个功能进行实现。

//游戏主体逻辑框架voidgame(int choice){//创建棋盘char board[ROW][COL];//初始化棋盘InitBoard(board, ROW, COL);char ret=0;//用于接受游戏状态while(1){简单模式if(choice ==1){//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;//电脑下棋ComputerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;}困难模式else{//电脑下棋AI(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;}困难模式}if(ret =='o'){printf("\n-------------  玩家赢了  ------------  \n");}elseif(ret =='x'){printf("\n-------------  电脑赢了  -------------\n");}else{printf("\n--------------- 平局 ------------------\n");}}

1.创建三子棋盘

我们已知三子棋盘是3行3列,因此很容易想到用二维数组来表示棋盘:

//棋盘创建#defineROW3#defineCOL3char board[ROW][COL];

注意:这里的行——

ROW

、列——

COL

采用了宏定义

采用宏定义的优点:

1、方便程序的修改,增加了程序的可塑性(比如我想搭建五子棋盘,只需修改

ROW

COL

2、提高程序的运行效率:可以省去函数中传参的过程

2.初始化棋盘

当双方均未下棋时,我们需要一个空棋盘。由于初始时棋盘内容不显示,我们通过变量棋盘数组,将棋盘内容初始化为空格。

//棋盘初始化voidInitBoard(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]=' ';}}}

3.打印棋盘

棋盘样式:

在这里插入图片描述

通过效果图,我们通过

---

|

的有机组合打印出三子棋盘,同时还可以打印一些提示信息,方便玩家辨别棋子。

代码展示:

voidDisplayBoard(char board[ROW][COL],int row,int col){system("cls");printf("**********  三子棋游戏  **********\n");printf("玩家棋子:o\n");printf("电脑棋子:x\n");int i =0;for(i =0; i < row; i++){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){
            j =0;for(j =0; j < col; j++){printf("---");if(j < col -1)printf("|");}printf("\n");}}}

4.模式规定

为了增加游戏的趣味性,给游戏设置了两种模式,分别是:

  1. 简单模式规则: 玩家先下棋,电脑后下棋。注: 电脑随机下棋胜率: 玩家>电脑
  2. 困难模式规则: 电脑先下棋并且第一步棋落子中间,玩家后下棋注: ”模拟电脑智能“下棋(增加下棋算法)胜率: 电脑>=玩家

5.简单模式

(1)玩家下棋

代码展示:

voidPlayerMove(char board[][COL],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(board[x -1][y -1]==' '){
                board[x -1][y -1]='o';break;}else{printf("坐标被占用, 请重新输入\n");}}else{printf("坐标非法, 请重新输入\n");}}}

注意:
1、

board[x-1][y-1]

——

x-1,y-1

是因为:玩家不是程序员,输入坐标比二维数组中字符坐标大

1

比如玩家在中间下棋,则会输入坐标

(2 ,2)

,所以我们采用

x-1,y-1

使数组坐标合法化。

2、玩家棋子用

o

表示(可自定义)

(2)简单模式电脑下棋

voidComputerMove(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]='x';break;}}}

注意:
1、这里使用了随机生成函数

rand()

,不清楚怎样使用的小伙伴可以看一下随机生成三剑客

2、不同于玩家下棋,这里省去了判断坐标合法性,因为

x=rand()%row

y=rand()%col

必定合法

3、电脑棋子用

x

表示(可自定义)

(3)判断游戏状态

三子棋游戏一共用四种游戏状态:

1、玩家赢
三行、三列、左右对角线存在三个棋子相同且均为

o

2、电脑赢
三行、三列、左右对角线存在三个棋子相同且均为

x

3、平局
棋盘下满且不存在上述两种情况
4、游戏继续
上述情况均不满足

规定:
1、玩家赢

--return 'o'

2、电脑赢

--return 'x'

3、平局

--return 'Q'

4、游戏继续

--return 'C'
//判断棋盘是否已满(返回值用于判断是否平局)intIsFull(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++){if(board[i][j]==' '){return0;//棋盘没满}}}return1;//棋盘满了}判断输赢///1、判断三行是否一样charIsWin(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][1]!=' '){return  board[i][1];//}}//2、判断三列是否一样for(i =0; i < col; i++){if(board[0][i]== board[1][i]&& board[1][i]== board[2][i]&& board[1][i]!=' '){return board[1][i];}}//3、判断对角线是否一样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];}//4、判断平局//如果棋盘满了并且上述情况均不满足,返回Q、否则返回Cint ret =IsFull(board, row, col);if(ret ==1){return'Q';}//继续return'C';}

简单模式下的三子棋到这里就结束了,我们玩一把:

(4)问题与改进

通过观察发现,玩家和电脑每次下棋都会打印一次棋盘,这样的话游戏界面就会非常混乱,不利于玩家观察。为了能够让游戏界面更简洁,可以在打印棋盘函数

DisplayBoard()

中增加一个系统清屏命令

system("cls")

,使界面中只保留一个棋盘。
在这里插入图片描述

改进后效果:
是不是变得干净整洁多了!

5.困难模式

困难模式下,玩家下棋判断游戏状态和简单模式相同,困难模式的核心是电脑下棋规则设计。

通过简单模式的演示效果,我们发现简单模式下电脑下棋总是呆呆的,电脑胜率几乎为零,玩家就算是赢了也没有什么成就感。所以可以给电脑植入一些算法,使电脑”智能“,提高电脑胜率,从而增加游戏的趣味性和挑战性。

(1)困难模式-模拟智能下棋

设计思路:
在设计电脑“智能下棋”之前,我们可以分析一下玩家是怎样取胜的。玩家下棋的时候,总有这样一种思路:

1、先看棋盘上任意连续的三个位置是否有己方的两枚棋子,如果有并且剩下一个位置为空,那么在此处落子就会取胜。
2、如果

1、

不满足,再看棋盘任意三个位置是否有对方的两枚棋子,如果有并且剩下一个位置为空,那么在此处落子保证不输
3、如果

1、2、

均不满足,那么就分析大局观,在有较大可能赢并且为空的位置落子

补充: 开局先落子,并且落子中间胜率大

显然

3、

对于目前来说实现起来比较困难,但是我们可以对

1、 2、

**补充**

进行实现,从而模拟出两种“智能”情况

下面展示“模拟电脑智能下棋”的代码的详细介绍,思路很简单,代码较长,大家慢慢食用!

代码展示:(这里由于代码过长,以缩进后图片形式呈现。详细代码放到了最后!

七、完整代码:

上面我们已经提到,通过项目拆分,将三子棋项目分为了三个模块(1、逻辑部分 2、声明部分 3、函数定义部分),分别放在文件(test.c
/game.h /game.c)中。

如下图:

1.游戏交互主体-test.c

#include"game.h"int flag=1;//为了限制,每次都以动画方式进场/游戏菜单/voidmenu(){if(flag ==1){char arr1[]="------------Welcom to game!!!------------";char arr2[]="*****************************************";int left =0;int right =strlen(arr1)-1;while(left <= right){
            arr2[left]= arr1[left];
            arr2[right]= arr1[right];printf("%s\n", arr2);//休息1秒Sleep(50);system("cls");//执行系统命令//清空屏幕
            left++;
            right--;}printf("%s\n", arr2);Sleep(300);printf("************  1.开始游戏  ************\n");printf("************  0.退出游戏  ************\n");}else{printf("------------Welcom to game!!!------------\n");printf("************  1.开始游戏  ************\n");printf("************  0.退出游戏  ************\n");}}/游戏模式/intmodel(){int choice =0;while(1){printf("----------------------------------------\n");printf("--------------1.简单模式---------------\n");printf("--------------2.困难模式---------------\n");printf("----------------------------------------\n");printf("请选择:>");scanf("%d",&choice);if(choice ==1){printf("\n只有菜鸡才会选择简单模式!!!\n");printf("\n你准备好了吗?游戏要开始喽!!!");Sleep(2000);break;}if(choice ==2){printf("\n你能赢得了电脑吗?\n");printf("你可能不会输,但也不一定会赢!!!");printf("\n你准备好了吗?游戏要开始喽!!!");Sleep(3000);break;}else{printf("输入错误,请重新选!\n");}}return choice;}/游戏主题/voidgame(int choice){//存储数据 - 二维数组char board[ROW][COL];//初始化棋盘 - 初始化空格InitBoard(board, ROW, COL);//打印一下棋盘 - 本质是打印数组的内容char ret =0;//接受游戏状态/简单模式/while(1){if(choice ==1){//玩家下棋DisplayBoard(board, ROW, COL);PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;//电脑下棋ComputerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;}/困难模式/else{//电脑下棋AI(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断电脑是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;//玩家下棋PlayerMove(board, ROW, COL);DisplayBoard(board, ROW, COL);//判断玩家是否赢得游戏
            ret =IsWin(board, ROW, COL);if(ret !='C')break;}}if(ret =='o'){printf("\n-------------  玩家赢了  ------------  \n");}elseif(ret =='x'){printf("\n-------------  电脑赢了  -------------\n");}else{printf("\n--------------- 平局 ------------------\n");}}/游戏交互逻辑结构/int count=0;//声明外部符号intmain(){int input =0;srand((unsignedint)time(NULL));do{    
        
        count =1;//保证每一把开始count=1,使电脑在中间落子menu();printf("请选择:>");scanf("%d",&input);switch(input){case1:game(model());
            flag++;break;case0:printf("退出游戏\n");break;default:printf("选择错误,重新选择\n");Sleep(1000);break;}}while(input);return0;}

2.声明部分-game.h

#pragmaonce//头文件的包含/#include<stdio.h>#include<time.h>#include<string.h>#include<windows.h>#include<stdlib.h>符号的定义/#defineROW3#defineCOL3函数的声明////初始化棋盘的voidInitBoard(char board[ROW][COL],int row,int col);//打印棋盘的函数voidDisplayBoard(char board[ROW][COL],int row,int col);//玩家下棋voidPlayerMove(char board[ROW][COL],int row,int col);//电脑下棋(简单模式)voidComputerMove(char board[ROW][COL],int row,int col);//电脑下棋(AI模式)voidAI(char board[ROW][COL],int row,int col);//判断游戏是否有输赢charIsWin(char board[ROW][COL],int row,int col);

3.函数定义部分-game.c

#include"game.h"初始化棋盘/voidInitBoard(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]=' ';}}}打印棋盘/voidDisplayBoard(char board[ROW][COL],int row,int col){system("cls");printf("**********  三子棋游戏  **********\n");printf("玩家棋子:o\n");printf("电脑棋子:x\n");int i =0;for(i =0; i < row; i++){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){
            j =0;for(j =0; j < col; j++){printf("---");if(j < col -1)printf("|");}printf("\n");}}}玩家下棋/voidPlayerMove(char board[][COL],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(board[x -1][y -1]==' '){
                board[x -1][y -1]='o';break;}else{printf("坐标被占用, 请重新输入\n");}}else{printf("坐标非法, 请重新输入\n");}}}电脑下棋(简单模式)/voidComputerMove(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]='x';break;}}}判断棋盘是否已满/intIsFull(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++){if(board[i][j]==' '){return0;//棋盘没满}}}return1;//棋盘满了}判断输赢/charIsWin(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][1]!=' '){return  board[i][1];//}}///判断三列///for(i =0; i < col; i++){if(board[0][i]== board[1][i]&& board[1][i]== board[2][i]&& board[1][i]!=' '){return board[1][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];}///判断平局/////如果棋盘满了返回1, 不满返回0int ret =IsFull(board, row, col);if(ret ==1){return'Q';}//继续return'C';}

4.模拟智能下棋(完整版)

extern count;//AI模式voidAI(char board[ROW][COL],int row,int col){int i =0;int flag =2;if(count ==1)//定义全局变量,保证电脑先走,第一步一定下中间{
        board[1][1]='x';//赋值是一个等号
        count++;}else{if(flag ==2){//判断行有没有两个xfor(i =0; i < row; i++){if((board[i][0]== board[i][1])&&(board[i][1]=='x')&&(board[i][2]==' ')){
                    board[i][2]='x'; flag =1;break;}if((board[i][0]== board[i][2])&&(board[i][2]=='x')&&(board[i][1]==' ')){
                    board[i][1]='x'; flag =1;break;}if((board[i][1]== board[i][2])&&(board[i][1]=='x')&&(board[i][0]==' ')){
                    board[i][0]='x'; flag =1;break;}}//判断列有没有两个xfor(i =0; i < col; i++){if((board[0][i]== board[1][i])&&(board[0][i]=='x')&&(board[2][i]==' ')){
                    board[2][i]='x'; flag =1;break;}if((board[0][i]== board[2][i])&&(board[0][i]=='x')&&(board[1][i]==' ')){
                    board[1][i]='x'; flag =1;break;}if((board[1][i]== board[2][i])&&(board[1][i]=='x')&&(board[0][i]==' ')){
                    board[0][i]='x'; flag =1;break;}}}while(flag ==2){//判断右对角线有没有两个xif((board[0][0]== board[1][1])&&(board[0][0]=='x')&&(board[2][2]==' ')){
                board[2][2]='x';
                flag =1;break;}if((board[0][0]== board[2][2])&&(board[0][0]=='x')&&(board[1][1]==' ')){
                board[1][1]='x';
                flag =1;break;}if((board[2][2]== board[1][1])&&(board[1][1]=='x')&&(board[0][0]==' ')){
                board[0][0]='x';
                flag =1;break;}//判断左对角线有没有两个xif((board[2][0]== board[1][1])&&(board[1][1]=='x')&&(board[0][2]==' ')){
                board[0][2]='x';
                flag =1;break;}if((board[2][0]== board[0][2])&&(board[2][0]=='x')&&(board[1][1]==' ')){
                board[1][1]='x';
                flag =1;break;}if((board[1][1]== board[0][2])&&(board[1][1]=='x')&&(board[2][0]==' ')){
                board[2][0]='x';
                flag =1;break;}break;}if(flag ==2){//判断行有没有两个ofor(i =0; i < row; i++){//再判断if((board[i][0]== board[i][1])&&(board[i][1]=='o')&&(board[i][2]==' ')){
                    board[i][2]='x'; flag =1;break;}if((board[i][0]== board[i][2])&&(board[i][2]=='o')&&(board[i][1]==' ')){
                    board[i][1]='x'; flag =1;break;}if((board[i][1]== board[i][2])&&(board[i][1]=='o')&&(board[i][0]==' ')){
                    board[i][0]='x'; flag =1;break;}}//判断列有没有两个ofor(i =0; i < col; i++){//再判断if((board[0][i]== board[1][i])&&(board[0][i]=='o')&&(board[2][i]==' ')){
                    board[2][i]='x'; flag =1;break;}if((board[0][i]== board[2][i])&&(board[0][i]=='o')&&(board[1][i]==' ')){
                    board[1][i]='x'; flag =1;break;}if((board[1][i]== board[2][i])&&(board[1][i]=='o')&&(board[0][i]==' ')){
                    board[0][i]='x'; flag =1;break;}}}while(flag ==2){//判断右对角线有没有两个oif((board[0][0]== board[1][1])&&(board[0][0]=='o')&&(board[2][2]==' ')){
                board[2][2]='x';
                flag =1;break;}if((board[0][0]== board[2][2])&&(board[0][0]=='o')&&(board[1][1]==' ')){
                board[1][1]='x';
                flag =1;break;}if((board[2][2]== board[1][1])&&(board[1][1]=='o')&&(board[0][0]==' ')){
                board[0][0]='x';
                flag =1;break;}//判断左对角线有没有两个oif((board[2][0]== board[1][1])&&(board[1][1]=='o')&&(board[0][2]==' ')){
                board[0][2]='x';
                flag =1;break;}if((board[2][0]== board[0][2])&&(board[2][0]=='o')&&(board[1][1]==' ')){
                board[1][1]='x';
                flag =1;break;}if((board[1][1]== board[0][2])&&(board[1][1]=='o')&&(board[2][0]==' ')){
                board[2][0]='x';
                flag =1;break;}}//如果以上都不满足,则随机放置xwhile(flag ==2){int x =rand()% row;int y =rand()% col;if(board[x][y]==' '){
                board[x][y]='x';break;}}}}

总结

由于作者水平有限,如笔下有误,敬请留言。

如果本文对您有所帮助,请给博主点赞👍关注🙏哦,笔者会持续更新干货教程,期待与君共勉!


本文转载自: https://blog.csdn.net/LEE180501/article/details/126078573
版权归原作者 小牛要翻身 所有, 如有侵权,请联系我们删除。

“C语言&rdquo;三子棋&ldquo;升级版(模式选择+&rdquo;模拟智能&ldquo;下棋)”的评论:

还没有评论