# Honinbo **Repository Path**: lzs_2016/honinbo ## Basic Information - **Project Name**: Honinbo - **Description**: 开源的围棋AI软件,前端Electron + Vue,后端Python+torch,利用卷积神经网络和强化学习,提供一个强大的围棋引擎 - **Primary Language**: Python - **License**: GPL-2.0 - **Default Branch**: product - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 32 - **Created**: 2021-10-14 - **Last Updated**: 2021-10-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Honinbo Honinbo是一款开源的围棋ai程序,名称来源于日本古棋圣【本因坊秀策】。 # 技术架构 前端: Electron + Vue + Node.js 引擎: Python + torch + sqlite # 开发流程 您如果想要加入本项目,请添加QQ群790148267。 可能需要的软件:Visual Studio Code,Pycharm,fork(一种免费的git管理工具) 开发新功能时从product分支签出新分支,在staging分支进行开发,最后测试完毕由管理员合并至product分支。 分支名字考虑用中文名,可以用xxx/xxxx的方式创建在文件夹内的分支,比如feature/xxx,则该分支会出现在feature文件夹下。 数据集地址: git@gitee.com:onlyyyy_admin/go-data-set.git 多写注释。 # 🥂安装 前端: ``` cd /honinbo; # 安装 npm i; # 如果网路卡顿 尝试以下命令进行安装 npm i cnpm -g; cnpm i #运行 npm run dev; ``` 引擎: ``` cd /honinbo/engine pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ python3 main.py ``` # 前端部分 ## 围棋规则浅谈 1. 吃子 一个棋子的上下左右四个格子若为空,则称为棋子的气,当四个气都被其他棋子占据之后,这个子就被称为死棋。 多个相邻(指相邻的上下左右格子)的同色棋子组成一个棋串,棋串会按整体去计算气,若气为0,则应该从棋盘上提去。 2. 打劫 围棋不允许出现重复(指完全一样)的棋形,所以当一方被吃一子的时候,不能马上吃回,必须先去其他地方落子,这就是打劫。打劫只会发生在被吃单个棋子的情况,吃多个马上吃回并不会导致棋盘重复。 3. 胜负 去除棋盘上所有的死棋后,黑白计算棋子的个数+棋盘围空的数量,黑需要贴6目半(目即棋子围起来的空,1空为1目),多者获胜。 ## 围棋逻辑实现 ### 棋盘数据结构 棋盘是一个19*19的二维数组,0代表空,-1为白子,1为黑子,每次落子后程序对数组进行处理 程序中棋盘边界为0-18,用户层为1-19 ### 落子 1. Honinbo会先判断落子是否合法,即x,y坐标是否在(1,19)的范围内。再判断该点是否处于打劫状态 2. `combine(x,y)`会尝试将当前落子点与上下左右四个方向匹配,若找到同色棋子,则会合并到棋串当中。 ```js //棋串数据结构: { black:{ 1:{ 2: { num:19 } }, 19:[{x:1,y:2}] } } ``` 即棋串按黑白二色区分,次级键是x,y坐标,最后则是这个棋串的编号。19开始则为棋串数组(因为棋盘只会是0-18的点),管理了该棋串共有哪些元素。 3. `getStringInfo(x,y)`会根据传入的坐标获取棋串,或者返回该点不存在棋串 4. `getSrcString(su,sd,sl,sr)`会对四个方向的棋串进行选举,决定基准棋串。 5. `combineCurrentString(x,y,su,sd,sl,sr,src)`对这些棋串进行合并操作。 ```js if (sd > 0 && sd !== src) { console.log("合并sd :>> ", sd); subString[src] = subString[src].concat(subString[sd]); for (let key in subString) { if (key < 19) { for (let subKey in subString[key]) { if (subString[key][subKey] === sd) { subString[key][subKey] = src; } } } } delete subString[sd]; } ``` ### 吃子、杀棋 每次落子的时候,若出现杀棋也只会是上下左右四个方向的相邻格,因此: 1. `kill(x,y)` 会获取上下左右四个点的坐标,若是异色棋子则进行处理,交给`checkKill`判断 2. `checkKill(x,y,flag)` 从棋串中按编号查询到该棋串数组,进行遍历: - 若四个方向没有为空的点,则判断为死棋,继续递归。 - 若有空格则直接判断为活棋,`return` - 棋盘边界与同色棋子也是死棋,因为它们都算是占了一个气眼 3. 若出现杀棋则交给`cleanString(num)`,从棋串中将棋子信息清除 ### 自身死棋 围棋不允许落子导致自身死棋,因此未杀棋就需要交给`kill(x,y)`判断,只是这里的flag颜色标识是判断的自身 若自身死棋则交给`suicide(x,y)`将刚才的落子从棋串中清除。 ### 总结整体流程 1. 落子基本判断 2. combine() 3. kill() 4. suicide() # ⏳ 引擎部分 ## 通信 前后端通信有两种方式:Tcp和命令行(暂不支持),Tcp传输Json数据。 ### 引擎分析 ```json { "operator":"run", "board": [], "color": "black" } ``` run命令代表前端要求引擎进行分析。 ### 保存前端的棋谱 ```json { "operator":"saveGoban", "goban": "sgf..." } ``` 引擎会将这些数据入库保存。 # 未完待续