sakurapyon’s blog

sakurapyon’s blog

打一手詰

もっとさぼれるところがあると思う。

//
//	簡易1手詰(駒打ち)
//	呼び出し元で持ち駒があることは確認している
//
template	<Player_t p,Player_t op>
inline  Move Board::hMate1PlyDrop()
{
	//
	// 玉の近傍に駒を打って詰ませる
	const int	pos=king[op];
	int	to;
	//
	// 桂馬を打って詰むかな?
	if(Hand(p,Knight)){
		BitBoard b=((p==Black)?bb_white_knight_attack[pos]:bb_black_knight_attack[pos])-occupied;	// 桂馬の利きは近傍8箇所じゃないから最初に処理
		while((to=b.BitScanClear())!=-1){
			//if(!isAttacked(op,to))	continue;						// 桂馬の場合は自利きは要らない
			if(hCanKingEscapeByDrop<op>(pos,to,((p==Black)?bb_black_knight_attack[to]:bb_white_knight_attack[to])))	continue;
			if(hCanCapture<op>(to)) continue;
			return	Move(p,to,Knight,0);
		}
	}
	if(!(hand[p]&(HANDLANCE|HANDSILVER|HANDGOLD|HANDBISHOP|HANDROOK))){
		return	Move(0);	// 歩・桂馬以外の持ち駒無し
	}
	//
	BitBoard b_drop=bb_king_attack[pos]-occupied;				// 玉近傍に駒が打てる場所(玉の回り8箇所-既に駒のある場所)
	if(b_drop.isZero())	return	Move(0);				// 打てる場所がない

	BitBoard b_put(0);
	if(Hand(p,Silver))	b_put|=((p==Black)?bb_white_silver_attack[pos]:bb_black_silver_attack[pos]);
	else if(Hand(p,Bishop))	b_put|=bb_cross[pos];
	if(Hand(p,Gold))	b_put|=((p==Black)?bb_white_gold_attack[pos]:bb_black_gold_attack[pos]);
	else if(Hand(p,Rook))	b_put|=bb_plus[pos];
	else if(Hand(p,Lance))	b_put|=((p==Black)?bb_white_pawn_attack[pos]:bb_black_pawn_attack[pos]);
	b_drop&=b_put;
	if(b_drop.isZero())	return	Move(0);				// 打って王手になる場所がない

	BitBoard b=b_drop;
	foreach_BitScanClear(b,to,				\
		{						\
			if(!isAttacked(op,to)){			\
				b_drop.Off(to);			\
			}					\
		}						\
	);
	if(b_drop.isZero())	return	Move(0);				// 自利きのある打てる場所がない

	if(Hand(p,Rook)){	// 飛車を打って詰ませる
		BitBoard b=b_drop&bb_plus[pos];					// 飛車を打って王手になる場所
		while((to=b.BitScanClear())!=-1){				// 飛車が打てる升目を調べる
			if(hCanKingEscapeByDrop<op>(pos,to,(bb_file[to]|bb_rank[to])))	continue;
			if(hCanCapture<op>(to)){
				b_drop.Off(to);					// 打った駒が玉以外の駒で取られるのであれば、ここには何を打っても詰まない
				continue;					// 打った飛車が玉以外の駒で取れるようだ
			}
			return Move(p,to,Rook,0);				// 逃げられないなら詰み
		}
	}else if(Hand(p,Lance) && ((p==Black)?(pos<72):(pos>=9))){		// 飛車を打って詰まないなら香車を打っても詰まない
		to=(p==Black)?(pos+9):(pos-9);
		if(board[to]==Empty){
			if(hCanKingEscapeByDrop<op>(pos,to,(p==Black)?bb_black_lance_attack[to]:bb_white_lance_attack[to])){
				// 玉が逃げて詰まない
			}else if(hCanCapture<op>(to)){
				b_drop.Off(to);					// 打った香車が玉以外の駒で取れるようだ
			}else{
				return Move(p,to,Lance,0);			// 詰んだ
			}
		}
	}
	if(Hand(p,Bishop)){
		BitBoard b=b_drop&bb_cross[pos];				// 角を打って王手になる場所
		while((to=b.BitScanClear())!=-1){
			if(hCanKingEscapeByDrop<op>(pos,to,bb_left[to]|bb_right[to]))	continue;
			if(hCanCapture<op>(to)){
				b_drop.Off(to);					// 打った駒が玉以外の駒で取られるのであれば、ここには何を打っても詰まない
				continue;
			}
			return Move(p,to,Bishop,0);			// 逃げられないなら詰み
		}
	}
	if(Hand(p,Gold)){
		BitBoard b=((b_drop&((p==Black)?bb_white_gold_attack[pos]:bb_black_gold_attack[pos])));	
		if(Hand(p,Rook))	b-=((p==Black)?bb_black_pawn_attack[pos]:bb_white_pawn_attack[pos]);	// 飛車で詰まないなら尻金でも詰まない
		while((to=b.BitScanClear())!=-1){
			if(hCanKingEscapeByDrop<op>(pos,to,((p==Black)?bb_black_gold_attack[to]:bb_white_gold_attack[to])))	continue;
			if(hCanCapture<op>(to)) continue;		// (b_drop.Offしなくても大丈夫)
			return Move(p,to,Gold,0);
		}
	}
	if(Hand(p,Silver) && !(Hand(p,Bishop)&&Hand(p,Gold))){		// 角金で詰まないなら、銀を持っていても詰まない
		BitBoard b=(b_drop&((p==Black)?bb_white_silver_attack[pos]:bb_black_silver_attack[pos]));
		if(Hand(p,Gold)){										// 金で詰まないのであれば上から打つ詰みはない
			b-=((p==Black)?	(bb_white_gold_attack[pos]&bb_white_silver_attack[pos]):
					(bb_black_gold_attack[pos]&bb_black_silver_attack[pos]));
		}else if(Hand(p,Bishop)){
			b&=((p==Black)?bb_white_gold_attack[pos]:bb_black_gold_attack[pos]);	// 角で詰まないのであれば尻銀は考えなくて良い
		}
		while((to=b.BitScanClear())!=-1){
			if(hCanKingEscapeByDrop<op>(pos,to,((p==Black)?bb_black_silver_attack[to]:bb_white_silver_attack[to])))	continue;
			if(hCanCapture<op>(to)) continue;
			return Move(p,to,Silver,0);
		}
	}
	return	Move(0);
}