Ejemplo n.º 1
0
PieceType PtHorse::AppendToNextAttackerAndTryPromote(
	Bitboard& occupied,
	Bitboard& attackers,
	PieceType nextPT,
	const PieceTypeSeeEvent ptsEvent
	) const {
	PieceType PT = PieceType::N13_Horse;

	if (ptsEvent.m_opponentAttackers.AndIsNot0(ptsEvent.m_pos.GetBbOf10(PT))) {
		// todo: 実際に移動した方向を基にattackersを更新すれば、template, inline を使用しなくても良さそう。
		//       その場合、キャッシュに乗りやすくなるので逆に速くなるかも。
		const Bitboard bb = ptsEvent.m_opponentAttackers & ptsEvent.m_pos.GetBbOf10(PT);
		const Square from = bb.GetFirstOneFromI9();
		g_setMaskBb.XorBit(&occupied, from);

		attackers |= (g_lanceAttackBb.GetControllBb(occupied, ConvColor::OPPOSITE_COLOR10b(ptsEvent.m_turn), ptsEvent.m_to) &
			ptsEvent.m_pos.GetBbOf20(N02_Lance, ptsEvent.m_turn))
			| (g_lanceAttackBb.GetControllBb(occupied, ptsEvent.m_turn, ptsEvent.m_to) &
				ptsEvent.m_pos.GetBbOf20(N02_Lance, ConvColor::OPPOSITE_COLOR10b(ptsEvent.m_turn)))
			| (g_rookAttackBb.GetControllBb(occupied, ptsEvent.m_to) & ptsEvent.m_pos.GetBbOf20(N06_Rook, N14_Dragon))
			| (g_bishopAttackBb.BishopAttack(occupied, ptsEvent.m_to) & ptsEvent.m_pos.GetBbOf20(N05_Bishop, N13_Horse));

		// それ以外の駒種類は、そのまま返す☆
		return PT;
	}

	return PiecetypePrograms::m_PIECETYPE_PROGRAMS[nextPT]->AppendToNextAttackerAndTryPromote(
		occupied,
		attackers,
		PieceType::N06_Rook,
		ptsEvent
		);
}
Ejemplo n.º 2
0
Score Evaluator::calculateMaterialScore(const Position& position) const {
  Score score = Score::zero();

  auto& blackHand = position.getBlackHand();
  score += material::Pawn   * blackHand.get(PieceType::pawn  ());
  score += material::Lance  * blackHand.get(PieceType::lance ());
  score += material::Knight * blackHand.get(PieceType::knight());
  score += material::Silver * blackHand.get(PieceType::silver());
  score += material::Gold   * blackHand.get(PieceType::gold  ());
  score += material::Bishop * blackHand.get(PieceType::bishop());
  score += material::Rook   * blackHand.get(PieceType::rook  ());

  auto& whiteHand = position.getWhiteHand();
  score -= material::Pawn   * whiteHand.get(PieceType::pawn  ());
  score -= material::Lance  * whiteHand.get(PieceType::lance ());
  score -= material::Knight * whiteHand.get(PieceType::knight());
  score -= material::Silver * whiteHand.get(PieceType::silver());
  score -= material::Gold   * whiteHand.get(PieceType::gold  ());
  score -= material::Bishop * whiteHand.get(PieceType::bishop());
  score -= material::Rook   * whiteHand.get(PieceType::rook  ());

  Bitboard occ = nosseOr(position.getBOccupiedBitboard(),
                         position.getWOccupiedBitboard());
  occ.unset(position.getBlackKingSquare());
  occ.unset(position.getWhiteKingSquare());

  BB_EACH(square, occ) {
    auto piece = position.getPieceOnBoard(square);

    if (piece.isBlack()) {
      score += material::score(piece);
    } else {
      score -= material::score(piece);
    }
  }
Ejemplo n.º 3
0
static Square minAttacker(const Board &board, Bitboard atcks, ColorType side) {
   if (side == White)
   {
      Bitboard retval(atcks & board.pawn_bits[White]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.knight_bits[White]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.bishop_bits[White]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.rook_bits[White]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.queen_bits[White]);
      if (!retval.isClear())
         return retval.firstOne();
      if (atcks.isSet(board.kingSquare(White)))
        return board.kingSquare(White);
      else
        return InvalidSquare;
   }
   else
   {
      Bitboard retval(atcks & board.pawn_bits[Black]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.knight_bits[Black]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.bishop_bits[Black]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.rook_bits[Black]);
      if (!retval.isClear())
         return retval.firstOne();
      retval = (atcks & board.queen_bits[Black]);
      if (!retval.isClear())
         return retval.firstOne();
      if (atcks.isSet(board.kingSquare(Black)))
        return board.kingSquare(Black);
      else
        return InvalidSquare;
   }    
}
Ejemplo n.º 4
0
Key Book::GetBookKey(const Position& pos) {
	Key key = 0;
	Bitboard bb = pos.GetOccupiedBB();

	while (bb.Exists1Bit()) {
		const Square sq = bb.PopFirstOneFromI9();
		key ^= m_ZobPiece[pos.GetPiece(sq)][sq];
	}
	const Hand hand = pos.GetHand(pos.GetTurn());
	for (HandPiece hp = HPawn; hp < HandPieceNum; ++hp) {
		key ^= m_ZobHand[hp][hand.NumOf(hp)];
	}
	if (pos.GetTurn() == White) {
		key ^= m_ZobTurn;
	}
	return key;
}
Ejemplo n.º 5
0
Bitboard SEE::extractAttackers(const Position& position,
                               Square from,
                               Square to) {
  Bitboard occ = nosseOr(position.getBOccupiedBitboard(),
                         position.getWOccupiedBitboard());
  RotatedBitboard occ90 = position.get90RotatedBitboard();
  RotatedBitboard occR45 = position.getRight45RotatedBitboard();
  RotatedBitboard occL45 = position.getLeft45RotatedBitboard();

  occ.unset(from);
  occ90.unset(from.rotate90());
  occR45.unset(from.rotateRight45());
  occL45.unset(from.rotateLeft45());

  Bitboard bb = Bitboard::zero();
  bb |= (Bitboard::mask(to) << 1) & position.getBPawnBitboard();
  bb |= (Bitboard::mask(to) >> 1) & position.getWPawnBitboard();
  bb |= MoveTables::whiteLance(occ, to) & position.getBLanceBitboard();
  bb |= MoveTables::blackLance(occ, to) & position.getWLanceBitboard();
  bb |= MoveTables::whiteKnight(to) & position.getBKnightBitboard();
  bb |= MoveTables::blackKnight(to) & position.getWKnightBitboard();
  bb |= MoveTables::whiteSilver(to) & position.getBSilverBitboard();
  bb |= MoveTables::blackSilver(to) & position.getWSilverBitboard();
  bb |= MoveTables::whiteGold(to) & position.getBGoldBitboard();
  bb |= MoveTables::blackGold(to) & position.getWGoldBitboard();
  bb |= (MoveTables::ver(occ, to) |
         MoveTables::hor(occ90, to)) &
        (position.getBRookBitboard() |
         position.getBDragonBitboard() |
         position.getWRookBitboard() |
         position.getWDragonBitboard());
  bb |= (MoveTables::diagR45(occR45, to) |
         MoveTables::diagL45(occL45, to)) &
        (position.getBBishopBitboard() |
         position.getBHorseBitboard() |
         position.getWBishopBitboard() |
         position.getWHorseBitboard());
  bb |= MoveTables::king(to) &
       (position.getBDragonBitboard() |
        position.getWDragonBitboard()); // TODO: king

  bb.unset(from);

  return bb;
}
Ejemplo n.º 6
0
  Bitboard operator ^= (const Bitboard& rhs) {
#if defined (HAVE_SSE2) || defined (HAVE_SSE4)
    _mm_store_si128(&this->m_, _mm_xor_si128(this->m_, rhs.m_));
#else
    this->p_[0] ^= rhs.p(0);
    this->p_[1] ^= rhs.p(1);
#endif
    return *this;
  }
Ejemplo n.º 7
0
void EvalList::set(const Position& pos) {
	const Hand handB = pos.hand(Black);
	const Hand handW = pos.hand(White);

	int nlist = 0;
	auto func = [&nlist, this](const Hand hand, const HandPiece hp, const int list0_index, const int list1_index, const Color c) {
		for (u32 i = 1; i <= hand.numOf(hp); ++i) {
			list0[nlist] = list0_index + i;
			list1[nlist] = list1_index + i;
			const Square squarehand = HandPieceToSquareHand[c][hp] + static_cast<Square>(i);
			listToSquareHand[nlist] = squarehand;
			squareHandToList[squarehand] = nlist;
			++nlist;
		}
	};
	func(handB, HPawn  , f_hand_pawn  , e_hand_pawn  , Black);
	func(handW, HPawn  , e_hand_pawn  , f_hand_pawn  , White);
	func(handB, HLance , f_hand_lance , e_hand_lance , Black);
	func(handW, HLance , e_hand_lance , f_hand_lance , White);
	func(handB, HKnight, f_hand_knight, e_hand_knight, Black);
	func(handW, HKnight, e_hand_knight, f_hand_knight, White);
	func(handB, HSilver, f_hand_silver, e_hand_silver, Black);
	func(handW, HSilver, e_hand_silver, f_hand_silver, White);
	func(handB, HGold  , f_hand_gold  , e_hand_gold  , Black);
	func(handW, HGold  , e_hand_gold  , f_hand_gold  , White);
	func(handB, HBishop, f_hand_bishop, e_hand_bishop, Black);
	func(handW, HBishop, e_hand_bishop, f_hand_bishop, White);
	func(handB, HRook  , f_hand_rook  , e_hand_rook  , Black);
	func(handW, HRook  , e_hand_rook  , f_hand_rook  , White);

	Bitboard bb = pos.bbOf(King).notThisAnd(pos.occupiedBB());
	while (bb.isNot0()) {
		const Square sq = bb.firstOneFromSQ11();
		const Piece pc = pos.piece(sq);
		listToSquareHand[nlist] = sq;
		squareHandToList[sq] = nlist;
		list0[nlist  ] = kppArray[pc         ] + sq;
		list1[nlist++] = kppArray[inverse(pc)] + inverse(sq);
	}
}
Ejemplo n.º 8
0
Archivo: init.cpp Proyecto: ixixi/apery
// square の位置の rook, bishop それぞれのMagic Bitboard に使用するマジックナンバーを見つける。
// isBishop  : true なら bishop, false なら rook のマジックナンバーを見つける。
u64 findMagic(const Square square, const bool isBishop) {
	Bitboard occupied[1<<14];
	Bitboard attack[1<<14];
	Bitboard attackUsed[1<<14];
	Bitboard mask = (isBishop ? bishopBlockMaskCalc(square) : rookBlockMaskCalc(square));
	int num1s = (isBishop ? BishopBlockBits[square] : RookBlockBits[square]);

	// n bit の全ての数字 (利きのあるマスの全ての 0 or 1 の組み合わせ)
	for (int i = 0; i < (1 << num1s); ++i) {
		occupied[i] = indexToOccupied(i, num1s, mask);
		attack[i] = attackCalc(square, occupied[i], isBishop);
	}

	for (u64 k = 0; k < UINT64_C(100000000); ++k) {
		const u64 magic = g_mt64bit.randomFewBits();
		bool fail = false;

		// これは無くても良いけど、少しマジックナンバーが見つかるのが早くなるはず。
		if (count1s((mask.merge() * magic) & UINT64_C(0xfff0000000000000)) < 6)
			continue;

		std::fill(std::begin(attackUsed), std::end(attackUsed), allZeroBB());

		for (int i = 0; !fail && i < (1 << num1s); ++i) {
			const int shiftBits = (isBishop ? BishopShiftBits[square] : RookShiftBits[square]);
			const u64 index = occupiedToIndex(occupied[i], magic, shiftBits);
			if      (attackUsed[index] == allZeroBB())
				attackUsed[index] = attack[i];
			else if (attackUsed[index] != attack[i])
				fail = true;
		}
		if (!fail)
			return magic;
	}

	std::cout << "/***Failed***/\t";
	return 0;
}
Ejemplo n.º 9
0
int Evaluation::evaluateKingSafety(int color, Position& position) {
	assert(Color::isValid(color));

	auto pawns = position.pieces[color][PieceType::PAWN].squares;
	auto rooks = position.pieces[color][PieceType::ROOK].squares;
	int square = Bitboard::next(position.pieces[color][PieceType::KING].squares);

	Bitboard pawnShield;
	if (color == Color::WHITE) {
		if (Square::isValid(square + Square::NE)) { pawnShield.add(square + Square::NE); }
		if (Square::isValid(square + Square::N)) { pawnShield.add(square + Square::N); }
		if (Square::isValid(square + Square::NW)) { pawnShield.add(square + Square::NW); }
	}
	else {
		if (Square::isValid(square + Square::SE)) { pawnShield.add(square + Square::SE); }
		if (Square::isValid(square + Square::S)) { pawnShield.add(square + Square::S); }
		if (Square::isValid(square + Square::SW)) { pawnShield.add(square + Square::SW); }
	}
	int pawnShieldCount = Bitboard::bitCount(pawnShield.squares & pawns);

	int rookShieldCount = 0;
	for (auto rookSquares = position.pieces[color][PieceType::ROOK].squares; rookSquares != 0; rookSquares = Bitboard::remainder(rookSquares)) {
		int rookSquare = Bitboard::next(rookSquares);
		for (auto rookDirection : Square::rookDirections) {
			int targetSquare = rookSquare + rookDirection;

			int cover = 0;
			while (Square::isValid(targetSquare)) {
				for (auto kingDirection : Square::kingDirections) {
					if (targetSquare == square + kingDirection)
						rookShieldCount++;
				}

				if (position.board[targetSquare] != Piece::NOPIECE) {
					cover++;
				}

				if (cover < 2) {
					targetSquare += rookDirection;
				}
				else {
					break;
				}
			}
		}
	}
	

	return pawnShieldCount * 20
		+ rookShieldCount * 10;
}
Ejemplo n.º 10
0
Bitboard SEE::extractShadowAttacker(const Position& position,
                                    Bitboard bb,
                                    Square from,
                                    Square to) {
  Direction dir = from.dir(to);
  if (dir >= Direction::EndS) {
    return bb;
  }

  Bitboard occ = nosseOr(position.getBOccupiedBitboard(),
                         position.getWOccupiedBitboard());
  RotatedBitboard occ90 = position.get90RotatedBitboard();
  RotatedBitboard occR45 = position.getRight45RotatedBitboard();
  RotatedBitboard occL45 = position.getLeft45RotatedBitboard();

  Bitboard masked;
  switch (dir) {
  case Direction::Up:
  case Direction::Down:
    masked = MoveTables::ver(occ, from);
    break;
  case Direction::Left:
  case Direction::Right:
    masked = MoveTables::hor(occ90, from);
    break;
  case Direction::RightUp:
  case Direction::LeftDown:
    masked = MoveTables::diagR45(occR45, to);
    break;
  case Direction::LeftUp:
  case Direction::RightDown:
    masked = MoveTables::diagL45(occL45, to);
    break;
  default:
    ASSERT(false);
  }

  BB_EACH(square, masked) {
    Piece piece = position.getPieceOnBoard(square);
    if (square.dir(from) == dir && MoveTables::isMovableInLongStep(piece, dir)) {
      bb.set(square);
      break;
    }
  }
Ejemplo n.º 11
0
  MoveStack* generateDropMoves20151211(MoveStack* moveStackList, const Position& pos, const Bitboard& target) {
    const Hand hand = pos.hand(US);
    // まず、歩に対して指し手を生成
    if (hand.exists<HPawn>()) {
      Bitboard toBB = target;
      // 一段目には打てない
      const Rank TRank9 = (US == Black ? Rank9 : Rank1);
      toBB.andEqualNot(rankMask<TRank9>());

      // 二歩の回避
      Bitboard pawnsBB = pos.bbOf(Pawn, US);
      Square pawnsSquare;
      foreachBB(pawnsBB, pawnsSquare, [&](const int part) {
        toBB.set(part, toBB.p(part) & ~squareFileMask(pawnsSquare).p(part));
      });

      // 打ち歩詰めの回避
      const Rank TRank1 = (US == Black ? Rank1 : Rank9);
      const SquareDelta TDeltaS = (US == Black ? DeltaS : DeltaN);

      const Square ksq = pos.kingSquare(oppositeColor(US));
      // 相手玉が九段目なら、歩で王手出来ないので、打ち歩詰めを調べる必要はない。
      if (makeRank(ksq) != TRank1) {
        const Square pawnDropCheckSquare = ksq + TDeltaS;
        assert(isInSquare(pawnDropCheckSquare));
        if (toBB.isSet(pawnDropCheckSquare) && pos.piece(pawnDropCheckSquare) == Empty) {
          if (!pos.isPawnDropCheckMate(US, pawnDropCheckSquare)) {
            // ここで clearBit だけして MakeMove しないことも出来る。
            // 指し手が生成される順番が変わり、王手が先に生成されるが、後で問題にならないか?
            (*moveStackList++).move = makeDropMove(Pawn, pawnDropCheckSquare);
          }
          toBB.xorBit(pawnDropCheckSquare);
        }
      }

      Square to;
      FOREACH_BB(toBB, to, {
        (*moveStackList++).move = makeDropMove(Pawn, to);
      });
Ejemplo n.º 12
0
 FORCE_INLINE MoveStack* generateBishopOrRookMoves(MoveStack* moveStackList, const Position& pos,
   const Bitboard& target, const Square /*ksq*/)
 {
   Bitboard fromBB = pos.bbOf(PT, US);
   while (fromBB.isNot0()) {
     const Square from = fromBB.firstOneFromI9();
     const bool fromCanPromote = canPromote(US, makeRank(from));
     Bitboard toBB = pos.attacksFrom<PT>(US, from) & target;
     while (toBB.isNot0()) {
       const Square to = toBB.firstOneFromI9();
       const bool toCanPromote = canPromote(US, makeRank(to));
       if (fromCanPromote | toCanPromote) {
         (*moveStackList++).move = makePromoteMove<MT>(PT, from, to, pos);
         if (MT == NonEvasion || ALL)
           (*moveStackList++).move = makeNonPromoteMove<MT>(PT, from, to, pos);
       }
       else // 角、飛車は成れるなら成り、不成は生成しない。
         (*moveStackList++).move = makeNonPromoteMove<MT>(PT, from, to, pos);
     }
   }
   return moveStackList;
 }
Ejemplo n.º 13
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.º 14
0
bool Mate::isProtected_(const Board& board, const Square to, const Bitboard& occ, const Bitboard& occNoAttacker, const Square king) {
  // pawn
  Bitboard bb = (black ? board.getBPawn() : board.getWPawn()) & occNoAttacker;
  if (bb.check(black ? to.safetyDown() : to.safetyUp())) {
    return true;
  }

  // lance
  bb = (black ? board.getBLance() : board.getWLance()) & occNoAttacker;
  bb &= black ? MoveTables::wlance(to, occ) : MoveTables::blance(to, occ);
  if (bb) { return true; }

  // knight
  bb = (black ? board.getBKnight() : board.getWKnight()) & occNoAttacker;
  bb &= black ? MoveTables::wknight(to) : MoveTables::bknight(to);
  if (bb) { return true; }

  // silver
  bb = (black ? board.getBSilver() : board.getWSilver()) & occNoAttacker;
  bb &= black ? MoveTables::wsilver(to) : MoveTables::bsilver(to);
  if (bb) { return true; }

  // gold
  bb = (black ? board.getBGold() : board.getWGold()) & occNoAttacker;
  bb &= black ? MoveTables::wgold(to) : MoveTables::bgold(to);
  if (bb) { return true; }

  // bishop
  bb = (black ? board.getBBishop() : board.getWBishop()) & occNoAttacker;
  bb &= MoveTables::bishop(to, occ);
  if (bb) { return true; }

  // rook
  bb = (black ? board.getBRook() : board.getWRook()) & occNoAttacker;
  bb &= MoveTables::rook(to, occ);
  if (bb) { return true; }

  // tokin
  bb = (black ? board.getBTokin() : board.getWTokin()) & occNoAttacker;
  bb &= black ? MoveTables::wgold(to) : MoveTables::bgold(to);
  if (bb) { return true; }

  // promoted lance
  bb = (black ? board.getBProLance() : board.getWProLance()) & occNoAttacker;
  bb &= black ? MoveTables::wgold(to) : MoveTables::bgold(to);
  if (bb) { return true; }

  // promoted knight
  bb = (black ? board.getBProKnight() : board.getWProKnight()) & occNoAttacker;
  bb &= black ? MoveTables::wgold(to) : MoveTables::bgold(to);
  if (bb) { return true; }

  // promoted silver
  bb = (black ? board.getBProSilver() : board.getWProSilver()) & occNoAttacker;
  bb &= black ? MoveTables::wgold(to) : MoveTables::bgold(to);
  if (bb) { return true; }

  // horse
  bb = (black ? board.getBHorse() : board.getWHorse()) & occNoAttacker;
  bb &= MoveTables::horse(to, occ);
  if (bb) { return true; }

  // dragon
  bb = (black ? board.getBDragon() : board.getWDragon()) & occNoAttacker;
  bb &= MoveTables::dragon(to, occ);
  if (bb) { return true; }

  // king
  if (king.isValid()) {
    if (MoveTables::king(king).check(to) &&
        (!recursive || !isProtected_<!black>(board, to, occ, occNoAttacker, Square::Invalid))) {
      return true;
    }
  }

  return false;
}
Ejemplo n.º 15
0
void Notation::image(const Board & b, const Move & m, OutputFormat format, ostream &image) {
   if (format == UCI) {
      return UCIMoveImage(m,image);
   }
   else if (format == WB_OUT) {
      if (TypeOfMove(m) == KCastle) {
          image << "O-O";
      }
      else if (TypeOfMove(m) == QCastle) {
          image << "O-O-O";
      }
      else {
         image << FileImage(StartSquare(m));
         image << RankImage(StartSquare(m));
         image << FileImage(DestSquare(m));
         image << RankImage(DestSquare(m));
         if (TypeOfMove(m) == Promotion) {
            // N.b. ICS requires lower case.
            image << (char)tolower((int)PieceImage(PromoteTo(m)));
         }
      }
      return;
   }
   // format is SAN
   if (IsNull(m)) {
       image << "(null)";
      return;
   }

   PieceType p = PieceMoved(m);
   ASSERT(p != Empty);
   if (TypeOfMove(m) == KCastle) {
       image << "O-O";
   }
   else if (TypeOfMove(m) == QCastle) {
       image << "O-O-O";
   }
   else {
      if (p == Pawn) {
         if (Capture(m) == Empty) {
            image << FileImage(DestSquare(m));
            image << RankImage(DestSquare(m));
         }
         else {
            image << FileImage(StartSquare(m));
            image << 'x';
            image << FileImage(DestSquare(m));
            image << RankImage(DestSquare(m));
         }
         if (TypeOfMove(m) == Promotion) {
            image << '=';
            image << PieceImage(PromoteTo(m));
         }
      }
      else {
         image << PieceImage(p);
         Bitboard attacks =
            b.calcAttacks(DestSquare(m), b.sideToMove());
         unsigned n = attacks.bitCount();
         int dups = 0;
         int filedups = 0;
         int rankdups = 0;
         int files[9];
         int ranks[9];

         if (n > 1) {
            Square sq;
            while (attacks.iterate(sq)) {
               if (TypeOfPiece(b[sq]) == p) {
                  files[dups] = File(sq);
                  if (files[dups] == File(StartSquare(m)))
                     filedups++;
                  ranks[dups] = Rank(sq,White);
                  if (ranks[dups] == Rank(StartSquare(m),White))
                     rankdups++;
                  ++dups;
               }
            }
         }
         if (dups > 1) {
            // need to disambiguate move.
            if (filedups == 1) {
               image << FileImage(StartSquare(m));
            }
            else if (rankdups == 1) {
               image << RankImage(StartSquare(m));
            }
            else {
               // need both rank and file to disambiguate
               image << FileImage(StartSquare(m));
               image << RankImage(StartSquare(m));
            }
         }
         if (Capture(m) != Empty) {
            image << 'x';
         }
         image << FileImage(DestSquare(m));
         image << RankImage(DestSquare(m));
      }
   }
   Board board_copy(b);
   board_copy.doMove(m);
   if (board_copy.checkStatus() == InCheck) {
      Move moves[Constants::MaxMoves];
      MoveGenerator mg(board_copy);
      if (mg.generateEvasions(moves))
         image << '+';
      else
         image << '#';                        // mate
   }
}
Ejemplo n.º 16
0
Move Notation::value(const Board & board, ColorType side, InputFormat format, const string &image) 
{
    int rank = 0;
    int file = 0;

    PieceType piece = Empty;
    PieceType promotion = Empty;
    Square dest = InvalidSquare, start = InvalidSquare;
    int capture = 0;

    stringstream s(image);
    string::const_iterator it = image.begin();
    int i = 0;
    while (it != image.end() && isspace(*it)) {
        it++;
        i++;
    }
    if (it == image.end() || !isalpha(*it)) return NullMove;
    string img(image,i); // string w/o leading spaces
    ASSERT(img.length());
    it = img.begin();
    if (*it == 'O' || *it == '0') {
       // castling, we presume
       return parseCastling(board, side, img);
    } else if (format == WB_IN) {
       if (img.length() < 4) return NullMove;
       Square start = SquareValue(img.substr(0,2));
       if (!OnBoard(start)) return NullMove;
       Square dest = SquareValue(img.substr(2,2));
       if (!OnBoard(dest)) return NullMove;
       PieceType promotion = Empty;
       if (img.length() > 4) {
          promotion = PieceCharValue(toupper(img[4]));
       }
       return CreateMove(board,start,dest,promotion);
    }
    int have_start = 0;
    if (isupper(*it)) {
       piece = PieceCharValue(*it);
       it++;
    }
    else {
       piece = Pawn;
       if ((it+1) != img.end()) {
          char next = *it;
          file = next-'a'+1;
          if (file < 1 || file > 8) return NullMove;
          char next2 = *(it+1);
          if (next2 == 'x' || is_file(next2)) {
             // allow "dc4" as in Informant, instead of dxc4
             it++;
             capture = 1;
          }
          else if (isdigit(next2) && img.length()>2) {
             char next3 = *(it+2);
             if ((next3 == 'x' || next3 == '-') && img.length()>=5) {
                // long algebraic notation
                have_start++;
                start = SquareValue(next,next2);
                if (start == InvalidSquare) return NullMove;
                it+=3; // point to dest
                piece = TypeOfPiece(board[start]);
             }
          }
       }
    }
    if (piece == Empty) {
       return NullMove;
    }
    if (piece != Pawn && !have_start && it != img.end()) {
       char next = *it;
       char next2 = '\0';
       if (it + 1 != img.end()) next2 = *(it+1);
       if (is_file(next) && isdigit(next2) && img.length()>=5) {
          // long algebraic notation, or a SAN move like Qd1d3
          start = SquareValue(next,next2);
          if (IsInvalid(start)) return NullMove;
          it+=2;
          have_start++;
       }
       // also look for disambiguating rank, e.g. '2' in "N2e4".
       else if (isdigit(next)) {
          rank = next - '0';
          if (rank < 1 || rank > 8) return NullMove;
          it++;
       }
       else if (is_file(next) && isalpha(next2)) {
          // disamiguating rank, e.g. "Rfd1"
          file = next - 'a' + 1;
          if (file < 1 || file > 8) return NullMove;
          it++;
       }
    }

    if (it != img.end() && *it == 'x') {
       capture = 1;
       it++;
    }
    if (it != img.end() && (it+1) != img.end()) {
       // remainder of move should be a square identifier, e.g. "g7"
       dest = SquareValue(*it,*(it+1));
       it += 2;
    }
    if (IsInvalid(dest)) {
       return NullMove;
    }
    if (it != img.end() && *it == '=') {
       it++;
       if (it == img.end()) {
          return NullMove;
       } else {
          promotion = PieceCharValue(*it);
          if (piece != Pawn || promotion == Empty)
             return NullMove;
          it++;
       }
    }
    else if (piece == Pawn && it != img.end() && isupper(*it)) {
       // Quite a few "PGN" files have a8Q instead of a8=Q.
       promotion = PieceCharValue(*it);
       if (promotion == Empty || Rank(dest,side) != 8)
          return NullMove;
    } else if (piece == Pawn && Rank(dest,side) == 8) {
       // promotion but no piece specified, treat as error
       return NullMove;
    }

    // Informant does not use "x" for captures.  Assume that if the destination
    // is occupied, this is a capture move.
    if (board[dest] != EmptyPiece) {
       capture = 1;
    }
    // Do a sanity check on capture moves:
    if (capture && !IsEmptyPiece(board[dest]) && PieceColor(board[dest]) == board.sideToMove()) {
       return NullMove;
    }

    // Ok, now we need to figure out where the start square is. For pawn
    // moves this is implicit.

    int dups = 0;

    if (!have_start) {
       if (capture && piece == Pawn && IsEmptyPiece(board[dest]) &&
           Rank(dest,board.sideToMove()) != 8) {
          // en passant capture, special case
          int start_rank = (board.sideToMove() == White) ?
             Rank(dest,White) - 1 :
             Rank(dest,White) + 1;

          start = MakeSquare(file, start_rank, White);
          dups = 1;
       }
       else if (piece == Pawn && board[dest] == EmptyPiece) {
          start = MakeSquare(file,Rank(dest,board.sideToMove())-1,board.sideToMove());
          if (board[start] == EmptyPiece && Rank(dest,board.sideToMove())==4) {
             start = MakeSquare(file,Rank(dest,board.sideToMove())-2,board.sideToMove());
          }
          if (board[start] == EmptyPiece) return NullMove;
          dups = 1;
       }
       else {
          Bitboard attacks = board.calcAttacks(dest,side);
          Square maybe;
          while (attacks.iterate(maybe)) {
             if (TypeOfPiece(board[maybe]) == piece &&
                 PieceColor(board[maybe]) == board.sideToMove()) {
                if (file && File(maybe) != file)
                   continue;
                if (rank && Rank(maybe,White) != rank)
                   continue;
                if (PieceColor(board[maybe]) == board.sideToMove()) {
                   // Possible move to this square.  Make sure it is legal.
                   Board board_copy(board);
                   Move emove = CreateMove(board,maybe,dest,
                                           promotion);
                   board_copy.doMove(emove);
                   if (!board_copy.anyAttacks(
                          board_copy.kingSquare(board_copy.oppositeSide()),
                          board_copy.sideToMove())) {
                      ++dups;
                      start = maybe;
                   }
                }
             }
          }
       }
    }
    if (dups == 1 || have_start) {
       if (start == InvalidSquare || board[start] == EmptyPiece)
          return NullMove;
       else
          return CreateMove(board, start, dest, promotion);
    }
    else                                           // ambiguous move
       return NullMove;
}
Ejemplo n.º 17
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
}