bug in Stockfish-Evaluation-Guide

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
Kotlov
Posts: 271
Joined: Fri Jul 10, 2015 9:23 pm
Location: Russia

bug in Stockfish-Evaluation-Guide

Post by Kotlov »

I realize this is a bit late, but for the sake of historical record (and out of deep respect for StockFish), I’m going to write this anyway.
I found a bug in the JS representation of the evaluation.

Let's take a position to examine.
[d]8/5k2/8/6p1/7p/8/6N1/4K3 w - - 1 66


The point is that the code wants to check the passed h4-pawn for a "Passed block."

Code: Select all

function passed_block(pos, square) {
  if (square == null) return sum(pos, passed_block);
  if (!passed_leverable(pos, square)) return 0;
  if (rank(pos, square) < 4) return 0;
  if (board(pos, square.x, square.y - 1) != "-") return 0;
  var r = rank(pos, square) - 1;
  var w = r > 2 ? 5 * r - 13 : 0;
  var pos2 = colorflip(pos);
  var defended = 0, unsafe = 0, wunsafe = 0, defended1 = 0, unsafe1 = 0;
  for (var y = square.y - 1; y >= 0; y--) {
    if (attack(pos, {x:square.x,y:y})) defended++;
    if (attack(pos2, {x:square.x,y:7-y})) unsafe++;
    if (attack(pos2, {x:square.x-1,y:7-y})) wunsafe++;
    if (attack(pos2, {x:square.x+1,y:7-y})) wunsafe++;
    if (y == square.y - 1) {
      defended1 = defended;
      unsafe1 = unsafe;
    }
  }
  for (var y = square.y + 1; y < 8; y++) {
    if (board(pos, square.x, y) == "R"
     || board(pos, square.x, y) == "Q") defended1 = defended = square.y;
    if (board(pos, square.x, y) == "r"
     || board(pos, square.x, y) == "q") unsafe1 = unsafe = square.y;
  }
  var k = (unsafe == 0 && wunsafe == 0 ? 35 : unsafe == 0 ? 20 : unsafe1 == 0 ? 9 : 0)
        + (defended1 != 0 ? 5 : 0);
  return k * w;
}
we look at

Code: Select all

if (attack(pos2, {x:square.x+1,y:7-y})) wunsafe++;
These are the coordinates for a pawn move to the right (to the virtual square i3); we want to check whether this square is under attack by White's pieces.

Code: Select all

function attack(pos, square) {
  if (square == null) return sum(pos, attack);
  var v = 0;
  v += pawn_attack(pos, square);
  v += king_attack(pos, square);
  v += knight_attack(pos, square);
  v += bishop_xray_attack(pos, square);
  v += rook_xray_attack(pos, square);
  v += queen_attack(pos, square);
  return v;
}
We are interested in...

Code: Select all

 v += knight_attack(pos, square);
Let's take a look.

Code: Select all

function knight_attack(pos, square, s2) {
  if (square == null) return sum(pos, knight_attack);
  var v = 0;
  for (var i = 0; i < 8; i++) {
    var ix = ((i > 3) + 1) * (((i % 4) > 1) * 2 - 1);
    var iy = (2 - (i > 3)) * ((i % 2 == 0) * 2 - 1);
    var b = board(pos, square.x + ix, square.y + iy);
    if (b == "N"
    && (s2 == null || s2.x == square.x + ix && s2.y == square.y + iy)
    && !pinned(pos, {x:square.x + ix, y:square.y + iy})) v++;
  }
  return v;
}
We calculate (ix, iy) and discover that the knight on g2 is indeed attacking the illegal square i3, because the board() function only checks the knight's own square, which is legal.

Code: Select all

function board(pos, x, y) {
  if (x >= 0 && x <= 7 && y >= 0 && y <= 7) return pos.b[x][y];
  return "x";
}
Image

The code includes a separate function to check for going off the board.

Code: Select all

function bounds(x, y) {
  return x >= 0 && x <= 7 && y >= 0 && y <= 7;
}
but it is not called for

Code: Select all

    if (attack(pos2, {x:square.x-1,y:7-y})) wunsafe++;
    if (attack(pos2, {x:square.x+1,y:7-y})) wunsafe++;
from

Code: Select all

passed_block()
-----
If the historical legacy of the core engine matters to anyone, then shouldn't it be fixed?
Eugene Kotlov author Hedgehog 2.6 64-bit
User avatar
Kotlov
Posts: 271
Joined: Fri Jul 10, 2015 9:23 pm
Location: Russia

Re: bug in Stockfish-Evaluation-Guide

Post by Kotlov »

Eugene Kotlov author Hedgehog 2.6 64-bit