Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hostage #19 #758

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ffishjs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ namespace ffish {

bool captures_to_hand(std::string uciVariant) {
const Variant* v = get_variant(uciVariant);
return v->capturesToHand;
return v->captureType != MOVE_OUT;
}

std::string starting_fen(std::string uciVariant) {
Expand Down
54 changes: 54 additions & 0 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ namespace {
for (PieceSet promotions = pos.promotion_piece_types(c); promotions;)
{
PieceType pt = pop_msb(promotions);
if (pos.prison_pawn_promotion() && pos.count_in_prison(~c, pt) == 0) {
continue;
}
if (!pos.promotion_limit(pt) || pos.promotion_limit(pt) > pos.count(c, pt))
moveList = make_move_and_gating<PROMOTION>(pos, moveList, pos.side_to_move(), to - D, to, pt);
}
Expand Down Expand Up @@ -130,6 +133,50 @@ namespace {
return moveList;
}

template<Color Us, GenType Type>
ExtMove* generate_exchanges(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) {
assert(Type != CAPTURES);
static_assert(SQUARE_BITS >= PIECE_TYPE_BITS, "not enough bits for exchange move");
Color opp = ~Us;
if (pos.count_in_prison(opp, pt) > 0) {
PieceSet rescue = NO_PIECE_SET;
for (PieceSet r = pos.rescueFor(pt); r; ) {
PieceType ex = pop_lsb(r);
if (pos.count_in_prison(Us, ex) > 0) {
rescue |= ex;
}
}
if (rescue == NO_PIECE_SET) {
return moveList;
}
// Restrict to valid target
b &= pos.drop_region(Us, pt);
// Add to move list
if (pos.drop_promoted() && pos.promoted_piece_type(pt)) {
Bitboard b2 = b;
if (Type == QUIET_CHECKS)
b2 &= pos.check_squares(pos.promoted_piece_type(pt));
while (b2) {
auto to = pop_lsb(b2);
for (PieceSet r = rescue; r; ) {
PieceType ex = pop_lsb(r);
*moveList++ = make_exchange(to, ex, pt, pos.promoted_piece_type(pt));
}
}
}
if (Type == QUIET_CHECKS)
b &= pos.check_squares(pt);
while (b) {
auto to = pop_lsb(b);
for (PieceSet r = rescue; r; ) {
PieceType ex = pop_lsb(r);
*moveList++ = make_exchange(to, ex, pt, pt);
}
}
}
return moveList;
}

template<Color Us, GenType Type>
ExtMove* generate_pawn_moves(const Position& pos, ExtMove* moveList, Bitboard target) {

Expand Down Expand Up @@ -356,6 +403,9 @@ namespace {
for (PieceSet ps = pos.promotion_piece_types(Us); ps;)
{
PieceType ptP = pop_msb(ps);
if (pos.prison_pawn_promotion() && pos.count_in_prison(~Us, ptP) == 0) {
continue;
}
if (!pos.promotion_limit(ptP) || pos.promotion_limit(ptP) > pos.count(Us, ptP))
for (Bitboard promotions = pawnPromotions; promotions; )
moveList = make_move_and_gating<PROMOTION>(pos, moveList, pos.side_to_move(), from, pop_lsb(promotions), ptP);
Expand Down Expand Up @@ -408,6 +458,10 @@ namespace {
if (pos.piece_drops() && Type != CAPTURES && (pos.can_drop(Us, ALL_PIECES) || pos.two_boards()))
for (PieceSet ps = pos.piece_types(); ps;)
moveList = generate_drops<Us, Type>(pos, moveList, pop_lsb(ps), target & ~pos.pieces(~Us));
// generate exchange
if (pos.capture_type() == PRISON && Type != CAPTURES && pos.has_exchange())
for (PieceSet ps = pos.piece_types(); ps;)
moveList = generate_exchanges<Us, Type>(pos, moveList, pop_lsb(ps), target & ~pos.pieces(~Us));

// Castling with non-king piece
if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(Us & ANY_CASTLING))
Expand Down
2 changes: 1 addition & 1 deletion src/movepick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Move MovePicker::next_move(bool skipQuiets) {
case QSEARCH_TT:
case PROBCUT_TT:
++stage;
assert(pos.legal(ttMove) == MoveList<LEGAL>(pos).contains(ttMove) || pos.virtual_drop(ttMove));
assert(pos.legal(ttMove) == MoveList<LEGAL>(pos).contains(ttMove) || pos.virtual_drop(ttMove) || exchange_piece(ttMove));
return ttMove;

case CAPTURE_INIT:
Expand Down
67 changes: 66 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ namespace {
return value == "win" || value == "loss" || value == "draw" || value == "none";
}

template <> bool set(const std::string& value, CapturingRule& target) {
target = value == "out" ? MOVE_OUT
: value == "hand" ? HAND
: value == "prison" ? PRISON
: MOVE_OUT;
return value == "out" || value == "hand" || value == "prison";
}

template <> bool set(const std::string& value, MaterialCounting& target) {
target = value == "janggi" ? JANGGI_MATERIAL
: value == "unweighted" ? UNWEIGHTED_MATERIAL
Expand Down Expand Up @@ -187,6 +195,50 @@ namespace {
target |= pt;
}

void parse_hostage_exchanges(Variant *v, std::string &map, bool DoCheck) {
bool readPiece = true;
size_t idx = -1;
PieceSet mask = NO_PIECE_SET;
for (size_t i = 0; i < map.size(); ++i) {
char token = map[i];
if (token == ' ') {
if (!readPiece) {
v->hostageExchange[idx] = mask;
readPiece = true;
}
continue;
}
if (readPiece) {
mask = NO_PIECE_SET;
idx = v->pieceToChar.find(toupper(token));
if (idx == std::string::npos) {
if (DoCheck) {
std::cerr << "hostageExchange - Invalid piece type: " << token << std::endl;
}
return;
}
readPiece = false;
} else if (token == ':') {
if (mask != NO_PIECE_SET) {
if (DoCheck) {
std::cerr << "hostageExchange - Invalid syntax: " << map << std::endl;
}
return;
}
} else {
size_t idx2 = v->pieceToChar.find(toupper(token));
if (idx2 == std::string::npos) {
if (DoCheck) {
std::cerr << "hostageExchange - Invalid hostage piece type: " << token << std::endl;
}
return;
}
mask = mask | PieceType(idx2);
}
}
v->hostageExchange[idx] = mask;
}

} // namespace

template <bool DoCheck>
Expand All @@ -207,6 +259,7 @@ template <bool Current, class T> bool VariantParser<DoCheck>::parse_attribute(co
: std::is_same<T, MaterialCounting>() ? "MaterialCounting"
: std::is_same<T, CountingRule>() ? "CountingRule"
: std::is_same<T, ChasingRule>() ? "ChasingRule"
: std::is_same<T, CapturingRule>() ? "CapturingRule"
: std::is_same<T, EnclosingRule>() ? "EnclosingRule"
: std::is_same<T, Bitboard>() ? "Bitboard"
: std::is_same<T, CastlingRights>() ? "CastlingRights"
Expand Down Expand Up @@ -453,7 +506,19 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("mustDropType", v->mustDropType, v->pieceToChar);
parse_attribute("pieceDrops", v->pieceDrops);
parse_attribute("dropLoop", v->dropLoop);
parse_attribute("capturesToHand", v->capturesToHand);

bool capturesToHand = false;
if (parse_attribute<false>("capturesToHand", capturesToHand)) {
v->captureType = capturesToHand ? HAND : MOVE_OUT;
}

parse_attribute("captureType", v->captureType);
// hostage price
const auto& it_host_p = config.find("hostageExchange");
if (it_host_p != config.end()) {
parse_hostage_exchanges(v, it_host_p->second, DoCheck);
}
parse_attribute("prisonPawnPromotion", v->prisonPawnPromotion);
parse_attribute("firstRankPawnDrops", v->firstRankPawnDrops);
parse_attribute("promotionZonePawnDrops", v->promotionZonePawnDrops);
parse_attribute("enclosingDrop", v->enclosingDrop);
Expand Down
Loading
Loading