組込み屋でもアプリがしたい! 第3局

強くなるには

さて、今回からAIのアルゴリズムを改良して強くしていきます。改良の道筋として、大きく3つが考えられます。

  • 評価関数の改良 (読みの質を高める)
  • ミニマックス法→アルファベータ法 (無駄な読みを捨てて、読みを深くする)
  • 演算の高速化の工夫 (読みのスピードを上げて、読みを深くする)

この中で、まずやるべきは評価関数の改良と思われます。というのも、現状ではAIは6手まで先読みしているにもかかわらず、2手くらいしか先読みしていない僕にすら負けるからです。これは評価関数に問題があると見るべきです。

評価関数の改良

いちばん大きいのは、「隅を取ると有利」という基本中の基本を考えていないことです。現状の評価関数は、単純に石の数を合計して評価値としています。それでは、隅を取ることを重視するにはどうすれば良いでしょうか? まず思いつくのは「重み付け」です。場所によって価値が違うなら重みを付けて合計すればよいでしょう。
今回は、次のような重みテーブルを採用します。

        // 評価の重みづけ
        private int[,] WEIGHT = {
            {+50, -10, +5, +5, +5, +5, -10, +50},
            {-10, -10, -2, -2, -2, -2, -10, -10},
            { +5,  -2, +2, +1, +1, +2,  -2,  +5},
            { +5,  -2, +1, +1, +1, +1,  -2,  +5},
            { +5,  -2, +1, +1, +1, +1,  -2,  +5},
            { +5,  -2, +2, +1, +1, +2,  -2,  +5},
            {-10, -10, -2, -2, -2, -2, -10, -10},
            {+50, -10, +5, +5, +5, +5, -10, +50}
        };

これは、次のような根拠によるものです。数値はテキトーです。

  • 四隅は最も価値が高い。
  • 四隅に隣接する各3マスは、最も取るべきでない。(相手に隅を取られやすいので)
  • それ以外の外周部は、まあまあ価値が高い。
  • 外周より1マス内側は、なるべく取るべきでない。(相手に外周を取られやすいので)

結果

図
結果はこの通り。たったこれだけのことで、僕には勝てなくなりました。
また、テストのためにAIどうしの対戦機能も実装しました。当然のごとく、前回までのAIには圧勝です。

今回のソースのスナップショット

今回のTIPS

C#での定数テーブルについて。
上記のテーブル定義で、constで定義することはできません。C#の配列は参照型であり、constの参照型はnullでしか初期化できません。

    // これはエラー
    private const int[,] WEIGHT = {
    (中略)
    };

constの代わりにreadonlyで定義することはできます。この場合、参照の変更はできなくなりますが、値の変更はできてしまいます。

    private readonly int[,] WEIGHT = {
    (中略)
    };
    // 参照の変更はできない
    WEIGHT = null; // ←エラー
    // 値の変更はできてしまう
    WEIGHT[0,0] = 0;

どうすればいいのかな?