Fix Antiking
[xogo.git] / base_rules.js
index 16f6d7a..b98c724 100644 (file)
@@ -416,6 +416,7 @@ export default class ChessRules {
     // Graphical (can use variables defined above)
     this.containerId = o.element;
     this.isDiagram = o.diagram;
+    this.marks = o.marks;
     this.graphicalInit();
   }
 
@@ -647,43 +648,58 @@ export default class ChessRules {
   }
 
   setupPieces(r) {
-    // TODO: d_pieces : only markers (for diagrams) / also in rescale()
-    if (this.g_pieces) {
-      // Refreshing: delete old pieces first
-      for (let i=0; i<this.size.x; i++) {
-        for (let j=0; j<this.size.y; j++) {
-          if (this.g_pieces[i][j]) {
-            this.g_pieces[i][j].remove();
-            this.g_pieces[i][j] = null;
-          }
-        }
-      }
-    }
-    else
-      this.g_pieces = ArrayFun.init(this.size.x, this.size.y, null);
     let chessboard =
       document.getElementById(this.containerId).querySelector(".chessboard");
     if (!r)
       r = chessboard.getBoundingClientRect();
     const pieceWidth = this.getPieceWidth(r.width);
+    const addPiece = (i, j, arrName, classes) => {
+      this[arrName][i][j] = document.createElement("piece");
+      C.AddClass_es(this[arrName][i][j], classes);
+      this[arrName][i][j].style.width = pieceWidth + "px";
+      this[arrName][i][j].style.height = pieceWidth + "px";
+      let [ip, jp] = this.getPixelPosition(i, j, r);
+      // Translate coordinates to use chessboard as reference:
+      this[arrName][i][j].style.transform =
+        `translate(${ip - r.x}px,${jp - r.y}px)`;
+      chessboard.appendChild(this[arrName][i][j]);
+    };
+    const conditionalReset = (arrName) => {
+      if (this[arrName]) {
+        // Refreshing: delete old pieces first. This isn't necessary,
+        // but simpler (this method isn't called many times)
+        for (let i=0; i<this.size.x; i++) {
+          for (let j=0; j<this.size.y; j++) {
+            if (this[arrName][i][j]) {
+              this[arrName][i][j].remove();
+              this[arrName][i][j] = null;
+            }
+          }
+        }
+      }
+      else
+        this[arrName] = ArrayFun.init(this.size.x, this.size.y, null);
+      if (arrName == "d_pieces")
+        this.marks.forEach(([i, j]) => addPiece(i, j, arrName, "mark"));
+    };
+    if (this.marks)
+      conditionalReset("d_pieces");
+    conditionalReset("g_pieces");
     for (let i=0; i < this.size.x; i++) {
       for (let j=0; j < this.size.y; j++) {
         if (this.board[i][j] != "") {
           const color = this.getColor(i, j);
           const piece = this.getPiece(i, j);
-          this.g_pieces[i][j] = document.createElement("piece");
-          C.AddClass_es(this.g_pieces[i][j],
-                        this.pieces(color, i, j)[piece]["class"]);
+          addPiece(i, j, "g_pieces", this.pieces(color, i, j)[piece]["class"]);
           this.g_pieces[i][j].classList.add(C.GetColorClass(color));
-          this.g_pieces[i][j].style.width = pieceWidth + "px";
-          this.g_pieces[i][j].style.height = pieceWidth + "px";
-          let [ip, jp] = this.getPixelPosition(i, j, r);
-          // Translate coordinates to use chessboard as reference:
-          this.g_pieces[i][j].style.transform =
-            `translate(${ip - r.x}px,${jp - r.y}px)`;
           if (this.enlightened && !this.enlightened[i][j])
             this.g_pieces[i][j].classList.add("hidden");
-          chessboard.appendChild(this.g_pieces[i][j]);
+        }
+        if (this.marks && this.d_pieces[i][j]) {
+          let classes = ["mark"];
+          if (this.board[i][j] != "")
+            classes.push("transparent");
+          addPiece(i, j, "d_pieces", classes);
         }
       }
     }
@@ -817,7 +833,7 @@ export default class ChessRules {
         }
       }
     }
-    if (this.hasReserve && !this.isDiagram)
+    if (this.hasReserve)
       this.rescaleReserve(newR);
   }
 
@@ -1495,7 +1511,7 @@ export default class ChessRules {
     if (piece == "p" && this.hasEnpassant && this.epSquare)
       Array.prototype.push.apply(moves, this.getEnpassantCaptures([x, y]));
     if (
-      piece == "k" && this.hasCastle &&
+      this.isKing(0, 0, piece) && this.hasCastle &&
       this.castleFlags[color || this.turn].some(v => v < this.size.y)
     ) {
       Array.prototype.push.apply(moves, this.getCastleMoves([x, y]));
@@ -2146,21 +2162,25 @@ export default class ChessRules {
     );
   }
 
-  underCheck([x, y], oppCol) {
+  // Argument is (very generally) an array of squares (= arrays)
+  underCheck(square_s, oppCol) {
     if (this.options["taking"] || this.options["dark"])
       return false;
-    return this.underAttack([x, y], oppCol);
+    if (!Array.isArray(square_s[0]))
+      square_s = [square_s];
+    return square_s.some(sq => this.underAttack(sq, oppCol));
   }
 
-  // Stop at first king found (TODO: multi-kings)
+  // Scan board for king(s)
   searchKingPos(color) {
+    let res = [];
     for (let i=0; i < this.size.x; i++) {
       for (let j=0; j < this.size.y; j++) {
         if (this.getColor(i, j) == color && this.isKing(i, j))
-          return [i, j];
+          res.push([i, j]);
       }
     }
-    return [-1, -1]; //king not found
+    return res;
   }
 
   // 'color' arg because some variants (e.g. Refusal) check opponent moves
@@ -2168,24 +2188,32 @@ export default class ChessRules {
     if (!color)
       color = this.turn;
     const oppCol = C.GetOppCol(color);
-    const kingPos = this.searchKingPos(color);
+    let kingPos = this.searchKingPos(color);
     let filtered = {}; //avoid re-checking similar moves (promotions...)
     return moves.filter(m => {
       const key = m.start.x + m.start.y + '.' + m.end.x + m.end.y;
       if (!filtered[key]) {
         this.playOnBoard(m);
-        let square = kingPos,
+        let newKingPP = null,
+            sqIdx = 0,
             res = true; //a priori valid
-        if (m.vanish.some(v => this.isKing(0, 0, v.p) && v.c == color)) {
+        const oldKingPP =
+          m.vanish.find(v => this.isKing(0, 0, v.p) && v.c == color);
+        if (oldKingPP) {
           // Search king in appear array:
-          const newKingIdx =
-            m.appear.findIndex(a => this.isKing(0, 0, a.p) && a.c == color);
-          if (newKingIdx >= 0)
-            square = [m.appear[newKingIdx].x, m.appear[newKingIdx].y];
+          newKingPP =
+            m.appear.find(a => this.isKing(0, 0, a.p) && a.c == color);
+          if (newKingPP) {
+            sqIdx = kingPos.findIndex(kp =>
+              kp[0] == oldKingPP.x && kp[1] == oldKingPP.y);
+            kingPos[sqIdx] = [newKingPP.x, newKingPP.y];
+          }
           else
-            res = false;
+            res = false; //king vanished
         }
-        res &&= !this.underCheck(square, oppCol);
+        res &&= !this.underCheck(kingPos, oppCol);
+        if (oldKingPP && newKingPP)
+          kingPos[sqIdx] = [oldKingPP.x, oldKingPP.y];
         this.undoOnBoard(m);
         filtered[key] = res;
         return res;
@@ -2332,7 +2360,7 @@ export default class ChessRules {
       return false;
     const color = this.turn;
     const oppKingPos = this.searchKingPos(C.GetOppCol(color));
-    if (oppKingPos[0] < 0 || this.underCheck(oppKingPos, color))
+    if (oppKingPos.length == 0 || this.underCheck(oppKingPos, color))
       return true;
     return (
       (
@@ -2381,17 +2409,20 @@ export default class ChessRules {
   getCurrentScore(move) {
     const color = this.turn;
     const oppCol = C.GetOppCol(color);
-    const kingPos = [this.searchKingPos(color), this.searchKingPos(oppCol)];
-    if (kingPos[0][0] < 0 && kingPos[1][0] < 0)
+    const kingPos = {
+      [color]: this.searchKingPos(color),
+      [oppCol]: this.searchKingPos(oppCol)
+    };
+    if (kingPos[color].length == 0 && kingPos[oppCol].length == 0)
       return "1/2";
-    if (kingPos[0][0] < 0)
+    if (kingPos[color].length == 0)
       return (color == "w" ? "0-1" : "1-0");
-    if (kingPos[1][0] < 0)
+    if (kingPos[oppCol].length == 0)
       return (color == "w" ? "1-0" : "0-1");
     if (this.atLeastOneMove(color))
       return "*";
     // No valid move: stalemate or checkmate?
-    if (!this.underCheck(kingPos[0], oppCol))
+    if (!this.underCheck(kingPos[color], oppCol))
       return "1/2";
     // OK, checkmate
     return (color == "w" ? "0-1" : "1-0");