一个学习项目,第一个版本已大概完成,虽然我觉得它还不是很厉害,但我疑似并不是他的对手emmmmm
总而言之,对于一个完全不懂国际象棋的人,能做出一个比自己还强的AI,神经网络还是挺有趣的
elo 到达 1500 我就满意了
代码执行方式
uvicorn main:app --reload-
棋盘接结构
- 棋盘为8×8的64个黑白交替方格,浅色棋格称为“白格”,深色棋格称为“黑格”。摆放时右下角需为白格
- 横向为“行”(Rank),纵向为“列”(File),由字母a-h(file)和数字1-8(rank)标识每个格子
-
棋子配置
- 双方各执16枚棋子,包括:1王、1后、2车、2象、2马、8兵
- 初始摆法:白棋位于第1-2行,黑棋位于第7-8行。
- 白棋的后置于白格;黑棋的后置于黑格。
- 白棋从左至右棋子摆放顺序为:RNBQKBNR。黑棋与其对应
-
基础规则
- 王(King):横、直、斜均可移动一格,不可进入被攻击的格子。特殊情况下可进行[王车易位]
- 后(Queen):任意方向不限格数移动,威力最大
- 车(Rook):横、直移动不限格数,不可斜走
- 象(Bishop):斜线移动不限格数,开局时一象占白格,一象占黑格
- 马(Knight):走“日”字形(行2列1或列2行1),可越子
- 兵(Pawn):仅直进,第一步可选一或两格,之后每步一格;吃子时斜进一格
-
特殊规则
- 吃过路兵(En Passant):若敌方兵第一步走两格至己方兵相邻位置,己方可立即斜吃该兵,但仅限下一步执行
- 兵的升变(Promotion):兵抵达对方底线时,必须升变为己方的后、车、象或马(不可变王或兵)
- 王车易位(Castling):每局一次,王向车横向移动两格,车越过王至相邻格。需满足以下条件:
- 王与车未移动过,且位于同一横行(即不能与兵升变的车易位);
- 中间无其他棋子;
- 王未被将军,且经过和到达的格子不受敌方棋子攻击
-
胜利条件
- 将死(Checkmate):使对方王无法避开将军即为胜局
- 认输或超时:一方主动认输或比赛时间耗尽
-
和局判定
- 逼和(Stalemate):一方未被将军但无合法移动
- 任何一方以任何合法走法都无法将死对方,这种“和棋”称“死局”
- 三次重复局面:同一局面出现三次,且轮到同一方行棋
- 50回合规则:连续50回合未吃子且未移动兵
- 双方同意和棋:需在行棋时提出,对方接受即生效
使用 board.shredder_fen() 可打印出当前棋局的详细描述
print(board.shredder_fen())
# rnbqkb1r/pp2pppp/2p2n2/3p4/3P1B2/4PN2/PPP2PPP/RN1QKB1R b HAha - 0 4- 第一个字符串表示棋子分布每层以
/分隔,从第八层到第一层 - 第二个字符串表示行棋方,
b代表black - 第三个字符串表示特殊走法权利
- 大写
H与A分别表示白方在 H 与 a 文件的车仍保留易位权; - 小写
h与a分别表示黑方在 h- 与 a- 文件的车仍保留易位权 -表示无一方具有王车易位权
- 大写
- 第四个字符串表示是否有吃过路兵的可能
- 第五个数字表示半回合计数:自上一次“吃子”或“兵着”之后,已经走过的半回合(half‑move)数,用于五十回合和棋规则
- 全回合计数记录:目前是第几回合(full move),从1开始计数,每当黑方走完则+1
一共 8*8 = 64 个格子
棋子类型:6 + 1(空格子) = 7 种,使用 3 bits 编码
棋子颜色:(0 = 白方,1 = 黑方),使用 1 bit 编码
因此整个棋盘需要 64 * (3 + 1) = 256 bits 编码
再加上一个当前玩家的回合,(0 = 白方,1 = 黑方)
由于 +1 的编码方式有些难以实现,所以多加一个 bit 用于编码
从而需要 64 * (3 + 1 + 1) bits 进行编码
白棋使用 1, 2, 3, 4, 5, 6
黑棋使用 9, 10, 11, 12, 13, 14
空白格为 0
思路来源于:twichchess
将不同特征(如棋子种类、易位权利、吃过路标记)的多值编码用多个二值通道(bit‑planes)表示,可以让卷积核更容易在局部感受野内学习到这些离散特征
将每个格子的原始编码(0–15)拆分为四条二值位平面(bit‑planes),再加上一个回合平面,共 5 个通道输入给卷积网络。
将王车易位、吃过路兵做特殊编码。
给每个棋子赋分,数据来源:Simplified Evaluation Function
特殊赋分:
- 孤兵与连通兵
- 活跃度
- 被将军惩罚
- 将死特判
TODO:
- 特殊操作加权,如 将军、绝杀、吃子、升变
每一步操作的得分评估函数:
更新了,但是暂时没时间写清楚
由于数据范围较大,因此做了简单的归一化,用当前得分除以当前对局得分绝对值的最大值。
-
将棋局分为:开局、中局、残局。以优化棋局评估函数
-
更新编码结构,将每一个旗子都编码为一个位面
-
更新神经网络结构,现在的神经网络结构还是太随机了