コード例 #1
0
        /// <summary>
        /// staticなテーブルの初期化
        /// 起動時にInitializerから一度だけ呼び出される。
        /// 普段は呼び出してはならない。
        /// </summary>
        public static void Init()
        {
            ALL_BB  = new Bitboard(0x1FFFFFF);
            ZERO_BB = new Bitboard(0U);

            Bitboard FILE1_BB = new Bitboard(0x1fU << (5 * 0));
            Bitboard FILE2_BB = new Bitboard(0x1fU << (5 * 1));
            Bitboard FILE3_BB = new Bitboard(0x1fU << (5 * 2));
            Bitboard FILE4_BB = new Bitboard(0x1fU << (5 * 3));
            Bitboard FILE5_BB = new Bitboard(0x1fU << (5 * 4));

            FILE_BB = new Bitboard[(int)File.NB]
            {
                FILE1_BB, FILE2_BB, FILE3_BB, FILE4_BB, FILE5_BB
            };

            Bitboard RANK1_BB = new Bitboard(0x108421 << 0);
            Bitboard RANK2_BB = new Bitboard(0x108421 << 1);
            Bitboard RANK3_BB = new Bitboard(0x108421 << 2);
            Bitboard RANK4_BB = new Bitboard(0x108421 << 3);
            Bitboard RANK5_BB = new Bitboard(0x108421 << 4);

            RANK_BB = new Bitboard[(int)Rank.NB]
            {
                RANK1_BB, RANK2_BB, RANK3_BB, RANK4_BB, RANK5_BB
            };

            EnemyFieldBB = new Bitboard[(int)Color.NB] {
                RANK1_BB, RANK5_BB
            };

            SQUARE_BB = new Bitboard[(int)Square.NB + 1];

            ForwardRanksBB = new Bitboard[(int)Color.NB, (int)Rank.NB]
            {
                { ZERO_BB, RANK1_BB, RANK1_BB | RANK2_BB, ~(RANK4_BB | RANK5_BB), ~RANK5_BB },
                { ~RANK1_BB, ~(RANK1_BB | RANK2_BB), RANK4_BB | RANK5_BB, RANK5_BB, ZERO_BB }
            };

            // 2つの升のfileの差、rankの差のうち大きいほうの距離を返す。sq1,sq2のどちらかが盤外ならINT_MAXが返る。
            int dist(Square sq1, Square sq2)
            {
                return((!sq1.IsOk() || !sq2.IsOk()) ? int.MaxValue :
                       System.Math.Max(System.Math.Abs(sq1.ToFile() - sq2.ToFile()), System.Math.Abs(sq1.ToRank() - sq2.ToRank())));
            }

            BetweenBB_   = new Bitboard[89];
            BetweenIndex = new UInt16[(int)Square.NB + 1, (int)Square.NB + 1];


            // 1) SquareWithWallテーブルの初期化。

/*
 *          for (Square sq = Square.ZERO; sq < Square.NB; ++sq)
 *              SquareWithWallExtensions.SquareToSqww[sq.ToInt()] = (SquareWithWall)
 *                  ((int)SquareWithWall.SQWW_11
 + sq.ToFile().ToInt() * (int)SquareWithWall.SQWW_L
 + sq.ToRank().ToInt() * (int)SquareWithWall.SQWW_D);
 */

            // 2) direct_tableの初期化

            Util.direc_table = new Directions[(int)Square.NB + 1, (int)Square.NB + 1];

            for (var sq1 = Square.ZERO; sq1 < Square.NB; ++sq1)
            {
                for (var dir = Direct.ZERO; dir < Direct.NB; ++dir)
                {
                    // dirの方角に壁にぶつかる(盤外)まで延長していく。このとき、sq1から見てsq2のDirectionsは (1 << dir)である。
                    var delta = (int)dir.ToDeltaWW();
                    for (var sq2 = sq1.ToSqww() + delta; sq2.IsOk(); sq2 += delta)
                    {
                        Util.direc_table[(int)sq1, (int)sq2.ToSquare()] = dir.ToDirections();
                    }
                }
            }
            // 3) Square型のsqの指す升が1であるBitboardがSquareBB。これをまず初期化する。

            // SQUARE_BBは上記のRANK_BBとFILE_BBを用いて初期化すると楽。
            for (Square sq = Square.ZERO; sq < Square.NB; ++sq)
            {
                File f = sq.ToFile();
                Rank r = sq.ToRank();

                // 筋と段が交差するところがSQUARE_BB
                SQUARE_BB[sq.ToInt()] = FILE_BB[f.ToInt()] & RANK_BB[r.ToInt()];
            }

            // 4) 遠方利きのテーブルの初期化
            //  thanks to Apery (Takuya Hiraoka)

            // 引数のindexをbits桁の2進数としてみなす。すなわちindex(0から2^bits-1)。
            // 与えられたmask(1の数がbitsだけある)に対して、1のbitのいくつかを(indexの値に従って)0にする。
            Bitboard indexToOccupied(int index, int bits, Bitboard mask)
            {
                var result = ZERO_BB;

                for (int i = 0; i < bits; ++i)
                {
                    Square sq = mask.Pop();
                    if ((index & (1 << i)) != 0)
                    {
                        result ^= new Bitboard(sq);
                    }
                }
                return(result);
            }

            // Rook or Bishop の利きの範囲を調べて bitboard で返す。
            // occupied  障害物があるマスが 1 の bitboard
            // n = 0 右上から左下 , n = 1 左上から右下
            Bitboard effectCalc(Square square, Bitboard occupied, int n)
            {
                Bitboard result = ZERO_BB;

                // 角の利きのrayと飛車の利きのray

                SquareWithWall[] deltaArray;
                if (n == 0)
                {
                    deltaArray = new SquareWithWall[2]
                    {
                        SquareWithWall.SQWW_RU, SquareWithWall.SQWW_LD
                    }
                }
                ;
                else
                {
                    deltaArray = new SquareWithWall[2]
                    {
                        SquareWithWall.SQWW_RD, SquareWithWall.SQWW_LU
                    }
                };

                foreach (var delta in deltaArray)
                {
                    // 壁に当たるまでsqを利き方向に伸ばしていく
                    for (var sq = (SquareWithWall)(square.ToSqww().ToInt() + delta.ToInt()); sq.IsOk(); sq += delta.ToInt())
                    {
                        result ^= sq.ToSquare();                    // まだ障害物に当っていないのでここまでは利きが到達している

                        if ((occupied & sq.ToSquare()).IsNotZero()) // sqの地点に障害物があればこのrayは終了。
                        {
                            break;
                        }
                    }
                }
                return(result);
            }

            // pieceをsqにおいたときに利きを得るのに関係する升を返す
            Bitboard calcBishopEffectMask(Square sq, int n)
            {
                Bitboard result;

                result = ZERO_BB;

                // 外周は角の利きには関係ないのでそこは除外する。
                for (Rank r = Rank.RANK_2; r <= Rank.RANK_4; ++r)
                {
                    for (File f = File.FILE_2; f <= File.FILE_4; ++f)
                    {
                        var dr = sq.ToRank() - r;
                        var df = sq.ToFile() - f;
                        // dr == dfとdr != dfとをnが0,1とで切り替える。
                        if (System.Math.Abs(dr) == System.Math.Abs(df) &&
                            ((((int)dr == (int)df) ? 1 : 0) ^ n) != 0)
                        {
                            result ^= Util.MakeSquare(f, r);
                        }
                    }
                }

                // sqの地点は関係ないのでクリアしておく。
                result &= ~new Bitboard(sq);

                return(result);
            }

            // 角の利きテーブルの初期化
            for (int n = 0; n < 2; ++n)
            {
                int index = 0;
                for (var sq = Square.ZERO; sq < Square.NB; ++sq)
                {
                    // sqの升に対してテーブルのどこを見るかのindex
                    BishopEffectIndex[n, sq.ToInt()] = index;

                    // sqの地点にpieceがあるときにその利きを得るのに関係する升を取得する
                    var mask = calcBishopEffectMask(sq, n);
                    BishopEffectMask[n, sq.ToInt()] = mask;

                    // p[0]とp[1]が被覆していると正しく計算できないのでNG。
                    // Bitboardのレイアウト的に、正しく計算できるかのテスト。
                    // 縦型Bitboardであるならp[0]のbit63を余らせるようにしておく必要がある。
                    //ASSERT_LV3(!(mask.cross_over()));

                    // sqの升用に何bit情報を拾ってくるのか
                    int bits = mask.PopCount();

                    // 参照するoccupied bitboardのbit数と、そのbitの取りうる状態分だけ..
                    int num = 1 << bits;

                    for (int i = 0; i < num; ++i)
                    {
                        Bitboard occupied = indexToOccupied(i, bits, mask);
                        // 初期化するテーブル
                        BishopEffectBB[n, index + (int)OccupiedToIndex(occupied & mask, mask)] = effectCalc(sq, occupied, n);
                    }
                    index += num;
                }

                // 盤外(SQ_NB)に駒を配置したときに利きがZERO_BBとなるときのための処理
                BishopEffectIndex[n, (int)Square.NB] = index;

                // 何番まで使ったか出力してみる。(確保する配列をこのサイズに収めたいので)
                // cout << index << endl;
            }

            // 5. 飛車の縦方向の利きテーブルの初期化
            // ここでは飛車の利きを使わずに初期化しないといけない。

            for (Rank rank = Rank.RANK_1; rank <= Rank.RANK_5; ++rank)
            {
                // sq = SQ_11 , SQ_12 , ... , SQ_15
                Square sq = Util.MakeSquare(File.FILE_1, rank);

                const int num1s = 3;
                for (int i = 0; i < (1 << num1s); ++i)
                {
                    // iはsqに駒をおいたときに、その筋の2段~8段目の升がemptyかどうかを表現する値なので
                    // 1ビットシフトして、1~5段目の升を表現するようにする。
                    int      ii = i << 1;
                    Bitboard bb = ZERO_BB;
                    for (int r = sq.ToRank().ToInt() - 1; r >= (int)Rank.RANK_1; --r)
                    {
                        bb |= Util.MakeSquare(sq.ToFile(), (Rank)r);
                        if ((ii & (1 << r)) != 0)
                        {
                            break;
                        }
                    }
                    for (int r = sq.ToRank().ToInt() + 1; r <= (int)Rank.RANK_5; ++r)
                    {
                        bb |= Util.MakeSquare(sq.ToFile(), (Rank)r);
                        if ((ii & (1 << r)) != 0)
                        {
                            break;
                        }
                    }
                    RookFileEffectBB[(int)rank, i] = bb.p;
                    // RookEffectFile[RANK_NB][x] には値を代入していないがC++の規約によりゼロ初期化されている。
                }
            }

            // 飛車の横の利き
            for (File file = File.FILE_1; file <= File.FILE_5; ++file)
            {
                // sq = SQ_11 , SQ_21 , ... , SQ_NBまで
                Square sq = Util.MakeSquare(file, Rank.RANK_1);

                const int num1s = 3;
                for (int i = 0; i < (1 << num1s); ++i)
                {
                    int      ii = i << 1;
                    Bitboard bb = ZERO_BB;
                    for (int f = (int)sq.ToFile() - 1; f >= (int)File.FILE_1; --f)
                    {
                        bb |= Util.MakeSquare((File)f, sq.ToRank());
                        if ((ii & (1 << f)) != 0)
                        {
                            break;
                        }
                    }
                    for (int f = (int)sq.ToFile() + 1; f <= (int)File.FILE_5; ++f)
                    {
                        bb |= Util.MakeSquare((File)f, sq.ToRank());
                        if ((ii & (1 << f)) != 0)
                        {
                            break;
                        }
                    }

                    RookRankEffectBB[(int)file, i] = bb;
                    // RookRankEffect[FILE_NB][x] には値を代入していないがC++の規約によりゼロ初期化されている。
                }
            }


            // 6. 近接駒(+盤上の利きを考慮しない駒)のテーブルの初期化。
            // 上で初期化した、香・馬・飛の利きを用いる。

            foreach (var sq in All.Squares())
            {
                // 玉は長さ1の角と飛車の利きを合成する
                KingEffectBB[(int)sq] = BishopEffect(sq, ALL_BB) | RookEffect(sq, ALL_BB);
            }

            foreach (var c in All.Colors())
            {
                foreach (var sq in All.Squares())
                {
                    // 障害物がないときの香の利き
                    // これを最初に初期化しないとlanceEffect()が使えない。
                    LanceStepEffectBB[(int)sq, (int)c] = RookFileEffect(sq, ZERO_BB) & ForwardRanks(c, sq.ToRank());
                }
            }

            foreach (var c in All.Colors())
            {
                foreach (var sq in All.Squares())
                {
                    // 歩は長さ1の香の利きとして定義できる
                    PawnEffectBB[(int)sq, (int)c] = LanceEffect(c, sq, ALL_BB);

                    // 桂の利きは、歩の利きの地点に長さ1の角の利きを作って、前方のみ残す。
                    Bitboard tmp  = ZERO_BB;
                    Bitboard pawn = LanceEffect(c, sq, ALL_BB);
                    if (pawn.IsNotZero())
                    {
                        Square   sq2   = pawn.Pop();
                        Bitboard pawn2 = LanceEffect(c, sq2, ALL_BB); // さらに1つ前
                        if (pawn2.IsNotZero())
                        {
                            tmp = BishopEffect(sq2, ALL_BB) & RANK_BB[(int)pawn2.Pop().ToRank()];
                        }
                    }
                    KnightEffectBB[(int)sq, (int)c] = tmp;

                    // 銀は長さ1の角の利きと長さ1の香の利きの合成として定義できる。
                    SilverEffectBB[(int)sq, (int)c] = LanceEffect(c, sq, ALL_BB) | BishopEffect(sq, ALL_BB);

                    // 金は長さ1の角と飛車の利き。ただし、角のほうは相手側の歩の行き先の段でmaskしてしまう。
                    Bitboard e_pawn = LanceEffect(c.Not(), sq, ALL_BB);
                    Bitboard mask   = ZERO_BB;
                    if (e_pawn.IsNotZero())
                    {
                        mask = RANK_BB[(int)e_pawn.Pop().ToRank()];
                    }
                    GoldEffectBB[(int)sq, (int)c] = (BishopEffect(sq, ALL_BB) & ~mask) | RookEffect(sq, ALL_BB);

                    // 障害物がないときの角と飛車の利き
                    BishopStepEffectBB[(int)sq] = BishopEffect(sq, ZERO_BB);
                    RookStepEffectBB[(int)sq]   = RookEffect(sq, ZERO_BB);
                }
            }


            // 7) 二歩用のテーブル初期化

            for (int i = 0; i < 0x20; ++i)
            {
                Bitboard b = ZERO_BB;
                for (int k = 0; k < 5; ++k)
                {
                    if ((i & (1 << k)) == 0)
                    {
                        b |= FILE_BB[k];
                    }
                }

                PAWN_DROP_MASK_BB[i].p = b.p;
            }

            // 8) BetweenBB , LineBBの初期化
            {
                UInt16 between_index = 1;
                // BetweenBB[0] == ZERO_BBであることを保証する。

                foreach (var s1 in All.Squares())
                {
                    foreach (var s2 in All.Squares())
                    {
                        // 十字方向か、斜め方向かだけを判定して、例えば十字方向なら
                        // rookEffect(sq1,Bitboard(s2)) & rookEffect(sq2,Bitboard(s1))
                        // のように初期化したほうが明快なコードだが、この初期化をそこに依存したくないので愚直にやる。

                        // これについてはあとで設定する。
                        if (s1 >= s2)
                        {
                            continue;
                        }

                        // 方角を用いるテーブルの初期化
                        if (Util.DirectionsOf(s1, s2) != Directions.ZERO)
                        {
                            Bitboard bb = ZERO_BB;
                            // 間に挟まれた升を1に
                            int delta = (s2 - s1) / dist(s1, s2);
                            for (Square s = s1 + delta; s != s2; s += delta)
                            {
                                bb |= s;
                            }

                            // ZERO_BBなら、このindexとしては0を指しておけば良いので書き換える必要ない。
                            if (bb.IsZero())
                            {
                                continue;
                            }

                            BetweenIndex[(int)s1, (int)s2] = between_index;
                            BetweenBB_[between_index++]    = bb;
                        }
                    }
                }

                //		    ASSERT_LV1(between_index == 785);

                // 対称性を考慮して、さらにシュリンクする。
                foreach (var s1 in All.Squares())
                {
                    foreach (var s2 in All.Squares())
                    {
                        if (s1 > s2)
                        {
                            BetweenIndex[(int)s1, (int)s2] = BetweenIndex[(int)s2, (int)s1];
                        }
                    }
                }


                LineBB_ = new Bitboard[(int)Square.NB, 4];

                for (var s1 = Square.ZERO; s1 < Square.NB; ++s1)
                {
                    for (int d = 0; d < 4; ++d)
                    {
                        // BishopEffect0 , RookRankEffect , BishopEffect1 , RookFileEffectを用いて初期化したほうが
                        // 明快なコードだが、この初期化をそこに依存したくないので愚直にやる。

                        Square[] deltas = new Square[] { Square.SQ_RU, Square.SQ_R, Square.SQ_RD, Square.SQ_U };
                        int      delta  = (int)deltas[d];
                        Bitboard bb     = new Bitboard(s1);

                        // 壁に当たるまでs1から-delta方向に延長
                        for (Square s = s1; dist(s, s - delta) <= 1; s -= delta)
                        {
                            bb |= (s - delta);
                        }

                        // 壁に当たるまでs1から+delta方向に延長
                        for (Square s = s1; dist(s, s + delta) <= 1; s += delta)
                        {
                            bb |= (s + delta);
                        }

                        LineBB_[(int)s1, d] = bb;
                    }
                }
            }
        }
コード例 #2
0
 /// <summary>
 /// 盤内(True),盤外(False)
 /// </summary>
 /// <param name="sqww"></param>
 /// <returns></returns>
 public static bool IsOk(this SquareWithWall sqww)
 {
     return((sqww & SquareWithWall.SQWW_BORROW_MASK) == 0);
 }
コード例 #3
0
 public static Square ToSquare(this SquareWithWall sqww)
 {
     return((Square)(sqww.ToInt() & 0x1f));
 }
コード例 #4
0
 public static string Pretty(this SquareWithWall sqww)
 {
     return(sqww.ToSquare().Pretty());
 }
コード例 #5
0
 public static Int32 ToInt(this SquareWithWall sqww)
 {
     return((Int32)sqww);
 }