C++开发五子棋游戏案例详解

news2024/11/29 12:32:22

在这里插入图片描述

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:Java案例分享专栏
✨特色专栏:国学周更-心性养成之路
🥭本文内容:基于贝叶斯决策的 CAD 程序设计方案

文章目录

    • 1、游戏概念和设计
    • 2、游戏引擎选择
    • 3、游戏逻辑编写
    • 4、图形和音频处理
    • 5、用户界面设计
    • 6、游戏测试和调试
    • 7、游戏优化和性能调整
    • 8、发布和分发
    • 9、游戏更新和维护

在这里插入图片描述

1、游戏概念和设计

  五子棋是一种古老的策略棋类游戏,通常在 15x15 的棋盘上进行。游戏的规则非常简单:两名玩家轮流在棋盘的交叉点上落子,先连成五子的一方获胜。在游戏设计阶段,需要确定以下核心玩法:

  • 游戏规则:明确定义落子规则、胜负判定规则、禁手规则(如果有的话)等。
  • 界面设计:包括棋盘的布局、棋子的样式、玩家信息显示、计时器等。
  • AI对战:设计并实现一个智能的对战系统,使玩家可以与电脑进行对战。
  • 玩家对战:提供玩家之间的对战模式,可以通过局域网或在线进行对战。
  • 视觉风格:确定游戏的整体视觉风格,包括棋盘背景、棋子样式、界面按钮等。
  • 音效:选择合适的音效来增强游戏的氛围,例如落子音效、胜利音效等。
  • 用户交互:设计良好的用户交互方式,包括落子操作、悔棋功能、重新开始游戏等。

  以上是游戏设计的核心方面,详细的设计需要根据目标玩家群体、游戏平台等因素进行调整和完善。在设计过程中,还需要考虑如何提升游戏的趣味性、可玩性和吸引力,以及如何平衡游戏的难度和挑战性。

2、游戏引擎选择

  对于开发简单的2D游戏,如五子棋,选择轻量级的游戏引擎是非常合适的。SFML(Simple and Fast Multimedia Library)和SDL(Simple DirectMedia Layer)都是优秀的选择。

  SFML 是一个现代的多媒体库,提供了简单易用的接口,包括图形渲染、窗口管理、音频播放和输入处理等功能。它使用 C++ 编写,易于学习和使用,适合用于快速开发小型游戏。SFML 的文档和社区支持也非常完善,对于初学者来说是一个很好的选择。

  SDL 是另一个流行的跨平台多媒体库,同样提供了图形渲染、窗口管理、音频播放和输入处理等功能。它同样使用 C++ 编写,被广泛应用于游戏开发领域。SDL 也有丰富的文档和活跃的社区,可以帮助开发者快速上手并解决问题。

  这两个引擎都可以满足五子棋游戏开发的需求,选择哪个取决于开发者的个人偏好和经验。它们都提供了良好的图形渲染支持,可以轻松实现棋盘绘制、棋子落子效果等。同时,它们也提供了方便的输入处理功能,可以处理玩家的鼠标点击或触摸操作。

3、游戏逻辑编写

在C++中编写五子棋游戏的逻辑代码需要考虑以下几个关键点:

  • 棋盘数据结构:可以使用二维数组来表示棋盘,记录每个交叉点的状态(空、黑子、白子)。
  • 用户输入处理:通过输入获取玩家落子的位置,然后更新棋盘状态。
  • 游戏状态管理:需要管理游戏的进行状态,包括当前轮到哪个玩家落子、游戏是否结束等。
  • 落子逻辑:根据玩家输入的位置,在棋盘上落子,并更新棋盘状态。
  • 胜负判断:编写算法来判断是否有玩家连成了五子,从而决定游戏的胜负。

代码示例:

#include <iostream>
#include <vector>

using namespace std;

const int BOARD_SIZE = 15;
const char EMPTY = '-';
const char PLAYER1 = 'X';
const char PLAYER2 = 'O';

vector<vector<char>> board(BOARD_SIZE, vector<char>(BOARD_SIZE, EMPTY));

void printBoard() {
    for (int i = 0; i < BOARD_SIZE; i++) {
        for (int j = 0; j < BOARD_SIZE; j++) {
            cout << board[i][j] << " ";
        }
        cout << endl;
    }
}

bool isValidMove(int row, int col) {
    if (row < 0 || row >= BOARD_SIZE || col < 0 || col >= BOARD_SIZE) {
        return false;
    }
    if (board[row][col] != EMPTY) {
        return false;
    }
    return true;
}

bool isWinningMove(int row, int col, char player) {
    int count = 0;

    // 水平方向
    for (int i = max(0, col - 4); i <= min(col + 4, BOARD_SIZE - 1); i++) {
        if (board[row][i] == player) {
            count++;
            if (count == 5) {
                return true;
            }
        } else {
            count = 0;
        }
    }

    // 垂直方向
    count = 0;
    for (int i = max(0, row - 4); i <= min(row + 4, BOARD_SIZE - 1); i++) {
        if (board[i][col] == player) {
            count++;
            if (count == 5) {
                return true;
            }
        } else {
            count = 0;
        }
    }

    // 左上到右下斜线
    count = 0;
    int startRow = row - min(row, col);
    int startCol = col - min(row, col);
    for (int i = 0; i < min(BOARD_SIZE - startRow, BOARD_SIZE - startCol); i++) {
        if (board[startRow + i][startCol + i] == player) {
            count++;
            if (count == 5) {
                return true;
            }
        } else {
            count = 0;
        }
    }

    // 右上到左下斜线
    count = 0;
    startRow = row + min(BOARD_SIZE - 1 - row, col);
    startCol = col - min(BOARD_SIZE - 1 - row, col);
    for (int i = 0; i < min(startRow + 1, BOARD_SIZE - startCol); i++) {
        if (board[startRow - i][startCol + i] == player) {
            count++;
            if (count == 5) {
                return true;
            }
        } else {
            count = 0;
        }
    }

    return false;
}

void playGame() {
    int row, col;
    char currentPlayer = PLAYER1;

    while (true) {
        cout << "当前棋盘状态:" << endl;
        printBoard();

        cout << "玩家 " << currentPlayer << ",请输入你的下棋位置(行 列):";
        cin >> row >> col;

        if (isValidMove(row, col)) {
            board[row][col] = currentPlayer;
            if (isWinningMove(row, col, currentPlayer)) {
                cout << "玩家 " << currentPlayer << " 获胜!" << endl;
                break;
            }
            currentPlayer = (currentPlayer == PLAYER1) ? PLAYER2 : PLAYER1;
        } else {
            cout << "无效的下棋位置,请重新输入!" << endl;
        }
    }
}

int main() {
    cout << "欢迎来到五子棋游戏!" << endl;
    playGame();
    return 0;
}

4、图形和音频处理

  使用图形库(如SFML)可以方便地处理游戏的图形渲染,绘制棋盘、棋子和界面元素。下面是一个简单的示例代码,展示了如何使用SFML来渲染五子棋游戏的棋盘和棋子:

#include <SFML/Graphics.hpp>

const int BOARD_SIZE = 15;
const int CELL_SIZE = 40;

int main() {
    sf::RenderWindow window(sf::VideoMode(BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE), "Gobang Game");

    sf::RectangleShape board(sf::Vector2f(BOARD_SIZE * CELL_SIZE, BOARD_SIZE * CELL_SIZE));
    board.setFillColor(sf::Color(222, 184, 135));

    sf::CircleShape piece(CELL_SIZE / 2 - 2);
    piece.setOutlineThickness(2);

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        window.clear();

        window.draw(board);

        // 绘制棋子
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (/* 棋盘上该位置有棋子 */) {
                    piece.setFillColor(/* 棋子颜色 */);
                    piece.setPosition(i * CELL_SIZE + 2, j * CELL_SIZE + 2);
                    window.draw(piece);
                }
            }
        }

        window.display();
    }

    return 0;
}

  对于音频处理,可以使用相应的音频库来播放游戏音效。SFML 本身也提供了音频模块,可以方便地加载和播放音频文件。下面是一个简单的示例代码,展示了如何使用SFML的音频模块来播放音效:

#include <SFML/Audio.hpp>

int main() {
    sf::SoundBuffer buffer;
    if (!buffer.loadFromFile("sound.wav")) {
        // 加载音频文件失败
        return -1;
    }

    sf::Sound sound;
    sound.setBuffer(buffer);
    sound.play();

    // 游戏逻辑代码

    return 0;
}

  以上示例代码只是简单的演示了如何使用SFML进行图形渲染和音频处理,实际开发中可以根据需要进行更加复杂的图形和音频处理,例如添加动画效果、调整音量等。同时,还可以使用其他图形库和音频库来实现游戏的图形和音频处理,根据个人偏好和需求进行选择。

5、用户界面设计

  设计游戏的用户界面需要考虑主菜单、游戏界面和游戏设置等部分。通过图形库(如SFML)可以实现用户界面的绘制和交互。下面是一个简单的示例代码,展示了如何使用SFML来设计五子棋游戏的用户界面:

#include <SFML/Graphics.hpp>

int main() {
    sf::RenderWindow window(sf::VideoMode(800, 600), "Gobang Game");

    // 主菜单界面
    bool inMainMenu = true;
    sf::Font font;
    font.loadFromFile("arial.ttf");
    sf::Text title("Gobang Game", font, 50);
    title.setPosition(300, 100);
    sf::Text startButton("Start Game", font, 30);
    startButton.setPosition(350, 200);
    sf::Text exitButton("Exit", font, 30);
    exitButton.setPosition(380, 250);

    // 游戏界面
    bool inGame = false;
    // ... 游戏界面的绘制和交互代码 ...

    // 游戏设置界面
    bool inSettings = false;
    // ... 游戏设置界面的绘制和交互代码 ...

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            }

            if (inMainMenu) {
                // 处理主菜单界面交互
                if (event.type == sf::Event::MouseButtonPressed) {
                    // 检查鼠标点击位置,处理开始游戏和退出游戏的逻辑
                }
            } else if (inGame) {
                // 处理游戏界面交互
                // ... 游戏界面的交互代码 ...
            } else if (inSettings) {
                // 处理游戏设置界面交互
                // ... 游戏设置界面的交互代码 ...
            }
        }

        window.clear();

        if (inMainMenu) {
            // 绘制主菜单界面
            window.draw(title);
            window.draw(startButton);
            window.draw(exitButton);
        } else if (inGame) {
            // 绘制游戏界面
            // ... 游戏界面的绘制代码 ...
        } else if (inSettings) {
            // 绘制游戏设置界面
            // ... 游戏设置界面的绘制代码 ...
        }

        window.display();
    }

    return 0;
}

  以上示例代码展示了如何使用SFML来设计游戏的用户界面,包括主菜单、游戏界面和游戏设置界面。实际开发中,可以根据需求添加更多的交互元素和美化界面的效果,以提升游戏的用户体验。

6、游戏测试和调试

  进行游戏的测试和调试是确保游戏稳定性和可玩性的重要步骤。测试包括功能测试、兼容性测试和性能测试等,以确保游戏在不同平台上都能正常运行。

  • 功能测试:功能测试是验证游戏的各项功能是否按照设计要求正常工作。包括落子逻辑、胜负判断、悔棋功能、重新开始游戏等。在功能测试中,需要测试所有可能的游戏情况,包括正常情况和边界情况,以确保游戏的功能完备和稳定。

  • 兼容性测试:兼容性测试是验证游戏在不同平台和设备上的兼容性。包括不同操作系统(如Windows、macOS、Linux)、不同分辨率的屏幕、不同输入设备(如鼠标、触摸屏)等。通过兼容性测试,可以确保游戏在各种环境下都能正常运行和显示良好的效果。

  • 性能测试:性能测试是验证游戏在各种情况下的性能表现,包括帧率稳定性、内存占用、CPU占用等。通过性能测试,可以发现游戏在特定情况下可能出现的性能问题,并进行优化和调整。

  在测试过程中,需要使用各种测试工具和设备,包括调试器、性能分析工具、不同操作系统的设备等。同时,也需要进行用户体验测试,邀请真实玩家参与游戏测试,收集他们的反馈意见,以改进游戏的可玩性和用户体验。

7、游戏优化和性能调整

  游戏优化是确保游戏在各种平台上能够以流畅的方式运行,并且减少资源占用的重要步骤。优化包括代码优化、图形渲染优化、内存管理优化等。

  • 代码优化:代码优化是通过改进算法、减少不必要的计算、避免内存泄漏等方式来提高游戏的性能。这可能涉及到对游戏逻辑和数据结构的重新设计,以减少不必要的计算和内存占用。同时,还可以通过并行化处理、减少函数调用等方式来提高代码的执行效率。

  • 图形渲染优化:图形渲染是游戏性能的重要组成部分。通过减少不必要的绘制操作、使用合适的图形渲染技术(如批量渲染)、优化纹理和模型的加载等方式来提高图形渲染的效率。同时,还可以考虑使用低多边形模型、减少纹理大小等方式来降低图形渲染的资源占用。

  • 内存管理优化:合理的内存管理可以减少游戏的内存占用,提高游戏的性能。通过使用对象池、减少内存碎片、及时释放不再需要的资源等方式来优化内存管理。同时,还可以考虑使用内存映射和延迟加载等技术来降低内存占用。

  除了以上的优化方式,还可以考虑使用硬件加速、多线程优化、数据压缩等技术来提高游戏的性能和流畅度。在进行优化时,需要根据具体的情况进行分析和调整,以确保优化的效果和稳定性。

  在进行优化时,需要使用性能分析工具来评估游戏的性能瓶颈,并根据评估结果进行有针对性的优化。同时,也需要进行持续的测试和验证,以确保优化的效果和稳定性。通过不断的优化和调整,可以提高游戏的性能和用户体验,使游戏在各种平台上都能够以流畅的方式运行。

8、发布和分发

对于发布和分发游戏,需要进行以下步骤:

  • 打包游戏:将游戏打包为可执行文件或安装包。对于PC平台,可以打包为.exe文件或安装包;对于移动设备,可以打包为.apk(Android)或.ipa(iOS)文件。

  • 符合平台要求:确保游戏符合各个平台的发布要求。不同平台有不同的审核标准和要求,需要确保游戏内容、图标、描述等都符合平台的规定。同时,还需要确保游戏在不同设备上的适配性和稳定性。

  • 发布到应用商店:将游戏提交到各个平台的应用商店,如Steam(PC)、App Store(iOS)、Google Play(Android)等。在提交时需要填写相关的游戏信息、截图、描述等,并遵守应用商店的审核流程和规定。

  • 营销推广:发布游戏后,进行相关的营销推广工作,包括游戏宣传、社交媒体推广、媒体报道等,以吸引玩家关注并下载游戏。

  • 更新和维护:发布后需要持续进行游戏的更新和维护工作,包括修复bug、添加新内容、改进用户体验等,以保持游戏的品质和吸引力。

  在发布和分发游戏时,需要注意不同平台的特点和规定,确保游戏能够顺利通过审核并在各个平台上获得良好的展示和推广。同时,也需要关注玩家的反馈和意见,不断改进游戏,提高用户满意度。

9、游戏更新和维护

  游戏更新和维护是确保游戏持续吸引玩家的重要环节。根据用户反馈和需求,开发团队可以收集玩家意见和建议,然后评估并确定哪些功能需要更新或修复。这可能涉及添加新的游戏内容、改进游戏性能、修复bug或优化用户体验。持续改进游戏可以增加玩家的参与度,并确保游戏保持竞争力和吸引力。更新和维护也需要注意平衡,以避免对游戏整体稳定性和玩家体验造成负面影响。


  码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。

在这里插入图片描述

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

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

相关文章

JavaSE——集合3:ArrayList、Vector

目录 一、ArrayList的注意事项 二、ArrayList的扩容机制(重要) 三、Vector底层结构和源码剖析 1.Vector类的定义说明 2.Vector底层也是一个对象数组 3.Vector是线程同步的&#xff0c;即线程安全&#xff0c;Vector类的操作方法带有synchronized 4.在开发中&#xff0c…

obs录屏怎么样?四大优秀录屏工具亲测好用!

录屏需求日盛&#xff0c;接下来我们就来聊聊几款市面上较为热门的录屏软件——福昕录屏大师、转转大师录屏、爱拍录屏以及经典的obs录屏&#xff0c;希望能给寻找合适录屏工具的您带来一些灵感。 福昕录屏大师 直达链接&#xff1a;www.foxitsoftware.cn/REC/ 如果你刚开始…

如何在组织内推广和应用六西格玛设计?

六西格玛设计&#xff08;Design for Six Sigma, DFSS&#xff09;作为一种先进的流程设计和优化方法论&#xff0c;旨在通过设计阶段的创新与严谨&#xff0c;确保产品或服务从一开始就具备高度的质量和客户满意度。本文&#xff0c;深圳天行健企业管理咨询公司将深入探讨如何…

HCIP--以太网交换安全(三)MAC地址漂移防止与检测

MAC地址漂移防止与检测 一、MAC地址漂移防止与检测知识点 1.1MAC地址漂移的概述 MAC地址漂移是指交换机上一个vlan内有两个端口学习到同一个MAC地址&#xff0c;后学习到的MAC地址表项覆盖原MAC地址表项的现象。 1.2.MAC地址漂移的防止方法 &#xff08;1&#xff09;配置…

浸入式电磁流量计如何工作?

磁力如何产生可感应电压&#xff1f; 所有磁流量计都利用法拉第感应定律的指导原理&#xff0c;该定律显示了“表达变化的磁场在电路中感应出电压的定量关系”。 该感应定律可用于测量导体液体&#xff08;如水&#xff09;的速度&#xff0c;而无需移动部件。与其他类型的仪…

『网络游戏』游戏数据库管理类查询插入账号存储【23】

新建数据库连接 新建数据库 打开数据库 新建表 账号数据 设计表 - 添加属性 对照服务器工程GameMsg增加对应字段 保存后在服务器脚本中操作数据库数据 添加数据层文件夹 创建脚本&#xff1a;DBMgr 编写脚本&#xff1a;DBMgr.cs 修改脚本&#xff1a;ServerRoot.cs 将MySql.d…

两个数相加(c语言)

1./给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target // 的那 两个 整数&#xff0c;并返回它们的数组下标。 //你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。你可以按任意顺序返回答案。 /…

“城市酷选”排队免单模式:创新机制引领本地消费新风尚

近期&#xff0c;众多朋友对排队免单模式展现出浓厚兴趣&#xff0c;旨在借助商家优惠吸引顾客&#xff0c;激活本地商业活力&#xff0c;推动实体消费。自去年下半年起&#xff0c;本地生活服务平台热度持续攀升&#xff0c;其中&#xff0c;排队免单模式作为多商家联合的优惠…

DGX的优势

NVIDIA DGX 的 AI 领导力 文章目录 前言一、概述推动跨行业的 AI 创新二、优势客户体验到哪些好处?1. 利用生成式 AI 释放研究人员的潜力2. 加快现代应用程序的上市时间3. 利用 AI 改善客户体验三、性能性能很重要1. 为世界上最先进的超级计算机提供动力2. 打破世界纪录3. 提高…

『网络游戏』进入游戏主城UI跳转主城【26】

首先在Unity客户端中创建一个空节点重命名为MainCityWnd 设置父物体为全局 创建空节点钉在左上角作为角色信息UI 在钉子下创建Image 创建脚本&#xff1a;MainCityWnd.cs 编写脚本&#xff1a;MainCityWnd.cs 挂载脚本 创建脚本&#xff1a;MainCitySys.cs 编写脚本&#xff1a…

《Programming from the Ground Up》读后感

之所以看这本书&#xff0c;是想了解一些跟汇编相关的知识&#xff0c;打开这本书后就被作者的观点——“If you don’t understand something the first time, reread it. If you still don’t understand it, it is sometimes best to take it by faith and come back to it …

MeterSphere接口自动化平台调试

1。后置脚本节目 //导入json包 import org.json.*; import com.decode.DecodeMain; String responseprev.getResponseDataAsString(); String result DecodeMain.DecodeUtil(response); log.info(“获取批次账单id result:”result); //转换为Object对象类型 JSONObject data_…

Linux基础项目开发day2:量产工具——输入系统

文章目录 前言一、数据结构抽象1、数据本身2、数据本身3、input_manager.h 二、触摸屏编程1、touchscreen.c 三、触摸屏单元测试1、touchscreen.c2、上机测试 四、网络编程netiput.c 五、网络单元测试1、netiput.c2、client.c3、上机测试 六、输入系统的框架1、框架思路2、inpu…

5.STM32的串口通信

5.STM32的串口通信 两个串口之间的通信 发送端口&#xff1a;TX 接受端口&#xff1a;RX 注意一台设备的TX 与 另一台RX相连接 共地&#xff1a;还需要将两端地线相连接&#xff0c;将设备的参考电势在同一水平&#xff08;通讯的前提&#xff09; 建立连接 在cubeIDE中 图…

独家揭秘!新手铲屎官不可错过的宠物空气净化器选购攻略就在这

终于给我等到了双十一&#xff0c;这可是一年一度的促销力度最大的购物狂欢节&#xff0c;不要问我为什么这么期待&#xff0c;因为我养了猫&#xff0c;猫咪掉毛太严重了&#xff0c;必须得买一个宠物空气净化器&#xff0c;不然我在这个家就呆不下去了。 最近国庆节刚带猫回…

Transactional注解导致Spring Bean定时任务失效

背景 业务需要定时捞取数据库中新增的数据做数据处理及分析&#xff0c;更新状态&#xff0c;处理结束。而我们不能随意定义线程池&#xff0c;规定使用统一的标准规范来定义线程池。如在配置文件中配置线程池的属性&#xff1a;名称&#xff0c;线程核心数等&#xff0c;任务…

用最短长度的绳子把整个花园围起来

给定一个数组 trees&#xff0c;其中 trees[i] [xi, yi] 表示树在花园中的位置。 你被要求用最短长度的绳子把整个花园围起来&#xff0c;因为绳子很贵。只有把 所有的树都围起来&#xff0c;花园才围得很好。 返回恰好位于围栏周边的树木的坐标。 示例 1: 输入: points […

白鲨优化算法(WSO)的MATLAB代码复现

目录 1 白鲨优化算法优化BP神经网络代码复现 2 白鲨优化算法优化支持向量机代码复现 3 白鲨优化算法优化长短期记忆神经网络代码复现 1 白鲨优化算法优化BP神经网络代码复现 1&#xff09;单输出回归预测&#xff1a;单输出回归预测&#xff1a;大白鲨算法优化BP神经网络模…

OpenCV HoughLine()函数与HoughlinesP()函数及HoughCircles()函数详解及用法示例

OpenCV HoughLine()函数与HoughlinesP()函数都用于图像中的直线检测&#xff0c;但二者是有区别的。 HoughLine()函数 HoughLines&#xff08;&#xff09;基于霍夫变换的原理&#xff0c;通过投票机制来确定图像中直线的存在及其参数。该函数返回检测到的直线的极坐标参数。它…

【多线程】CAS原理

文章目录 为什么会出现CAS思想?CAS概念CAS自旋概念CAS的简单使用CAS源码解析 UnSafe类CAS底层原理CAS的硬件保证CAS自旋锁的实现前置知识----原子引用AtomicReference实现自旋锁 CAS缺点ABA问题什么是ABA问题如何解决ABA问题简单案例AtomicStampedReference的源码分析 为什么会…