boardgame.io 五子棋(三):增加趣味

太长不看:点击这里查看源代码

上一篇我们做了一个自己的蒙特卡洛 AI,今天我们给我们的游戏增添一点趣味。

对称性

我们知道五子棋游戏具有对称性,包含旋转和轴对称总计 8 种对称。纵使一个局面有这么多的对称局面,而 AI 却不见得可以利用这种对称性。由于 AI 不懂对称性,总是下相同的着法,咱们可以在游戏中把局面进行对称变换,让 AI 下出来的着法看似有所不同,从而增加一点趣味。大致思路就是,把人类的着法进行变换,然后把 AI 思考出来的着法进行反变换。

首先,咱们要有变换函数。新建 src/Symmetry.js 文件,并粘贴如下内容:

export function Symmetry(w, h, symm) {
    if (w < 1 || h < 1)
        throw new RangeError("width and height must be greater than 1");
    if (w !== h && symm > 3)
        throw new RangeError(`unsupported symmetry for shape [${w},${h}]`);
    else if (symm < 0 || symm > 7) throw new RangeError(`unsupported symmetry`);

    const temp = [0, 0];
    /**
     *
     * @param {number} x
     * @param {number} y
     * @param {number[]} [out]
     */
    function identity(x, y, out) {
        out = out || temp;
        out[0] = x;
        out[1] = y;
        return out;
    }

    function flipY(x, y, out) {
        return identity(x, h - 1 - y, out);
    }
    function flipX(x, y, out) {
        return identity(w - 1 - x, y, out);
    }
    function rotate180(x, y, out) {
        return identity(w - 1 - x, h - 1 - y, out);
    }

    function flipPrimaryDiagonal(x, y, out) {
        return identity(h - 1 - y, w - 1 - x, out);
    }
    function flipSecondaryDiagonal(x, y, out) {
        return identity(y, x, out);
    }
    function rotate90cw(x, y, out) {
        return identity(y, w - 1 - x, out);
    }
    function rotate90ccw(x, y, out) {
        return identity(h - 1 - y, x, out);
    }

    switch (symm) {
        case 0:
            return { map: identity, unmap: identity };
        case 1:
            return { map: flipX, unmap: flipX };
        case 2:
            return { map: flipY, unmap: flipY };
        case 3:
            return { map: rotate180, unmap: rotate180 };
        case 4:
            return { map: flipPrimaryDiagonal, unmap: flipPrimaryDiagonal };
        case 5:
            return { map: flipSecondaryDiagonal, unmap: flipSecondaryDiagonal };
        case 6:
            return { map: rotate90cw, unmap: rotate90ccw };
        case 7:
            return { map: rotate90ccw, unmap: rotate90cw };
        default:
            throw new Error(`unsupported symmetry(${symm})`);
    }
}

然后,修改 src/Game.js 文件,把对称变换加上:

import { Symmetry } from "./Symmetry";

export class Game {
	constructor(/* ... */) {
		/* ... */
		this._symmetry = Symmetry(
            BOARD_SIZE,
            BOARD_SIZE,
            Math.trunc(Math.random() * 8)
        );
	}

	/* ... */

	start() {
        if (this._started || this._stopped) return;
        
        this._client.subscribe((s) => {
            /* ... */
            if (this._aiPlayer === s.ctx.currentPlayer) {
                this._mcts.exec(this._root, this._state).then((result) => {
                    if (this._stopped) return;

                    const mov = this._unmapMove(result.bestChild.a);
                    this._client.moves.putStone(mov);
                });
            }
        });
	}

	_mapMove(id) {
        let y = Math.floor(id / BOARD_SIZE);
        let x = id % BOARD_SIZE;
        [x, y] = this._symmetry.map(x, y);
        return y * BOARD_SIZE + x;
    }

    _unmapMove(id) {
        let y = Math.floor(id / BOARD_SIZE);
        let x = id % BOARD_SIZE;
        [x, y] = this._symmetry.unmap(x, y);
        return y * BOARD_SIZE + x;
    }

    _advance(mov) {
        mov = this._mapMove(mov);
        this._state.makeMove(mov);
        /* ... */
    }
}

好了,现在每次进行游戏,都会随机选择一种对称性,来体验一下效果吧。

总结

本文介绍了如何利用五子棋的对称性增加游戏趣味。由于对称性,在训练神经网络时,我们也会将某一局面的对称局面输入给神经网络。所以,咱们添加的变换函数今后也能用上。接下来,就可以准备模型并开始训练了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值