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:Jifashi_619/go-data-set.git
神经网络权重文件地址:https://gitee.com/Jifashi_619/saved_model
多写注释。
前端:
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/
git clone https://gitee.com/Jifashi_619/saved_model.git
python3 main.py
一个棋子的上下左右四个格子若为空,则称为棋子的气,当四个气都被其他棋子占据之后,这个子就被称为死棋。
多个相邻(指相邻的上下左右格子)的同色棋子组成一个棋串,棋串会按整体去计算气,若气为0,则应该从棋盘上提去。
围棋不允许出现重复(指完全一样)的棋形,所以当一方被吃一子的时候,不能马上吃回,必须先去其他地方落子,这就是打劫。打劫只会发生在被吃单个棋子的情况,吃多个马上吃回并不会导致棋盘重复。
去除棋盘上所有的死棋后,黑白计算棋子的个数+棋盘围空的数量,黑需要贴6目半(目即棋子围起来的空,1空为1目),多者获胜。
棋盘是一个19*19的二维数组,0代表空,-1为白子,1为黑子,每次落子后程序对数组进行处理
程序中棋盘边界为0-18,用户层为1-19
Honinbo会先判断落子是否合法,即x,y坐标是否在(1,19)的范围内。再判断该点是否处于打劫状态
combine(x,y)
会尝试将当前落子点与上下左右四个方向匹配,若找到同色棋子,则会合并到棋串当中。
//棋串数据结构:
{
black:{
1:{
2: {
num:19
}
},
19:[{x:1,y:2}]
}
}
即棋串按黑白二色区分,次级键是x,y坐标,最后则是这个棋串的编号。19开始则为棋串数组(因为棋盘只会是0-18的点),管理了该棋串共有哪些元素。
getStringInfo(x,y)
会根据传入的坐标获取棋串,或者返回该点不存在棋串
getSrcString(su,sd,sl,sr)
会对四个方向的棋串进行选举,决定基准棋串。
combineCurrentString(x,y,su,sd,sl,sr,src)
对这些棋串进行合并操作。
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];
}
每次落子的时候,若出现杀棋也只会是上下左右四个方向的相邻格,因此:
kill(x,y)
会获取上下左右四个点的坐标,若是异色棋子则进行处理,交给checkKill
判断
checkKill(x,y,flag)
从棋串中按编号查询到该棋串数组,进行遍历:
若四个方向没有为空的点,则判断为死棋,继续递归。
若有空格则直接判断为活棋,return
棋盘边界与同色棋子也是死棋,因为它们都算是占了一个气眼
cleanString(num)
,从棋串中将棋子信息清除围棋不允许落子导致自身死棋,因此未杀棋就需要交给kill(x,y)
判断,只是这里的flag颜色标识是判断的自身
若自身死棋则交给suicide(x,y)
将刚才的落子从棋串中清除。
落子基本判断
combine()
kill()
suicide()
前后端通信有两种方式:Tcp和命令行(暂不支持),Tcp传输Json数据。
{
"operator":"run",
"board": [],
"color": "black"
}
run命令代表前端要求引擎进行分析。
{
"operator":"saveGoban",
"goban": "sgf..."
}
引擎会将这些数据入库保存。
提取器(feature.py)->评价器(value.py)、策略器(policy.py)->结果
评价器:均方差损失
策略器:交叉熵损失
def forward(winner, self_play_winner, probas, self_play_probas):
value_error = (self_play_winner - winner) ** 2
policy_error = torch.sum((-self_play_probas * (1e-6 + probas).log()), 1)
total_error = (value_error.view(-1) + policy_error).mean()
return total_error
由于棋盘状态是:0->空,1->落黑子,-1->落白子,与图像识别类似,所以考虑用卷积神经网络。
输入给提取器的共23通道,如下:
1.全部是自己的棋 2-8. 最近7步 棋盘上是否有自己的棋 9,10,11自己的棋子分别还剩1 2 3 口气的棋盘
12全部是对手的棋 13-19.最近7步 棋盘上是否有对手的棋 20,21,22对手的棋子分别还剩1 2 3 口气的棋盘 23. 全1或全-1 表示目前是谁在落子
提取器输出10通道
评价器输出单通道的胜率值
策略器输出[1,361]
的矩阵,对应每个点的落子概率
引擎从策略器的输出中取出5个概率最大的点,并且是合法的落子点,返回给前端
后续会接入蒙特卡洛树,未完待续。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。