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

improve connection games #768

Open
wants to merge 5 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
16 changes: 13 additions & 3 deletions src/evaluate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1281,8 +1281,17 @@ namespace {
}

// Connect-n
if (pos.connect_n() > 0)
if (pos.connect_n() > 0 && (pos.variant()->connectValue != VALUE_DRAW))
{
//Calculate eligible pieces for connection once.
//Still consider all opponent pieces as blocking.
Bitboard connectPiecesUs = 0;
for (PieceSet ps = pos.connect_piece_types(); ps;){
PieceType pt = pop_lsb(ps);
connectPiecesUs |= pos.pieces(pt);
};
connectPiecesUs &= pos.pieces(Us);

for (const Direction& d : pos.getConnectDirections())

{
Expand All @@ -1296,9 +1305,10 @@ namespace {
Square s = pop_lsb(b);
int c = 0;
for (int j = 0; j < pos.connect_n(); j++)
if (pos.pieces(Us) & (s - j * d))
if (connectPiecesUs & (s - j * d))
c++;
score += make_score(200, 200) * c / (pos.connect_n() - c) / (pos.connect_n() - c);
score += (pos.variant()->connectValue==VALUE_MATE ? 1 : -1) * //At least change the sign for misere variants.
(make_score(200, 200) * c / (pos.connect_n() - c) / (pos.connect_n() - c));
}
}
}
Expand Down
67 changes: 42 additions & 25 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2801,7 +2801,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
connectPieces &= pieces(~sideToMove);

// Connect-n
if (connect_n() > 0)
if ((connect_n() > 0) && (popcount(connectPieces) >= connect_n()))
{
Bitboard b;

Expand Down Expand Up @@ -2843,8 +2843,8 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
current |= newBitboard;
}
}
if (connect_nxn())

if ((connect_nxn()) && (popcount(connectPieces) >= connect_nxn() * connect_nxn()))
{
Bitboard connectors = connectPieces;
for (int i = 1; i < connect_nxn() && connectors; i++)
Expand All @@ -2857,28 +2857,45 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
}

// Collinear-n
if (collinear_n() > 0) {
Bitboard allPieces = connectPieces;
for (Direction d : var->connect_directions) {
Bitboard b = allPieces;
while (b) {
Square s = pop_lsb(b);

int total_count = 1; // Start with the current piece

// Check in both directions
for (int sign : {-1, 1}) {
Bitboard shifted = shift(sign * d, square_bb(s));
while (shifted) {
if (shifted & b) {
total_count++;
b &= ~shifted; // Remove this piece from further consideration
}
shifted = shift(sign * d, shifted);
}
}
if ((collinear_n() > 0) && (popcount(connectPieces) >= collinear_n())) {
Bitboard pieces = connectPieces;
while (pieces) {


if (total_count >= collinear_n()) {
/*
//can't combine this with the (!is_ok(shifted_square)) optimization below
//if it relies on there being another piece to count it as part of its line,
//can't early out.
if (popcount(pieces) < collinear_n()) {
break; // Early out to the next section
}
*/
//Use pop_lsb to loop through the pieces. Then for each of the directions,
//use line_bb to calculate the entire row, column or diagonal that contains
//the piece and the shifted square, then use popcount to count the number
//of pieces on that line.
Square s = pop_lsb(pieces);
for (Direction d : var->connect_directions) {
Square shifted_square = s + d;


if (!is_ok(shifted_square)) continue; //This is totally fine.
//Pieces where the shift is outside the board will not be processed
//for that direction, but in order to be collinear with another piece,
//there would be another piece that counts it as part of its line.
//Even if say, all the pieces were on the EAST edge, it's the NORTH
//direction that would count them up.
//Only exception is that if collinearN was set to 1, and there was 1
//piece on the NORTH_EAST corner, it wouldn't count. Possible solutions:
//1. Ignore
//2. Tell user that collinearN=1 is silly, use flagPieces or connectN
//3. Special case here to check
//4. Quietly convert it to connectN=1


Bitboard line = line_bb(s, shifted_square);
int piece_count = popcount(line & connectPieces);
if (piece_count >= collinear_n()) {
result = convert_mate_value(-var->connectValue, ply);
return true;
}
Expand All @@ -2887,7 +2904,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
}

// Check for bikjang rule (Janggi), double passing, or board running full
if ( (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
if ( (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || ((st->pass && st->previous->pass)&&!var->wallOrMove)))
|| (var->adjudicateFullBoard && !(~pieces() & board_bb())))
{
result = var->materialCounting ? convert_mate_value(material_counting_result(), ply) : VALUE_DRAW;
Expand Down
2 changes: 1 addition & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -1039,7 +1039,7 @@ inline int Position::connect_n() const {

inline PieceSet Position::connect_piece_types() const {
assert(var != nullptr);
return var->connectPieceTypes;
return var->connectPieceTypesTrimmed;
}

inline bool Position::connect_horizontal() const {
Expand Down
7 changes: 4 additions & 3 deletions src/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2066,15 +2066,16 @@ Variant* Variant::conclude() {
connect_directions.push_back(SOUTH_EAST);
}

// If not a connect variant, set connectPieceTypes to no pieces.
// If not a connect variant, set connectPieceTypesTrimmed to no pieces.
// connectPieceTypesTrimmed is separated so that connectPieceTypes is left unchanged for inheritance.
if ( !(connectRegion1[WHITE] || connectRegion1[BLACK] || connectN || connectNxN || collinearN) )
{
connectPieceTypes = NO_PIECE_SET;
connectPieceTypesTrimmed = NO_PIECE_SET;
}
//Otherwise optimize to pieces actually in the game.
else
{
connectPieceTypes = connectPieceTypes & pieceTypes;
connectPieceTypesTrimmed = connectPieceTypes & pieceTypes;
};

return this;
Expand Down
1 change: 1 addition & 0 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ struct Variant {
bool endgameEval = false;
bool shogiStylePromotions = false;
std::vector<Direction> connect_directions;
PieceSet connectPieceTypesTrimmed = ~NO_PIECE_SET;

void add_piece(PieceType pt, char c, std::string betza = "", char c2 = ' ') {
// Avoid ambiguous definition by removing existing piece with same letter
Expand Down
Loading