# dessert-bot **Repository Path**: yexiang841/dessert-bot ## Basic Information - **Project Name**: dessert-bot - **Description**: #### 介绍 点心AI - 国标麻将人工智能 - 北大AI比赛项目 #### 说明 1. 技术栈:C++ 2. 运行环境:Linux / Mac - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-05-20 - **Last Updated**: 2022-07-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # dessert-bot #### 介绍 点心AI - 国标麻将人工智能 - 北大AI比赛项目 #### 说明 1. 技术栈:C++ 2. 运行环境:Linux / Mac #### [引用链接][国际麻将] 1. 入口:https://www.botzone.org.cn/game/Chinese-Standard-Mahjong; 2. 主页:https://www.botzone.org.cn/static/gamecontest2020a_cn.html; 3. 报名:https://www.botzone.org.cn/group/5e6a0f416c4762146e9706a2; 4. 仓库:https://github.com/ailab-pku/Chinese-Standard-Mahjong; 5. 教程:https://www.botzone.org.cn/game/Chinese-Standard-Mahjong; 6. 维基:https://wiki.botzone.org.cn/index.php?title=首页; 7. 本地测试工具:https://github.com/zhouhaoyu/botzone-local-runner/releases;(需要.NET Framework4.6,只能Windows运行) 8. 代码合并工具:https://github.com/vinniefalco/Amalgamate; 9. Botzone官方使用的JSONCPP:https://wiki.botzone.org.cn/index.php?title=JSONCPP; 10. 算番库:https://github.com/ailab-pku/Chinese-Standard-Mahjong/tree/master/fan-calculator-usage; 11. 麻将规则详解:http://mj.lianzhong.com/gbmj/home/teaching_new_rule1; 12. 麻将英文术语大全:http://www.360doc.com/content/19/0105/14/46937163_806689384.shtml; 13. 测试案例:https://www.botzone.org.cn/match/5ebb9b08703c1e22d9335afa; #### [基础概念][Bot解读] 1. Bot可以读写用户空间下的文件; 1. 是否可以在运行时读写此空间待研究(TODO); 2. 支持C/C++/Java/js/C#/Python2-3/Pascal; 3. 每种语言都提供Json运行库; 4. Bot每个生命周期为一次输入一次输出,【长时运行】模式可以保持Bot存活,避免冷启动开销; 5. Bot流程: 1. 启动; 2. 从平台获取输入输出历史和本次输入; 3. 计算: 1. 根据历史恢复牌面; 2. 根据本次输入决策输出; 6. 限制: 1. 1秒内输出(官方Bot上传页说第一回合时间翻倍,意味着长时运行情况下有足够时间在第一回合初始化); 1. 不同语言乘以不同倍率; 2. C/C++ x 1 3. Java x 3 4. C# x 6 5. js x 2 6. Python x 6 7. Pascal x 1 2. 使用内存不超过256M; 3. 各语言运行大量裴波那契数列效率测试: 1. C/C++ x 1 2. Java x 3到10(依据io和内存、以及cpu核数) 3. C# x 9 4. js x 1000+ 5. Python x 200+ 6. Pascal笔者不测试; 4. 结论:只有C/C++和Java是比较划算的,但因为Java的内存读写结构不够高效且容易超出限制,最终选择C++; 7. 交互格式: 1. Json交互: 1. 数据比较易读,但笔者认为解析大量Json字段浪费性能,适合测试时使用; 2. 长时运行模式因数据量少也适合用Json交互; 3. 输入形如:{"requests":["req1","req2","req3"],"responses":["resp1","resp2"],"data":"abc","globaldata":"ABC"…...} 1. requests:[];来自平台每回合的信息; 2. responses:[];Bot输出历史; 3. data:"";上回合记录的备注,最大长度100K,不存Log,若合理利用可辅助本回合决策; 4. globaldata:"";上局记录的备注,最大长度100K,不存Log,若合理利用可辅助本回合决策; 5. time_limit:"";时间限制; 6. memory_limit:"";内存限制; 4. 输出形如:{"response":"resp3","debug":"hello","data","def","globaldata","DEF"} 1. response:"";本回合输出; 2. debug:"";本回合调试信息,会写入Log,最大长度1K,相当于1000个英文字母; 3. data:"";本回合备注,最大长度100K,下回合会输入回来; 4. globaldata:"";本局对战备注,最大长度100K; 2. 简化交互: 1. 数据格式按约定解读,性能较高,适合对战时使用; 2. 输入分多行: 1. 3 2. req1 3. resp1 4. req2 5. resp2 6. req3 7. abc 8. ABC 3. 输出分多行: 1. resp3 2. hello 3. def 4. DEF 3. 关于globaldata字段: 1. 目前推测应该算是一个全局变量,每局对战保留最后一次输出的globaldata,待考证(TODO); 2. 如果按照如上操作,当前回合就会从把globaldata从ABC变成DEF(丢失ABC信息); 3. 所以建议采用增量记录,比如从ABC变成ABC_DEF这样; 4. 100K相当于10万个英文字母,或者5万个汉字; 5. 注意如果数据太长也会占用少量io时间; 4. 不论哪种格式,最终都是以标准输入读取数据,以标准输出响应; 1. C:scanf()/printf()、C++:cin/cout、Java:System.in/System.out; 2. 所以只有本地测试时才用标准输出打日志; 3. 要记得在提交时注释掉标准输出日志,只留重要的放到debug字段; 8. 长时运行: 1. 此模式下可以忽略类对象生成开销,一次构建多次使用,可以在代码中运用更好的设计模式; 2. 此模式下也可以节省数据解析开销; 1. 长时运行模式的输入不包含responses、debug、data、globaldata字段,若进程不退出,这些都可以保存在变量; 2. 官方wiki表示长时运行模式的输出格式不变,但理论上data字段已经没作用了,待考证(TODO),globaldata还是可以给下一局用的; 3. 官方wiki没有说此模式的简化交互格式有多少行输入和多少行输出,因笔者采用Json格式交互,所以对此不予考证; 3. 第一回合不变; 4. 完成标准输出; 5. 根据官方建议清空标准输出缓冲区:fflush(stdout)、cout << flush、System.out.flush(); 6. 输出:>>>BOTZONE_REQUEST_KEEP_RUNNING<<<,没有这一句会导致超时; 7. 平台收到这行之后后会发送挂起信号将进程挂起; 1. 在程序输出和被挂起之间有一个等待时间,理论上这种守护进程都会在此循环或者挂起; 2. 官方用词叫【卡时】(没听说过),具体什么意思待研究源码(TODO); 3. 官方建议不要在此占用CPU(比如开个线程进行提前计算),CPU使用时间会计入下回合; 8. 因为不含本局之前回合的历史数据,所以Log中的【玩家输入】字段会有一定的变化,具体什么变化待测试(TODO); 9. 因为不含本局之前回合的历史数据,所以调试时要注意Bot中的随机算法,有可能本地测试的response会跟Botzone历史中的response不一样; 9. 在Botzone上传Bot的时候会约定: 1. Bot基本信息; 2. 编译器及依赖库; 3. 是否长时运行; 4. 采用哪种交互格式; 5. 是否开源代码; 10. 笔者采用长时运行+Json交互格式; #### [开发环境][系统配置] 1. macOS Catalina 10.15.4 2. 4 GHz 四核Intel Core i7 3. 16 GB 1867 MHz DDR3 #### [开发环境][VSCode] 1. 笔者当前使用1.44.2formac; 2. [实操]在将内置Shell设置为bash(默认好像是zsh) 1. 全局搜索Preferences: Open Settings (JSON),添加: 1. "terminal.integrated.automationShell.osx": "/bin/sh"; 2. "terminal.integrated.shell.osx": "/bin/bash"; 3. [实操]安装Chinese (Simplified) Language Pack for Visual Studio Code,官方中文包,全局搜索Configure Display Language切换,但笔者建议用英文; 4. [实操]安装Prettier - Code formatter代码规范插件,alt+shift+f规整代码; 5. [实操]安装Bracket Pair Colorizer 2,让嵌套代码块用不同颜色标识,安装后自动生效; 6. [实操]安装TODO Heighlight和Todo Tree,高亮TODO(自动生效)和生成TODO目录; 7. [实操]安装C/C++/Python/C#/Java语言支持,安装后自动生效; 8. [实操]安装Code Runner,各种语言快速运行助手,配置如下: 1. 调整运行设置,全局搜索Preferences: Open Settings (JSON),添加: 1. "code-runner.clearPreviousOutput": true,//每次运行之前清一下之前的输出; 2. "code-runner.runInTerminal": true,//打开终端执行; 3. "code-runner.saveAllFilesBeforeRun": true,//运行之前保存所有文; 1. 调整C++选项编译选项,全局搜索Preferences: Open Workspace Settings (JSON),添加: 1. "code-runner.executorMap":{"cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt.out -std=c++17 -Wall -O0 -g && $dir$fileNameWithoutExt.out"}; 9. [实操]安装CodeLLDB,解决macOS Catalina不支持lldb的问题; #### [开发环境][Bot工程] 1. 工程环境: 1. 找个地方建立dessert-bot目录; 2. VSCode打开目录; 3. 在目录下新建dessert_bot.cpp和hello_world.cpp,分别用作bot开发和算法测试; 4. 下载官方wiki提供的JSONCPP库,解压后把jsoncpp.cpp和json目录放到dessert-bot工程目录下; 2. 编译设置 1. 不需要debug的,用CodeRunner插件(右上角播放键)直接运行; 2. 需要debug的,如下步骤: 1. 选择任意cpp代码,比如hello_world.cpp,左侧run/debug选项生成.vscode/launch.json; 2. 编译平台选择C++(GDB/LLDB),编译器选g++;修改 3. "program": "${workspaceFolder}/dessert_bot.out"; 4. 点左上角运行或者cmd+shift+b,会提示生成一个.vscode/task.json; 5. .vscode/launch.json和.vscode/task.json这两个文件的细节见代码; #### [开发] 1. Google C++代码规范:[引用]https://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/; 2. 简明设计模式:[引用]https://www.cnblogs.com/wky1680/archive/2013/02/04/2891402.html; 3. 元编程高级技巧:https://bot-man-jl.github.io/articles/?post=2018/Cpp-Struct-Field-Reflection#%E9%9D%99%E6%80%81%E5%8F%8D%E5%B0%84; #### [部署环境][Botzone] 1. 由北大信科AI实验室研发维护; 2. 【控制器】运行【裁判】和【Bot】; 3. Botzone运行环境:Ubuntu 16.04 X86-64虚拟机,单核(多线程无性能提升); 4. C/C++语言对应的环境: 1. G++ 7.2.0 (-O2,C++17),支持.cpp/.cc; 2. G++ 7.2.0 with many lib (-O2,C++17),支持.cpp/.cc; 1. ; 3. 平台上编译会自动加:_BOTZONE_ONLINE宏,用此区分线上线下; 5. 对战错误提示: 1. TLE:超时; 2. MLE:超内存; 3. OLE:输出数据量过大; 4. NJ:输出JSON格式出错; 5. RE:运行时错误; 6. 调试: 1. 注册登录botzone; 2. 头像旁边点【本地AI配置】获取AI秘钥/URL; 1. 我的秘钥:yexiang841; 2. 我的URL:https://www.botzone.org.cn/api/5eacca18a96e206b647a5068/yexiang841/localai; 3. (TODO); #### [附][数据类型内存占用] ###### 32位编译器类型 - unsigned char :1个字节 - char :1个字节 - char*(即指针变量): 4个字节(32位的寻址空间是2^32, 即32个bit,也就是4个字节。同理64位编译器) - short int : 2个字节 - int: 4个字节 - unsigned int : 4个字节 - float: 4个字节 - double: 8个字节 - long: 4个字节 - unsigned long: 4个字节 - long long: 8个字节 ###### 64位编译器 - unsigned char :1个字节 - char :1个字节 - char*(即指针变量): 8个字节 - short int : 2个字节 - int: 4个字节 - unsigned int : 4个字节 - float: 4个字节 - double: 8个字节 - long: 8个字节 - unsigned long: 8个字节 - long long: 8个字节