This code was written several years ago, it's not optimized at all and it is redundant for black and white. But that doesn't matter because the result is stored in the hash table so this function is called rarely.
It's called when only pawns are left.
It was written following the code example and the rules described by Omid David in his paper: (2006). Blockage Detection in Pawn Endgames.
Perhaps it could be interesting for someone.
Sorry it's not commented but can be easily understood reading the paper.
Code: Select all
int FormsFence(int f, int r, int marked[8][8], int fence[8][8], int processed[8][8])
{
processed[f][r] = 1;
if (f == FILE_H) {
fence[f][r] = 1;
return(1);
}
if (marked[f][r + 1] && !processed[f][r + 1] && FormsFence(f, r + 1, marked, fence, processed)) {
fence[f][r] = 1;
return(1);
}
if (marked[f + 1][r] && !processed[f + 1][r] && FormsFence(f + 1, r, marked, fence, processed)) {
fence[f][r] = 1;
return(1);
}
if (marked[f][r - 1] && !processed[f][r - 1] && FormsFence(f, r - 1, marked, fence, processed)) {
fence[f][r] = 1;
return(1);
}
return(0);
}
int Blockage(SEARCH_INFO *search)
{
int f, r, sq;
int fixed_pawn[8][8] = {0};
int fence_rank[8];
int dynamic_pawns[8];
int i, n_dyn = 0;
int fence_formed = 0;
int blockage = 0;
int marked[8][8] = {0};
int fence[8][8] = {0};
int processed[8][8] = {0};
if (search->pos.side == WHITE) {
for (r = RANK_7; r > RANK_1; r--) {
for (f = FILE_A; f <= FILE_H; f++) {
sq = r * 8 + f;
if (search->pos.board[sq] == WPAWN) {
if ( (r < RANK_7 && (search->pos.board[sq + 8] == BPAWN || fixed_pawn[f][r + 1]))
&& (f == FILE_A || search->pos.board[sq + 7] != BPAWN)
&& (f == FILE_H || search->pos.board[sq + 9] != BPAWN)) {
fixed_pawn[f][r] = 1;
marked[f][r] = 1;
}
else
dynamic_pawns[n_dyn++] = sq;
}
else if (search->pos.board[sq] == BPAWN) {
if (f != FILE_A)
marked[f - 1][r - 1] = 1;
if (f != FILE_H)
marked[f + 1][r - 1] = 1;
}
}
}
for (r = RANK_7; r > RANK_1; r--) {
if (marked[FILE_A][r] && FormsFence(FILE_A, r, marked, fence, processed)) {
fence_formed = 1;
break;
}
}
if (!fence_formed)
goto end;
for (f = FILE_A; f <= FILE_H; f++) {
for (r = RANK_2; r < RANK_8; r++) {
if (fence[f][r]) {
fence_rank[f] = r;
break;
}
}
}
if (RANK(search->pos.king_sq[WHITE]) > fence_rank[FILE(search->pos.king_sq[WHITE])])
goto end;
for (f = FILE_A; f <= FILE_H; f++) {
sq = fence_rank[f] * 8 + f - 8;
for (; sq > H1; sq -= 8) {
if (search->pos.board[sq] == BPAWN && search->pos.board[sq - 8] == WPAWN)
dynamic_pawns[n_dyn++] = sq - 8;
}
}
for (i = 0; i < n_dyn; i++) {
sq = dynamic_pawns[i];
f = FILE(sq);
r = RANK(sq);
if (r > fence_rank[f]) {
if (!(search->pos.piece_bb[BPAWN] & passed_mask[WHITE][sq])) {
if (FILE(search->pos.king_sq[BLACK]) != f || RANK(search->pos.king_sq[BLACK]) < r)
goto end;
}
}
else if (fence[f][r]) {
if (r >= RANK_6)
goto end;
if (search->pos.board[sq + 16] != BPAWN) {
if (FILE(search->pos.king_sq[BLACK]) != f)
goto end;
if (RANK(search->pos.king_sq[BLACK]) < r)
goto end;
if ( (f != FILE_A && search->pos.board[sq - 1] != WPAWN)
|| POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f - 1]) > 1
|| !fixed_pawn[f - 1][r]
|| !fence[f - 1][r])
goto end;
if ( (f != FILE_H && search->pos.board[sq + 1] != WPAWN)
|| POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f + 1]) > 1
|| !fixed_pawn[f + 1][r]
|| !fence[f + 1][r])
goto end;
}
if (f != FILE_A && search->pos.board[sq + 15] == BPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq + 17] == BPAWN)
goto end;
if(POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f]) > 1)
goto end;
}
else if (r < fence_rank[f]) {
sq += 8;
f = FILE(sq);
r = RANK(sq);
while (!fence[f][r]) {
if (f != FILE_A && search->pos.board[sq + 7] == BPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq + 9] == BPAWN)
goto end;
if (search->pos.board[sq] == WPAWN)
break;
sq += 8;
f = FILE(sq);
r = RANK(sq);
}
if (fence[f][r] && search->pos.board[sq] == EMPTY) {
if (r >= RANK_6)
goto end;
if (search->pos.board[sq + 16] != BPAWN) {
if (FILE(search->pos.king_sq[BLACK]) != f)
goto end;
if (RANK(search->pos.king_sq[BLACK]) < r)
goto end;
if ( (f != FILE_A && search->pos.board[sq - 1] != WPAWN)
|| POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f - 1]) > 1
|| !fixed_pawn[f - 1][r]
|| !fence[f - 1][r])
goto end;
if ( (f != FILE_H && search->pos.board[sq + 1] != WPAWN)
|| POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f + 1]) > 1
|| !fixed_pawn[f + 1][r]
|| !fence[f + 1][r])
goto end;
}
if (f != FILE_A && search->pos.board[sq + 15] == BPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq + 17] == BPAWN)
goto end;
if(POPCNT(search->pos.piece_bb[WPAWN] & file_mask[f]) > 1)
goto end;
}
}
}
}
else {
for (r = RANK_1; r < RANK_8; r++) {
for (f = FILE_A; f<= FILE_H; f++) {
sq = r * 8 + f;
if (search->pos.board[sq] == BPAWN) {
if ( (r > RANK_1 && (search->pos.board[sq - 8] == WPAWN || fixed_pawn[f][r - 1]))
&& (f == FILE_A || search->pos.board[sq - 9] != WPAWN)
&& (f == FILE_H || search->pos.board[sq - 7] != WPAWN)) {
fixed_pawn[f][r] = 1;
marked[f][r] = 1;
}
else
dynamic_pawns[n_dyn++] = sq;
}
else if (search->pos.board[sq] == WPAWN) {
if (f != FILE_A)
marked[f - 1][r + 1] = 1;
if (f != FILE_H)
marked[f + 1][r + 1] = 1;
}
}
}
for (r = RANK_7; r > RANK_1; r--) {
if (marked[FILE_A][r] && FormsFence(FILE_A, r, marked, fence, processed)) {
fence_formed = 1;
break;
}
}
if (!fence_formed)
goto end;
for (f = FILE_A; f <= FILE_H; f++) {
for (r = RANK_7; r > RANK_1; r--) {
if (fence[f][r]) {
fence_rank[f] = r;
break;
}
}
}
if (RANK(search->pos.king_sq[BLACK]) < fence_rank[FILE(search->pos.king_sq[BLACK])])
goto end;
for (f = FILE_A; f <= FILE_H; f++) {
sq = fence_rank[f] * 8 + f + 8;
for (; sq < A8; sq += 8) {
if (search->pos.board[sq] == WPAWN && search->pos.board[sq + 8] == BPAWN)
dynamic_pawns[n_dyn++] = sq + 8;
}
}
for (i = 0; i < n_dyn; i++) {
sq = dynamic_pawns[i];
f = FILE(sq);
r = RANK(sq);
if (r < fence_rank[f]) {
if (!(search->pos.piece_bb[WPAWN] & passed_mask[BLACK][sq])) {
if (FILE(search->pos.king_sq[WHITE]) != f || RANK(search->pos.king_sq[WHITE]) > r)
goto end;
}
}
else if (fence[f][r]) {
if (r <= RANK_3)
goto end;
if (search->pos.board[sq - 16] != WPAWN) {
if (FILE(search->pos.king_sq[WHITE]) != f)
goto end;
if (RANK(search->pos.king_sq[WHITE]) > r)
goto end;
if ( (f != FILE_A && search->pos.board[sq - 1] != BPAWN)
|| POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f - 1]) > 1
|| !fixed_pawn[f - 1][r]
|| !fence[f - 1][r])
goto end;
if ( (f != FILE_H && search->pos.board[sq + 1] != BPAWN)
|| POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f + 1]) > 1
|| !fixed_pawn[f + 1][r]
|| !fence[f + 1][r])
goto end;
}
if (f != FILE_A && search->pos.board[sq - 17] == WPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq - 15] == WPAWN)
goto end;
if (POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f]) > 1)
goto end;
}
else if (r > fence_rank[f]) {
sq = sq - 8;
f = FILE(sq);
r = RANK(sq);
while (!fence[f][r]) {
if (f != FILE_A && search->pos.board[sq - 9] == WPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq - 7] == WPAWN)
goto end;
if (search->pos.board[sq] == BPAWN)
break;
sq -= 8;
f = FILE(sq);
r = RANK(sq);
}
if (fence[f][r] && search->pos.board[sq] == EMPTY) {
if (r <= RANK_3)
goto end;
if (search->pos.board[sq - 16] != WPAWN) {
if (FILE(search->pos.king_sq[WHITE]) != f)
goto end;
if (RANK(search->pos.king_sq[WHITE]) > r)
goto end;
if ( (f != FILE_A && search->pos.board[sq - 1] != BPAWN)
|| POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f - 1]) > 1
|| !fixed_pawn[f - 1][r]
|| !fence[f - 1][r])
goto end;
if ( (f != FILE_H && search->pos.board[sq + 1] != BPAWN)
|| POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f + 1]) > 1
|| !fixed_pawn[f + 1][r]
|| !fence[f + 1][r])
goto end;
}
if (f != FILE_A && search->pos.board[sq - 17] == WPAWN)
goto end;
if (f != FILE_H && search->pos.board[sq - 15] == WPAWN)
goto end;
if (POPCNT(search->pos.piece_bb[BPAWN] & file_mask[f]) > 1)
goto end;
}
}
}
}
blockage = 1;
end:
return(blockage);
}