ぬるーむ

Unity初心者が誰もが知っているゲームの模倣をしています。個人的な備忘録ですが、入門書を読み終えたばかりの初心者の方は「こんなへなちょこでもいいのか!」「俺の方がうまく作れる」と作成意欲がわいたりするかもしれません。

Unityでリバーシを作ってみた 7


スポンサードリンク

AIの作成 2

合法手の数、確定石(4隅とそれに隣接する石)の数、C打ち・X打ちの数で評価する。
探索と同様、主に下記の本を参考にした。
リバーシのアルゴリズム C++&Java対応―「探索アルゴリズム」「評価関数」の設計と実装 (I・O BOOKS) | Seal Software |本 | 通販 | Amazon

Evaluatorクラス

public static class Evaluator
{
    //合法手の数に対する重み
    private static readonly float mobilityWeight= 67f;
    //確定石の数に対する重み
    private static readonly float stableWeight = 101f;
    //C打ちの数に対する重み
    private static readonly float cMoveWeight = -552f;
    //X打ちの数に対する重み
    private static readonly float xMoveWeight = -449f;
    private static LogicBoard board;

    public static float Evaluate(LogicBoard logicBoard, Stone.ColorType corrent)
    {
        board = logicBoard;

        var currentBit = board.CurrentBitBoards[(int)corrent];
        int currentMovable = CountMovableCells(corrent);

        EdgeEvaluator.Setup(currentBit);
        int currentStable = EdgeEvaluator.CountStableStone(currentBit);
        int currentCMove = EdgeEvaluator.CountCMove(currentBit);
        int currentXMove = EdgeEvaluator.CountXMove(currentBit);

        var opponentColor = Stone.GetReverseColor(corrent);
        
        var opponentBit = board.CurrentBitBoards[(int)opponentColor];
        int opponentMovable = CountMovableCells(opponentColor);

        EdgeEvaluator.Setup(opponentBit);
        int opponentStable = EdgeEvaluator.CountStableStone(opponentBit);
        int opponentCMove = EdgeEvaluator.CountCMove(opponentBit);
        int opponentXMove = EdgeEvaluator.CountXMove(opponentBit);

        float eval = (currentMovable - opponentMovable) * mobilityWeight+
            (currentStable - opponentStable) * stableWeight +
            (currentCMove - opponentCMove) * cMoveWeight +
            (currentXMove - opponentXMove) * xMoveWeight;

        return eval;
    }

    //合法手の数を数える
    private static int CountMovableCells(Stone.ColorType color)
    {
        var movable = board.GetMovableBitBoard(color);
        return LogicBoard.CountBit(movable);
    }
}

EdgeEvaluatorクラス

public class EdgeEvaluator
{
    private static ulong topLeft;
    private static ulong topRight;
    private static ulong bottomLeft;
    private static ulong bottomRight;
    private static readonly ulong topLeftMask = 0x8000000000000000;
    private static readonly ulong topRightMask = 0x0100000000000000;
    private static readonly ulong bottomLeftMask = 0x0000000000000080;
    private static readonly ulong bottomRightMask = 0x0000000000000001;

    public static void Setup(ulong bit)
    {
        //4隅を取っているか調べる
        topLeft = bit & topLeftMask;
        topRight = bit & topRightMask;
        bottomLeft = bit & bottomLeftMask;
        bottomRight = bit & bottomRightMask;
    }

    //確定石(4隅とそれに隣接する石)の数を数える
    public static int CountStableStone(ulong bit)
    {
        int cnt = 0;

        cnt += CountTopStableStone(bit);
        cnt += CountLeftStableStone(bit);
        cnt += CountBottomStableStone(bit);
        cnt += CountRightStableStone(bit);

        if (topLeft != 0) cnt++;    
        if (topRight != 0) cnt++;
        if (bottomLeft != 0) cnt++;
        if (bottomRight != 0) cnt++;

        return cnt;
    }

    //C打ちの数を数える
    public static int CountCMove(ulong bit)
    {
        ulong topLeftC1 = 0x4000000000000000;
        ulong topLeftC2 = 0x0080000000000000;
        ulong topRightC1 = 0x0200000000000000;
        ulong topRightC2 = 0x0001000000000000;
        ulong bottomLeftC1 = 0x0000000000000040;
        ulong bottomLeftC2 = 0x0000000000008000;
        ulong bottomRightC1 = 0x0000000000000002;
        ulong bottomRightC2 = 0x0000000000000100;
        int cnt = 0;

        if (topLeft == 0)
        {
            cnt += (bit & topLeftC1) > 0 ? 1 : 0;
            cnt += (bit & topLeftC2) > 0 ? 1 : 0;
        }

        if (topRight == 0)
        {
            cnt += (bit & topRightC1) > 0 ? 1 : 0;
            cnt += (bit & topRightC2) > 0 ? 1 : 0;
        }

        if (bottomLeft == 0)
        {
            cnt += (bit & bottomLeftC1) > 0 ? 1 : 0;
            cnt += (bit & bottomLeftC2) > 0 ? 1 : 0;
        }

        if (bottomRight == 0)
        {
            cnt += (bit & bottomRightC1) > 0 ? 1 : 0;
            cnt += (bit & bottomRightC2) > 0 ? 1 : 0;
        }

        return cnt;
    }

    //X打ちの数を数える
    public static int CountXMove(ulong bit)
    {
        ulong topLeftX = 0x0040000000000000;
        ulong topRightX = 0x0002000000000000;
        ulong bottomLeftX = 0x0000000000004000;
        ulong bottomRightX = 0x0000000000000200;
        int cnt = 0;

        if (topLeft == 0)
        {
            cnt += (bit & topLeftX) > 0 ? 1 : 0;
        }

        if (topRight == 0)
        {
            cnt += (bit & topRightX) > 0 ? 1 : 0;
        }

        if (bottomLeft == 0)
        {
            cnt += (bit & bottomLeftX) > 0 ? 1 : 0;
        }

        if (bottomRight == 0)
        {
            cnt += (bit & bottomRightX) > 0 ? 1 : 0;
        }

        return cnt;
    }

    //上辺の確定石の数を数える
    private static int CountTopStableStone(ulong bit)
    {
        int cnt = 0;

        cnt = CountStableStoneInLine(bit, topLeft,
            corner => corner >> 1);

        if (cnt < 6)
        {
            cnt += CountStableStoneInLine(bit, topRight,
                corner => corner << 1);
        }

        return cnt;
    }

    //右辺の確定石の数を数える
    private static int CountRightStableStone(ulong bit)
    {
        int cnt = 0;

        cnt = CountStableStoneInLine(bit, topRight,
            corner => corner >> 8);

        if (cnt < 6)
        {
            cnt += CountStableStoneInLine(bit, bottomRight,
                corner => corner << 8);
        }

        return cnt;
    }

    //下辺の確定石の数を数える
    private static int CountBottomStableStone(ulong bit)
    {
        int cnt = 0;

        cnt = CountStableStoneInLine(bit, bottomLeft,
            corner => corner >> 1);

        if (cnt < 6)
        {
            cnt += CountStableStoneInLine(bit, bottomRight,
                corner => corner << 1);
        }

        return cnt;
    }

    //左辺の確定石の数を数える
    private static int CountLeftStableStone(ulong bit)
    {
        int cnt = 0;

        cnt = CountStableStoneInLine(bit, topLeft,
            corner => corner >> 8);

        if (cnt < 6)
        {
            cnt += CountStableStoneInLine(bit, bottomLeft,
                corner => corner << 8);
        }

        return cnt;
    }

    //辺の確定石の数を数える
    private static int CountStableStoneInLine(ulong bit, ulong corner,
        Func<ulong, ulong> shift)
    {
        int cnt = 0;

        if (corner != 0)
        {
            ulong next = bit & shift(corner);

            while (next != 0 && cnt < 6)
            {
                cnt++;
                next = bit & shift(next);
            }
        }

        return cnt;
    }
}