]> git.sesse.net Git - remoteglot/commitdiff
chess.js: Faster and smaller attacked(). (A test perft went from ~11.5 to ~7.5 secs.)
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 25 Dec 2022 12:35:07 +0000 (13:35 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 25 Dec 2022 12:35:07 +0000 (13:35 +0100)
www/js/chess.js

index 9a2d383047dc167bebb571e4e4b515601cbd6589..af275589f65e1924bf880d37ba480c1c6b763f49 100644 (file)
@@ -68,44 +68,6 @@ var Chess = function(fen) {
     k: [-17, -16, -15,   1,  17, 16, 15,  -1]
   };
 
-  var ATTACKS = [
-    20, 0, 0, 0, 0, 0, 0, 24,  0, 0, 0, 0, 0, 0,20, 0,
-     0,20, 0, 0, 0, 0, 0, 24,  0, 0, 0, 0, 0,20, 0, 0,
-     0, 0,20, 0, 0, 0, 0, 24,  0, 0, 0, 0,20, 0, 0, 0,
-     0, 0, 0,20, 0, 0, 0, 24,  0, 0, 0,20, 0, 0, 0, 0,
-     0, 0, 0, 0,20, 0, 0, 24,  0, 0,20, 0, 0, 0, 0, 0,
-     0, 0, 0, 0, 0,20, 2, 24,  2,20, 0, 0, 0, 0, 0, 0,
-     0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
-    24,24,24,24,24,24,56,  0, 56,24,24,24,24,24,24, 0,
-     0, 0, 0, 0, 0, 2,53, 56, 53, 2, 0, 0, 0, 0, 0, 0,
-     0, 0, 0, 0, 0,20, 2, 24,  2,20, 0, 0, 0, 0, 0, 0,
-     0, 0, 0, 0,20, 0, 0, 24,  0, 0,20, 0, 0, 0, 0, 0,
-     0, 0, 0,20, 0, 0, 0, 24,  0, 0, 0,20, 0, 0, 0, 0,
-     0, 0,20, 0, 0, 0, 0, 24,  0, 0, 0, 0,20, 0, 0, 0,
-     0,20, 0, 0, 0, 0, 0, 24,  0, 0, 0, 0, 0,20, 0, 0,
-    20, 0, 0, 0, 0, 0, 0, 24,  0, 0, 0, 0, 0, 0,20
-  ];
-
-  var RAYS = [
-     17,  0,  0,  0,  0,  0,  0, 16,  0,  0,  0,  0,  0,  0, 15, 0,
-      0, 17,  0,  0,  0,  0,  0, 16,  0,  0,  0,  0,  0, 15,  0, 0,
-      0,  0, 17,  0,  0,  0,  0, 16,  0,  0,  0,  0, 15,  0,  0, 0,
-      0,  0,  0, 17,  0,  0,  0, 16,  0,  0,  0, 15,  0,  0,  0, 0,
-      0,  0,  0,  0, 17,  0,  0, 16,  0,  0, 15,  0,  0,  0,  0, 0,
-      0,  0,  0,  0,  0, 17,  0, 16,  0, 15,  0,  0,  0,  0,  0, 0,
-      0,  0,  0,  0,  0,  0, 17, 16, 15,  0,  0,  0,  0,  0,  0, 0,
-      1,  1,  1,  1,  1,  1,  1,  0, -1, -1,  -1,-1, -1, -1, -1, 0,
-      0,  0,  0,  0,  0,  0,-15,-16,-17,  0,  0,  0,  0,  0,  0, 0,
-      0,  0,  0,  0,  0,-15,  0,-16,  0,-17,  0,  0,  0,  0,  0, 0,
-      0,  0,  0,  0,-15,  0,  0,-16,  0,  0,-17,  0,  0,  0,  0, 0,
-      0,  0,  0,-15,  0,  0,  0,-16,  0,  0,  0,-17,  0,  0,  0, 0,
-      0,  0,-15,  0,  0,  0,  0,-16,  0,  0,  0,  0,-17,  0,  0, 0,
-      0,-15,  0,  0,  0,  0,  0,-16,  0,  0,  0,  0,  0,-17,  0, 0,
-    -15,  0,  0,  0,  0,  0,  0,-16,  0,  0,  0,  0,  0,  0,-17
-  ];
-
-  var SHIFTS = { p: 0, n: 1, b: 2, r: 3, q: 4, k: 5 };
-
   var FLAGS = {
     NORMAL: 'n',
     CAPTURE: 'c',
@@ -824,40 +786,71 @@ var Chess = function(fen) {
   }
 
   function attacked(color, square) {
-    for (var i = SQUARES.a8; i <= SQUARES.h1; i++) {
-      /* did we run off the end of the board */
-      if (i & 0x88) { i += 7; continue; }
+    // Check for attacks by the king.
+    if (Math.abs(rank(kings[color]) - rank(square)) <= 1 &&
+        Math.abs(file(kings[color]) - file(square)) <= 1) {
+      return true;
+    }
 
-      /* if empty square or wrong color */
-      if (board[i] == null || board[i].color !== color) continue;
+    // Check for attacks by knights.
+    for (const offset of PIECE_OFFSETS[KNIGHT]) {
+      let knight_sq = square + offset;
+      if (knight_sq & 0x88) continue;
 
-      var piece = board[i];
-      var difference = i - square;
-      var index = difference + 119;
+      if (board[knight_sq] != null &&
+          board[knight_sq].type === KNIGHT &&
+          board[knight_sq].color === color) {
+        return true;
+      }
+    }
 
-      if (ATTACKS[index] & (1 << SHIFTS[piece.type])) {
-        if (piece.type === PAWN) {
-          if (difference > 0) {
-            if (piece.color === WHITE) return true;
-          } else {
-            if (piece.color === BLACK) return true;
+    // Check for attacks by pawns.
+    const p1sq = square - PAWN_OFFSETS[color][2];
+    const p2sq = square - PAWN_OFFSETS[color][3];
+    if (!(p1sq & 0x88) &&
+        board[p1sq] != null &&
+        board[p1sq].type === PAWN &&
+        board[p1sq].color === color) {
+      return true;
+    }
+    if (!(p2sq & 0x88) &&
+        board[p2sq] != null &&
+        board[p2sq].type === PAWN &&
+        board[p2sq].color === color) {
+      return true;
+    }
+
+    // Check for attacks by rooks (where queens count as rooks).
+    for (const offset of PIECE_OFFSETS[ROOK]) {
+      let rook_sq = square;
+      while (true) {
+        rook_sq += offset;
+        if (rook_sq & 0x88) break;
+
+        if (board[rook_sq] != null) {
+          if ((board[rook_sq].type === ROOK || board[rook_sq].type === QUEEN) &&
+              board[rook_sq].color === color) {
+            return true;
           }
-          continue;
+          break;
         }
+      }
+    }
 
-        /* if the piece is a knight or a king */
-        if (piece.type === 'n' || piece.type === 'k') return true;
-
-        var offset = RAYS[index];
-        var j = i + offset;
+    // And similarly for attacks by bishops (where queens count as bishops).
+    for (const offset of PIECE_OFFSETS[BISHOP]) {
+      let bishop_sq = square;
+      while (true) {
+        bishop_sq += offset;
+        if (bishop_sq & 0x88) break;
 
-        var blocked = false;
-        while (j !== square) {
-          if (board[j] != null) { blocked = true; break; }
-          j += offset;
+        if (board[bishop_sq] != null) {
+          if ((board[bishop_sq].type === BISHOP || board[bishop_sq].type === QUEEN) &&
+              board[bishop_sq].color === color) {
+            return true;
+          }
+          break;
         }
-
-        if (!blocked) return true;
       }
     }