Ejemplo n.º 1
0
// Bitboard関連の各種テーブルの初期化。
void Bitboards::init()
{
	// ------------------------------------------------------------
	//        Bitboard関係のテーブルの初期化
	// ------------------------------------------------------------

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

	for (auto sq : SQ)
		sqww_table[sq] = SquareWithWall(SQWW_11 + (int32_t)file_of(sq) * SQWW_L + (int32_t)rank_of(sq) * SQWW_D);


	// 2) direct_tableの初期化

	for (auto sq1 : SQ)
		for (auto dir = Effect8::DIRECT_ZERO; dir < Effect8::DIRECT_NB; ++dir)
		{
			// dirの方角に壁にぶつかる(盤外)まで延長していく。このとき、sq1から見てsq2のDirectionsは (1 << dir)である。
			auto delta = Effect8::DirectToDeltaWW(dir);
			for (auto sq2 = to_sqww(sq1) + delta; is_ok(sq2); sq2 += delta)
			Effect8::direc_table[sq1][sqww_to_sq(sq2)] = Effect8::to_directions(dir);
		}


	// 3) Square型のsqの指す升が1であるBitboardがSquareBB。これをまず初期化する。

	for (auto sq : SQ)
	{
		Rank r = rank_of(sq);
		File f = file_of(sq);
		SquareBB[sq].p[0] = (f <= FILE_7) ? ((uint64_t)1 << (f * 9 + r)) : 0;
		SquareBB[sq].p[1] = (f >= FILE_8) ? ((uint64_t)1 << ((f - FILE_8) * 9 + r)) : 0;
	}


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

	// 引数のindexをbits桁の2進数としてみなす。すなわちindex(0から2^bits-1)。
	// 与えられたmask(1の数がbitsだけある)に対して、1のbitのいくつかを(indexの値に従って)0にする。
	auto indexToOccupied = [](const int index, const int bits, const Bitboard& mask_)
	{
		auto mask = mask_;
		auto result = ZERO_BB;
		for (int i = 0; i < bits; ++i)
		{
			const Square sq = mask.pop();
			if (index & (1 << i))
			result ^= sq;
		}
		return result;
	};

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

		// 角の利きのrayと飛車の利きのray
		const SquareWithWall deltaArray[2][2] = { { SQWW_RU, SQWW_LD },{ SQWW_RD, SQWW_LU} };
		for (auto delta : deltaArray[n])
		{
			// 壁に当たるまでsqを利き方向に伸ばしていく
			for (auto sq = to_sqww(square) + delta; is_ok(sq); sq += delta)
			{
				result ^= sqww_to_sq(sq); // まだ障害物に当っていないのでここまでは利きが到達している

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

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

		// 外周は角の利きには関係ないのでそこは除外する。
		for (Rank r = RANK_2; r <= RANK_8; ++r)
			for (File f = FILE_2; f <= FILE_8; ++f)
			{
				auto dr = rank_of(sq) - r;
				auto df = file_of(sq) - f;
				// dr == dfとdr != dfとをnが0,1とで切り替える。
				if (abs(dr) == abs(df)
					&& (!!((int)dr == (int)df) ^ n ))
						result ^= (f | r);
			}

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

		return result;
	};
  
	// 角の利きテーブルの初期化
	for (int n : { 0 , 1 })
	{
		int index = 0;
		for (auto sq : SQ)
		{
			// sqの升に対してテーブルのどこを見るかのindex
			BishopEffectIndex[n][sq] = index;

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

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

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

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

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

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

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

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

	for (Rank rank = RANK_1; rank <= RANK_9 ; ++rank)
	{
		// sq = SQ_11 , SQ_12 , ... , SQ_19
		Square sq = FILE_1 | rank;

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

	// 飛車の横の利き
	for (File file = FILE_1 ; file <= FILE_9 ; ++file )
	{
		// sq = SQ_11 , SQ_21 , ... , SQ_NBまで
		Square sq = file | RANK_1;
		
		const int num1s = 7;
		for (int i = 0; i < (1 << num1s); ++i)
		{
			int ii = i << 1;
			Bitboard bb = ZERO_BB;
			for (int f = file_of(sq) - 1; f >= FILE_1; --f)
			{
				bb |= (File)f | rank_of(sq);
				if (ii & (1 << f))
					break;
			}
			for (int f = file_of(sq) + 1; f <= FILE_9; ++f)
			{
				bb |= (File)f | rank_of(sq);
				if (ii & (1 << f))
					break;
			}
			RookRankEffect[file][i] = bb;
			// RookRankEffect[FILE_NB][x] には値を代入していないがC++の規約によりゼロ初期化されている。
		}
	}

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

	for (auto sq : SQ)
	{
		// 玉は長さ1の角と飛車の利きを合成する
		KingEffectBB[sq] = bishopEffect(sq, ALL_BB) | rookEffect(sq, ALL_BB);
	}

	for (auto c : COLOR)
		for(auto sq : SQ)
			// 障害物がないときの香の利き
			// これを最初に初期化しないとlanceEffect()が使えない。
			LanceStepEffectBB[sq][c] = rookFileEffect(sq,ZERO_BB) & ForwardRanksBB[c][rank_of(sq)];

	for (auto c : COLOR)
		for (auto sq : SQ)
		{
			// 歩は長さ1の香の利きとして定義できる
			PawnEffectBB[sq][c] = lanceEffect(c, sq, ALL_BB);

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

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

			// 金は長さ1の角と飛車の利き。ただし、角のほうは相手側の歩の行き先の段でmaskしてしまう。
			Bitboard e_pawn = lanceEffect(~c, sq, ALL_BB);
			Bitboard mask = ZERO_BB;
			if (e_pawn)
				mask = RANK_BB[rank_of(e_pawn.pop())];
			GoldEffectBB[sq][c]= (bishopEffect(sq, ALL_BB) & ~mask) | rookEffect(sq, ALL_BB);

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

			// --- 以下のbitboard、あまり頻繁に呼び出さないので他のbitboardを合成して代用する。

			// 盤上の駒がないときのqueenの利き
			// StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_QUEEN] = bishopEffect(sq, ZERO_BB) | rookEffect(sq, ZERO_BB);

			// 長さ1の十字
			// StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_CROSS00] = rookEffect(sq, ALL_BB);

			// 長さ1の斜め
			// StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_CROSS45] = bishopEffect(sq, ALL_BB);
		}

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

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

		PAWN_DROP_MASK_BB[i].p[0] = b.p[0]; // 1~7筋
	}
	for (int i = 0; i < 0x4; ++i)
	{
		Bitboard b = ZERO_BB;
		for (int k = 0; k < 2; ++k)
			if ((i & (1 << k)) == 0)
				b |= FILE_BB[k+7];

		PAWN_DROP_MASK_BB[i].p[1] = b.p[1]; // 8,9筋
	}

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

		for (auto s1 : SQ)
			for (auto s2 : SQ)
			{
				// 十字方向か、斜め方向かだけを判定して、例えば十字方向なら
				// rookEffect(sq1,Bitboard(s2)) & rookEffect(sq2,Bitboard(s1))
				// のように初期化したほうが明快なコードだが、この初期化をそこに依存したくないので愚直にやる。
					
				// これについてはあとで設定する。
				if (s1 >= s2)
					continue;

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

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

					BetweenIndex[s1][s2] = between_index;
					BetweenBB[between_index++] = bb;
				}
			}

		ASSERT_LV1(between_index == 785);

		// 対称性を考慮して、さらにシュリンクする。
		for (auto s1 : SQ)
			for (auto s2 : SQ)
				if (s1 > s2)
					BetweenIndex[s1][s2] = BetweenIndex[s2][s1];

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

			const Square deltas[4] = { SQ_RU , SQ_R , SQ_RD , SQ_U };
			const Square delta = deltas[d];
			Bitboard bb = 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[s1][d] = bb;
		}


	// 9) 王手となる候補の駒のテーブル初期化(王手の指し手生成に必要。やねうら王nanoでは削除予定)

#define FOREACH_KING(BB, EFFECT ) { for(auto sq : BB){ target|= EFFECT(sq); } }
#define FOREACH(BB, EFFECT ) { for(auto sq : BB){ target|= EFFECT(them,sq); } }
#define FOREACH_BR(BB, EFFECT ) { for(auto sq : BB) { target|= EFFECT(sq,ZERO_BB); } }

	for (auto Us : COLOR)
		for (auto ksq : SQ)
		{
			Color them = ~Us;
			auto enemyGold = goldEffect(them, ksq) & enemy_field(Us);
			Bitboard target;

			// 歩で王手になる可能性のあるものは、敵玉から2つ離れた歩(不成での移動) + ksqに敵の金をおいた範囲(enemyGold)に成りで移動できる
			target = ZERO_BB;
			FOREACH(pawnEffect(them, ksq), pawnEffect);
			FOREACH(enemyGold, pawnEffect);
			CheckCandidateBB[ksq][PAWN - 1][Us] = target & ~Bitboard(ksq);

			// 香で王手になる可能性のあるものは、ksqに敵の香をおいたときの利き。(盤上には何もないものとする)
			// と、王が1から3段目だと成れるので王の両端に香を置いた利きも。
			target = lanceStepEffect(them, ksq);
			if (enemy_field(Us) & ksq)
			{
				if (file_of(ksq) != FILE_1)
					target |= lanceStepEffect(them, ksq + SQ_R);
				if (file_of(ksq) != FILE_9)
					target |= lanceStepEffect(them, ksq + SQ_L);
			}
			CheckCandidateBB[ksq][LANCE - 1][Us] = target;

			// 桂で王手になる可能性のあるものは、ksqに敵の桂をおいたところに移動できる桂(不成) + ksqに金をおいた範囲(enemyGold)に成りで移動できる桂
			target = ZERO_BB;
			FOREACH(knightEffect(them, ksq) | enemyGold, knightEffect);
			CheckCandidateBB[ksq][KNIGHT - 1][Us] = target & ~Bitboard(ksq);

			// 銀も同様だが、2,3段目からの引き成りで王手になるパターンがある。(4段玉と5段玉に対して)
			target = ZERO_BB;
			FOREACH(silverEffect(them, ksq), silverEffect);
			FOREACH(enemyGold, silverEffect); // 移動先が敵陣 == 成れる == 金になるので、敵玉の升に敵の金をおいた利きに成りで移動すると王手になる。
			FOREACH(goldEffect(them, ksq), enemy_field(Us) & silverEffect); // 移動元が敵陣 == 成れる == 金になるので、敵玉の升に敵の金をおいた利きに成りで移動すると王手になる。
			CheckCandidateBB[ksq][SILVER - 1][Us] = target & ~Bitboard(ksq);

			// 金
			target = ZERO_BB;
			FOREACH(goldEffect(them, ksq), goldEffect);
			CheckCandidateBB[ksq][GOLD - 1][Us] = target & ~Bitboard(ksq);

			// 角
			target = ZERO_BB;
			FOREACH_BR(bishopEffect(ksq, ZERO_BB), bishopEffect);
			FOREACH_BR(kingEffect(ksq) & enemy_field(Us), bishopEffect); // 移動先が敵陣 == 成れる == 王の動き
			FOREACH_BR(kingEffect(ksq), enemy_field(Us) & bishopEffect); // 移動元が敵陣 == 成れる == 王の動き
			CheckCandidateBB[ksq][BISHOP - 1][Us] = target & ~Bitboard(ksq);

			// 飛・龍は無条件全域。
			// ROOKのところには馬のときのことを格納

			// 馬
			target = ZERO_BB;
			FOREACH_BR(horseEffect(ksq, ZERO_BB), horseEffect);
			CheckCandidateBB[ksq][ROOK - 1][Us] = target & ~Bitboard(ksq);

			// 王(24近傍が格納される)
			target = ZERO_BB;
			FOREACH_KING(kingEffect(ksq), kingEffect);
			CheckCandidateKingBB[ksq] = target & ~Bitboard(ksq);
		}

	// 10. LONG_EFFECT_LIBRARYの初期化

#ifdef LONG_EFFECT_LIBRARY
	LongEffect::init();
#endif

	// 11. 1手詰めテーブルの初期化
#ifdef USE_MATE_1PLY
	Mate1Ply::init();
#endif
}
Ejemplo n.º 2
0
// Bitboard関連の各種テーブルの初期化。
void Bitboards::init()
{
  // ------------------------------------------------------------
  //        Bitboard関係のテーブルの初期化
  // ------------------------------------------------------------

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

  for (auto sq : SQ)
    sqww_table[sq] = SquareWithWall(SQWW_11 + (int32_t)file_of(sq) * SQWW_L + (int32_t)rank_of(sq) * SQWW_D);


  // 2) direct_tableの初期化

  for (auto sq1 : SQ)
    for (auto dir = Effect8::DIRECT_ZERO; dir < Effect8::DIRECT_NB; ++dir)
    {
      // dirの方角に壁にぶつかる(盤外)まで延長していく。このとき、sq1から見てsq2のDirectionsは (1 << dir)である。
      auto delta = Effect8::DirectToDeltaWW(dir);
      for (auto sq2 = to_sqww(sq1) + delta; is_ok(sq2); sq2 += delta)
        Effect8::direc_table[sq1][sqww_to_sq(sq2)] = Effect8::to_directions(dir);
    }


  // 3) Square型のsqの指す升が1であるBitboardがSquareBB。これをまず初期化する。

  for (auto sq : SQ)
  {
    Rank r = rank_of(sq);
    File f = file_of(sq);
    SquareBB[sq].p[0] = (f <= FILE_7) ? ((uint64_t)1 << (f * 9 + r)) : 0;
    SquareBB[sq].p[1] = (f >= FILE_8) ? ((uint64_t)1 << ((f - FILE_8) * 9 + r)) : 0;
  }


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

  // 引数のindexをbits桁の2進数としてみなす。すなわちindex(0から2^bits-1)。
  // 与えられたmask(1の数がbitsだけある)に対して、1のbitのいくつかを(indexの値に従って)0にする。
  auto indexToOccupied = [](const int index, const int bits, const Bitboard& mask_)
  {
    auto mask = mask_;
    auto result = ZERO_BB;
    for (int i = 0; i < bits; ++i)
    {
      const Square sq = mask.pop();
      if (index & (1 << i))
        result ^= sq;
    }
    return result;
  };

  // Rook or Bishop の利きの範囲を調べて bitboard で返す。
  // occupied  障害物があるマスが 1 の bitboard
  auto effectCalc = [](const Square square, const Bitboard& occupied, const Piece piece)
  {
    auto result = ZERO_BB;

    // 角の利きのrayと飛車の利きのray
    const SquareWithWall deltaArray[2][4] = { { SQWW_RU, SQWW_RD, SQWW_LU, SQWW_LD },{ SQWW_U, SQWW_D, SQWW_R, SQWW_L } };
    for (auto delta : deltaArray[(piece == BISHOP) ? 0 : 1])
      // 壁に当たるまでsqを利き方向に伸ばしていく
      for (auto sq = to_sqww(square) + delta; is_ok(sq) ; sq += delta)
      {
        result ^= sqww_to_sq(sq); // まだ障害物に当っていないのでここまでは利きが到達している

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

  // pieceをsqにおいたときに利きを得るのに関係する升を返す
  auto calcEffectMask = [](Square sq, Piece piece)
  {
    Bitboard result;
    if (piece == BISHOP) {

      result = ZERO_BB;

      for (Rank r = RANK_2; r <= RANK_8; ++r)
        for (File f = FILE_2; f <= FILE_8; ++f)
          // 外周は角の利きには関係ないのでそこは除外する。
          if (abs(rank_of(sq) - r) == abs(file_of(sq) - f))
            result ^= (f | r);
    } else {

      ASSERT_LV3(piece == ROOK);

      result = RANK_BB[rank_of(sq)] ^ FILE_BB[file_of(sq)];

      // 外周に居ない限り、その外周升は利きの計算には関係ない。
      if (file_of(sq) != FILE_1) { result &= ~FILE1_BB; }
      if (file_of(sq) != FILE_9) { result &= ~FILE9_BB; }
      if (rank_of(sq) != RANK_1) { result &= ~RANK1_BB; }
      if (rank_of(sq) != RANK_9) { result &= ~RANK9_BB; }
    }

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

    return result;
  };
  
  // 角と飛車の利きテーブルの初期化
  for (Piece pc : {BISHOP,ROOK} )
  {
    // 初期化するテーブルのアドレス
    Bitboard* effects = (pc == BISHOP) ? BishopEffect : RookEffect;

    // sqの升に対してテーブルのどこを引くかのindex
    int* effectIndex = (pc == BISHOP) ? BishopEffectIndex : RookEffectIndex;

    // 利きを得るために関係する升
    Bitboard* masks = (pc == BISHOP) ? BishopEffectMask : RookEffectMask;

    int index = 0;

    for (auto sq : SQ)
    {
      effectIndex[sq] = index;

      // sqの地点にpieceがあるときにその利きを得るのに関係する升を取得する
      masks[sq] = calcEffectMask(sq, pc);

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

      // sqの升用に何bit情報を拾ってくるのか
      const int bits = masks[sq].pop_count();

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

      for (int i = 0; i < num; ++i)
      {
        Bitboard occupied = indexToOccupied(i, bits, masks[sq]);
        effects[index + occupiedToIndex(occupied & masks[sq], masks[sq])] = effectCalc(sq, occupied, pc);
      }
      index += num;
    }

    // 盤外(SQ_NB)に駒を配置したときに利きがZERO_BBとなるときのための処理
    effectIndex[SQ_NB] = index;
  }

  
  // 5. 香の利きテーブルの初期化
  // 上で初期化した飛車の利きを用いる。

  for (auto c : COLOR)
    for (auto sq : SQ)
    {
      const Bitboard blockMask = FILE_BB[file_of(sq)] & ~(RANK1_BB | RANK9_BB);
      const int num1s = 7;
      for (int i = 0; i < (1 << num1s); ++i) {
        Bitboard occupied = indexToOccupied(i, num1s, blockMask);
        LanceEffect[c][sq][i] = rookEffect(sq, occupied) & InFrontBB[c][rank_of(sq)];
      }
    }

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

  for (auto c : COLOR)
    for (auto sq : SQ)
    {
      // 歩は長さ1の香の利きとして定義できる
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_PAWN] = lanceEffect(c, sq, ALL_BB);

      // 障害物がないときの香の利き
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_LANCE] = lanceEffect(c, sq, ZERO_BB);

      // 桂の利きは、歩の利きの地点に長さ1の角の利きを作って、前方のみ残す。
      Bitboard tmp = ZERO_BB;
      Bitboard pawn = lanceEffect(c, sq, ALL_BB);
      if (pawn)
      {
        Square sq2 = pawn.pop();
        Bitboard pawn2 = lanceEffect(c, sq2, ALL_BB); // さらに1つ前
        if (pawn2)
          tmp = bishopEffect(sq2, ALL_BB) & RANK_BB[rank_of(pawn2.pop())];
      }
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_KNIGHT] = tmp;

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

      // 金は長さ1の角と飛車の利き。ただし、角のほうは相手側の歩の行き先の段でmaskしてしまう。
      Bitboard e_pawn = lanceEffect(~c, sq, ALL_BB);
      Bitboard mask = ZERO_BB;
      if (e_pawn)
        mask = RANK_BB[rank_of(e_pawn.pop())];
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_GOLD] = (bishopEffect(sq, ALL_BB) & ~mask) | rookEffect(sq, ALL_BB);

      // 障害物がないときの角と飛車の利き
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_BISHOP] = bishopEffect(sq, ZERO_BB);
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_ROOK] = rookEffect(sq, ZERO_BB);

      // 玉は長さ1の角と飛車の利きを合成する
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_HDK] = bishopEffect(sq, ALL_BB) | rookEffect(sq, ALL_BB);

      // 盤上の駒がないときのqueenの利き
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_QUEEN] = bishopEffect(sq, ZERO_BB) | rookEffect(sq, ZERO_BB);

      // 長さ1の十字
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_CROSS00] = rookEffect(sq, ALL_BB);

      // 長さ1の斜め
      StepEffectsBB[sq][c][PIECE_TYPE_BITBOARD_CROSS45] = bishopEffect(sq, ALL_BB);
    }

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

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

    PAWN_DROP_MASK_BB[i][BLACK] = b & rank1_n_bb(WHITE, RANK_8); // 2~9段目まで
    PAWN_DROP_MASK_BB[i][WHITE] = b & rank1_n_bb(BLACK, RANK_8); // 1~8段目まで
  }

  // 8) BetweenBB , LineBBの初期化
  
  for (auto s1 : SQ)
    for (auto s2 : SQ)
    {
      // 方角を用いるテーブルの初期化
      if (Effect8::directions_of(s1,s2))
      {
        // 間に挟まれた升を1に
        Square delta = (s2 - s1) / dist(s1 , s2);
        for (Square s = s1 + delta; s != s2; s += delta)
          BetweenBB[s1][s2] |= s;

        // 間に挟まれてない升も1に
        LineBB[s1][s2] = BetweenBB[s1][s2];

        // 壁に当たるまでs1から-delta方向に延長
        for (Square s = s1; dist(s, s + delta) <= 1; s -= delta) LineBB[s1][s2] |= s;

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

  // 9) 王手となる候補の駒のテーブル初期化(王手の指し手生成に必要。やねうら王nanoでは削除予定)

#define FOREACH_KING(BB, EFFECT ) { for(auto sq : BB){ target|= EFFECT(sq); } }
#define FOREACH(BB, EFFECT ) { for(auto sq : BB){ target|= EFFECT(them,sq); } }
#define FOREACH_BR(BB, EFFECT ) { for(auto sq : BB) { target|= EFFECT(sq,ZERO_BB); } }

  for (auto Us : COLOR)
    for (auto ksq : SQ)
    {
      Color them = ~Us;
      auto enemyGold = goldEffect(them, ksq) & enemy_field(Us);
      Bitboard target;

      // 歩で王手になる可能性のあるものは、敵玉から2つ離れた歩(不成での移動) + ksqに敵の金をおいた範囲(enemyGold)に成りで移動できる
      target = ZERO_BB;
      FOREACH(pawnEffect(them, ksq), pawnEffect);
      FOREACH(enemyGold, pawnEffect);
      CheckCandidateBB[ksq][PAWN - 1][Us] = target & ~Bitboard(ksq);

      // 香で王手になる可能性のあるものは、ksqに敵の香をおいたときの利き。(盤上には何もないものとする)
      // と、王が1から3段目だと成れるので王の両端に香を置いた利きも。
      target = lanceStepEffect(them, ksq);
      if (enemy_field(Us) & ksq)
      {
        if (file_of(ksq) != FILE_1)
          target |= lanceStepEffect(them, ksq + SQ_R);
        if (file_of(ksq) != FILE_9)
          target |= lanceStepEffect(them, ksq + SQ_L);
      }
      CheckCandidateBB[ksq][LANCE - 1][Us] = target;

      // 桂で王手になる可能性のあるものは、ksqに敵の桂をおいたところに移動できる桂(不成) + ksqに金をおいた範囲(enemyGold)に成りで移動できる桂
      target = ZERO_BB;
      FOREACH(knightEffect(them, ksq) | enemyGold, knightEffect);
      CheckCandidateBB[ksq][KNIGHT - 1][Us] = target & ~Bitboard(ksq);

      // 銀も同様だが、2,3段目からの引き成りで王手になるパターンがある。(4段玉と5段玉に対して)
      target = ZERO_BB;
      FOREACH(silverEffect(them, ksq) , silverEffect);
      FOREACH(enemyGold, silverEffect); // 移動先が敵陣 == 成れる == 金になるので、敵玉の升に敵の金をおいた利きに成りで移動すると王手になる。
      FOREACH(goldEffect(them, ksq), enemy_field(Us) & silverEffect); // 移動元が敵陣 == 成れる == 金になるので、敵玉の升に敵の金をおいた利きに成りで移動すると王手になる。
      CheckCandidateBB[ksq][SILVER - 1][Us] = target & ~Bitboard(ksq);

      // 金
      target = ZERO_BB;
      FOREACH(goldEffect(them, ksq), goldEffect);
      CheckCandidateBB[ksq][GOLD - 1][Us] = target & ~Bitboard(ksq);

      // 角
      target = ZERO_BB;
      FOREACH_BR(bishopEffect(ksq,ZERO_BB), bishopEffect);
      FOREACH_BR(kingEffect(ksq) & enemy_field(Us), bishopEffect); // 移動先が敵陣 == 成れる == 王の動き
      FOREACH_BR(kingEffect(ksq) , enemy_field(Us) & bishopEffect); // 移動元が敵陣 == 成れる == 王の動き
      CheckCandidateBB[ksq][BISHOP - 1][Us] = target & ~Bitboard(ksq);

      // 飛・龍は無条件全域。
      // ROOKのところには馬のときのことを格納

      // 馬
      target = ZERO_BB;
      FOREACH_BR(horseEffect(ksq, ZERO_BB), horseEffect);
      CheckCandidateBB[ksq][ROOK - 1][Us] = target & ~Bitboard(ksq);
      
      // 王(24近傍が格納される)
      target = ZERO_BB;
      FOREACH_KING(kingEffect(ksq) , kingEffect);
      CheckCandidateBB[ksq][HDK - 1][Us] = target & ~Bitboard(ksq);
    }

  // 10. LONG_EFFECT_LIBRARYの初期化
  
#ifdef LONG_EFFECT_LIBRARY
  LongEffect::init();
#endif

  // 11. 1手詰めテーブルの初期化
#ifdef USE_MATE_1PLY
  Mate1Ply::init();
#endif
}