On smartphone for Teleport, Chakart, Weiqi and some others: option "confirm moves on touch screen"
 (=> comme pour corr) + option "confirm moves in corr games"?
 
-Clorange:
-Clockwork Orange Chess (Fergus Duniho,
-1999). https://www.chessvariants.com/other.dir/clockworkorange.html
-implem : pieces code, yellow/red, easy
-
 https://www.chessvariants.com/difftaking.dir/replacement.html
 
 https://www.chessvariants.com/other.dir/pocket.html
 
--- /dev/null
+../Alice/bc.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/bo.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/bs.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/bt.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/bu.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/wc.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/wo.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/ws.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/wt.svg
\ No newline at end of file
 
--- /dev/null
+../Alice/wu.svg
\ No newline at end of file
 
     // 2) Check turn
     if (!fenParsed.turn || !V.IsGoodTurn(fenParsed.turn)) return false;
     // 3) Check moves count
-    if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount) >= 0))
+    if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount, 10) >= 0))
       return false;
     // 4) Check flags
     if (V.HasFlags && (!fenParsed.flags || !V.IsGoodFlags(fenParsed.flags)))
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
     return {
       // NOTE: column is always one char => max 26 columns
       // row is counted from black side => subtraction
-      x: V.size.x - parseInt(sq.substr(1)),
+      x: V.size.x - parseInt(sq.substr(1), 10),
       y: sq[0].charCodeAt() - 97
     };
   }
       let j = 0;
       for (let indexInRow = 0; indexInRow < rows[i].length; indexInRow++) {
         const character = rows[i][indexInRow];
-        const num = parseInt(character);
+        const num = parseInt(character, 10);
         // If num is a number, just shift j:
         if (!isNaN(num)) j += num;
         // Else: something at position i,j
     const fenParsed = V.ParseFen(fen);
     this.board = V.GetBoard(fenParsed.position);
     this.turn = fenParsed.turn;
-    this.movesCount = parseInt(fenParsed.movesCount);
+    this.movesCount = parseInt(fenParsed.movesCount, 10);
     this.setOtherVariables(fen);
   }
 
             this.INIT_COL_KING["w"] = k;
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
       endgameMessage: "",
       orientation: "w",
       mode: "",
+      gameMode: "",
       score: "*", //'*' means 'unfinished'
       moves: [],
       cursor: -1, //index of the move just played
       }
       else {
         // Exit analyze mode:
-        this.mode = this.gameMode ;
+        this.mode = this.gameMode;
         this.cursor = this.gameCursor;
         this.moves = this.gameMoves;
         let fen = this.game.fenStart;
           this.stackToPlay.unshift(move);
           return;
         }
-        this.inPlay = true;
         if (this.mode == "analyze") this.toggleAnalyze();
         if (this.cursor < this.moves.length - 1)
           // To play a received move, cursor must be at the end of the game:
           this.gotoEnd();
+        this.inPlay = true;
       }
       // The board may show some possible moves: (TODO: bad solution)
       this.$refs["board"].resetCurrentAttempt();
 
     document.getElementById("adjuster")
       .addEventListener("click", processModalClick);
     // Take full width on small screens:
-    let boardSize = parseInt(localStorage.getItem("boardSize"));
+    let boardSize = parseInt(localStorage.getItem("boardSize"), 10);
     if (!boardSize) {
       boardSize =
         window.innerWidth >= 768
 
 import { extractTime } from "@/utils/timeControl";
 
 export function checkChallenge(c) {
-  const vid = parseInt(c.vid);
+  const vid = parseInt(c.vid, 10);
   if (isNaN(vid) || vid <= 0) return "Please select a variant";
 
   const tc = extractTime(c.cadence);
 
 export function checkProblem(p) {
-  const vid = parseInt(p.vid);
+  const vid = parseInt(p.vid, 10);
   if (isNaN(vid) || vid <= 0) return "Please select a variant";
 
   if (!V.IsGoodFen(p.fen)) return "Errors in FEN";
 
       hints: getItemDefaultTrue("hints"),
       highlight: getItemDefaultTrue("highlight"),
       gotonext: getItemDefaultTrue("gotonext"),
-      randomness: parseInt(localStorage.getItem("randomness"))
+      randomness: parseInt(localStorage.getItem("randomness"), 10)
     };
     if (isNaN(this.state.settings.randomness))
       // Default: random asymmetric
 
 p.boxed
-  | TODO
+  | Captured pieces can be dropped later in the game,
+  | with or without capturing abilities.
+
+p Orthodox rules apply, with the following exceptions:
+ul
+  li.
+    When a regular (resp. non-capturing) Chess piece is captured, it is
+    replaced with a non-capturing (resp. regular) counterpart of the same
+    color and given back to the player of that color,
+    who holds it in hand until he drops it on the board.
+  li.
+    A player who has a piece in hand may use his turn to place it on any
+    empty square on the board. Pawns cannot be dropped on the last rank.
+
+p Non-capturing units appear in yellow for white, and red for black.
+
+figure.diagram-container
+  .diagram
+    | fen:3nkr2/1pNSpp1b/1p1sq3/7p/rT1N1cPp/8/PPPPPP2/R1BB1KR1:
+  figcaption The black king must capture the non-capturing white pawn.
+
+h3 Source
+
+p
+  | Slightly simplified from 
+  a(href="https://www.chessvariants.com/other.dir/clockworkorange.html")
+    | Clockwork Orange Chess
+  |  on chessvariants.com.
+
+p Inventor: Fergus Duniho (1999)
 
 p.boxed
-  | TODO
+  | Las piezas capturadas se pueden soltar más adelante en el juego,
+  | con o sin capacidad de captura.
+
+p Se aplican reglas ortodoxas, con las siguientes excepciones:
+ul
+  li.
+    Cuando se captura una pieza estándar (resp. sin-captura), es
+    reemplazado por una pieza sin-captura (resp. estándar) del mismo color
+    y regresó al jugador de ese color, que lo tiene en la mano hasta que Ã©l
+    decide ponerlo en el tablero.
+  li.
+    Un jugador con una pieza en reserva puede soltarlo en cualquier casilla
+    del tablero en lugar de hacer un movimiento. Los peones no pueden alcanzar
+    la Ãºltima fila asÃ.
+
+p.
+  Las unidades que no capturan aparecen en amarillo para las blancas,
+  y en rojo para las negras.
+
+figure.diagram-container
+  .diagram
+    | fen:3nkr2/1pNSpp1b/1p1sq3/7p/rT1N1cPp/8/PPPPPP2/R1BB1KR1:
+  figcaption El rey negro debe capturar el peón blanco sin-captura.
+
+h3 Fuente
+
+p
+  | Ligeramente simplificado desde 
+  a(href="https://www.chessvariants.com/other.dir/clockworkorange.html")
+    | Clockwork Orange Chess
+  |  en chessvariants.com.
+
+p Inventor: Fergus Duniho (1999)
 
 p.boxed
-  | TODO
+  | Les pièces capturées peuvent Ãªtre parachutées plus tard dans la partie,
+  | avec ou sans capacité de capture.
+
+p Les règles orthodoxes s'appliquent, avec les exceptions suivantes :
+ul
+  li.
+    Quand une pièce standard (resp. non-capturante) est capturée, elle est
+    remplacée par une pièce non-capturante (resp. standard) de la même couleur
+    et rendue au joueur de cette couleur, qui la garde en main jusqu'à ce qu'il
+    décide de la poser sur l'échiquier.
+  li.
+    Un joueur ayant une pièce en réserve peut la parachuter n'importe où sur
+    l'échiquier au lieu d'effectuer un coup. Les pions ne peuvent atteindre
+    la dernière rangée ainsi.
+
+p.
+  Les unités non-capturantes apparaissent en jaune pour les blancs,
+  et en rouge pour les noirs.
+
+figure.diagram-container
+  .diagram
+    | fen:3nkr2/1pNSpp1b/1p1sq3/7p/rT1N1cPp/8/PPPPPP2/R1BB1KR1:
+  figcaption le roi noir doit capturer le pion blanc non-capturant.
+
+h3 Source
+
+p
+  | Légèrement simplifié depuis 
+  a(href="https://www.chessvariants.com/other.dir/clockworkorange.html")
+    | Clockwork Orange Chess
+  |  sur chessvariants.com.
+
+p Inventeur : Fergus Duniho (1999)
 
   let shadowArray = ArrayFun.init(V.size.x, V.size.y, false);
   const squares = shadow.split(",");
   for (let i = 0; i < squares.length; i++) {
-    const rownum = V.size.x - parseInt(squares[i]);
+    const rownum = V.size.x - parseInt(squares[i], 10);
     if (!isNaN(rownum)) {
       // Shadow a full row
       for (let i = 0; i < V.size.y; i++) shadowArray[rownum][i] = true;
 
 // Inverse function
 export function getSquareFromId(id) {
   const idParts = id.split("-");
-  return [parseInt(idParts[1]), parseInt(idParts[2])];
+  return [parseInt(idParts[1], 10), parseInt(idParts[2], 10)];
 }
 
   tcParts[0] += "m";
   const mainTimeArray = tcParts[0].match(/^([0-9]+)([smhd]+)$/);
   if (!mainTimeArray) return null;
-  const mainTimeValue = parseInt(mainTimeArray[1]);
+  const mainTimeValue = parseInt(mainTimeArray[1], 10);
   const mainTimeUnit = mainTimeArray[2][0];
   const mainTime = timeUnitToSeconds(mainTimeValue, mainTimeUnit);
   let increment = 0;
     tcParts[1] += "s";
     const incrementArray = tcParts[1].match(/^([0-9]+)([smhd]+)$/);
     if (!incrementArray) return null;
-    const incrementValue = parseInt(incrementArray[1]);
+    const incrementValue = parseInt(incrementArray[1], 10);
     const incrementUnit = incrementArray[2][0];
     // Increment unit cannot be larger than main unit:
     if (isLargerUnit(incrementUnit, mainTimeUnit)) return null;
 
         if (['K','k','L','l'].includes(row[i])) kings[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
               this.kingPos["w"] = [i, k];
               break;
             default: {
-              const num = parseInt(rows[i].charAt(j));
+              const num = parseInt(rows[i].charAt(j), 10);
               if (!isNaN(num)) k += num - 1;
             }
           }
 
             this.antikingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(rows[i].charAt(j));
+            const num = parseInt(rows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
             this.antikingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(rows[i].charAt(j));
+            const num = parseInt(rows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
         if (['P','p'].includes(row[i])) pawns[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
   setFlags(fenflags) {
     this.penaltyFlags = {
-      'w': parseInt(fenflags[0]),
-      'b': parseInt(fenflags[1])
+      'w': parseInt(fenflags[0], 10),
+      'b': parseInt(fenflags[1], 10)
     };
   }
 
 
         if (['K','k','Q','q'].includes(row[i])) royals[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
           if (withBall.includes(lowerRi)) ballCount++;
           sumElts++;
         } else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(position[i].charAt(j));
+            const num = parseInt(position[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
         else if (kingWhiteCodes.includes(row[i])) kings['w']++;
         if (allPiecesCodes.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
             const color = (piece.charCodeAt(0) <= 90 ? 'w' : 'b');
             this.kingPos[color] = [i, k];
           } else {
-            const num = parseInt(rows[i].charAt(j));
+            const num = parseInt(rows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
           k++;
 
         if (['K', 'k', 'L', 'l'].includes(row[i])) kings[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Initialize captured pieces' counts from FEN
+    const captured =
+      V.ParseFen(fen).captured.split("").map(x => parseInt(x, 10));
     this.captured = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.captured[0]),
-        [V.ROOK]: parseInt(fenParsed.captured[1]),
-        [V.KNIGHT]: parseInt(fenParsed.captured[2]),
-        [V.BISHOP]: parseInt(fenParsed.captured[3]),
-        [V.QUEEN]: parseInt(fenParsed.captured[4]),
-        [V.KING]: parseInt(fenParsed.captured[5])
+        [V.PAWN]: captured[0],
+        [V.ROOK]: captured[1],
+        [V.KNIGHT]: captured[2],
+        [V.BISHOP]: captured[3],
+        [V.QUEEN]: captured[4],
+        [V.KING]: captured[5]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.captured[6]),
-        [V.ROOK]: parseInt(fenParsed.captured[7]),
-        [V.KNIGHT]: parseInt(fenParsed.captured[8]),
-        [V.BISHOP]: parseInt(fenParsed.captured[9]),
-        [V.QUEEN]: parseInt(fenParsed.captured[10]),
-        [V.KING]: parseInt(fenParsed.captured[11])
+        [V.PAWN]: captured[6],
+        [V.ROOK]: captured[7],
+        [V.KNIGHT]: captured[8],
+        [V.BISHOP]: captured[9],
+        [V.QUEEN]: captured[10],
+        [V.KING]: captured[11]
       }
     };
     this.firstMove = [];
 
     }
     // Stage 1: as Checkered2. Stage 2: checkered pieces are autonomous
     const stageInfo = V.ParseFen(fen).stage;
-    this.stage = parseInt(stageInfo[0]);
+    this.stage = parseInt(stageInfo[0], 10);
     this.sideCheckered = (this.stage == 2 ? stageInfo[1] : undefined);
   }
 
 
 import { ArrayFun } from "@/utils/array";
 
 export class ClorangeRules extends ChessRules {
-  static get PawnSpecs() {
-    return Object.assign(
-      {},
-      ChessRules.PawnSpecs,
-      // TODO: pawns reaching last rank promote normally? Seems better
-      { promotions: [V.PAWN] }
-    );
-  }
-
   static IsGoodFen(fen) {
     if (!ChessRules.IsGoodFen(fen)) return false;
     const fenParsed = V.ParseFen(fen);
   }
 
   getReserveFen() {
-    let counts = new Array(10);
-    for (
-      let i = 0;
-      i < V.PIECES.length - 1;
-      i++ //-1: no king reserve
+    return (
+      Object.keys(this.reserve).map(
+        c => Object.values(this.reserve[c]).join("")).join("")
+    );
+  }
+
+  getEpSquare(moveOrSquare) {
+    if (!moveOrSquare) return undefined;
+    if (typeof moveOrSquare === "string") {
+      const square = moveOrSquare;
+      if (square == "-") return undefined;
+      return V.SquareToCoords(square);
+    }
+    const move = moveOrSquare;
+    const s = move.start,
+          e = move.end;
+    if (
+      s.y == e.y &&
+      Math.abs(s.x - e.x) == 2 &&
+      move.vanish.length > 0 && ['p', 's'].includes(move.vanish[0].p)
     ) {
-      // TODO: adapt
-      counts[i] = this.reserve["w"][V.PIECES[i]];
-      counts[5 + i] = this.reserve["b"][V.PIECES[i]];
+      return {
+        x: (s.x + e.x) / 2,
+        y: s.y
+      };
     }
-    return counts.join("");
+    return undefined;
   }
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
-    // TODO: adapt
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[2]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[3]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[4])
+        'p': reserve[0],
+        'r': reserve[1],
+        'n': reserve[2],
+        'b': reserve[3],
+        'q': reserve[4],
+        's': reserve[5],
+        'u': reserve[6],
+        'o': reserve[7],
+        'c': reserve[8],
+        't': reserve[9]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[5]),
-        [V.ROOK]: parseInt(fenParsed.reserve[6]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[7]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[8]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[9])
+        'p': reserve[10],
+        'r': reserve[11],
+        'n': reserve[12],
+        'b': reserve[13],
+        'q': reserve[14],
+        's': reserve[15],
+        'u': reserve[16],
+        'o': reserve[17],
+        'c': reserve[18],
+        't': reserve[19]
       }
     };
   }
     return this.board[i][j].charAt(1);
   }
 
+  getPpath(b) {
+    return (V.NON_VIOLENT.includes(b[1]) ? "Clorange/" : "") + b;
+  }
+
   getReservePpath(index, color) {
-    return color + V.RESERVE_PIECES[index];
+    const prefix =
+      (V.NON_VIOLENT.includes(V.RESERVE_PIECES[index]) ? "Clorange/" : "");
+    return prefix + color + V.RESERVE_PIECES[index];
   }
 
   static get NON_VIOLENT() {
-    return ['s', 'u', 'o', 'c', 't', 'l'];
+    return ['s', 'u', 'o', 'c', 't'];
+  }
+
+  static get PIECES() {
+    return ChessRules.PIECES.concat(V.NON_VIOLENT);
   }
 
   // Ordering on reserve pieces
   static get RESERVE_PIECES() {
-    return ChessRules.PIECES.concat(V.NON_VIOLENT);
+    return V.PIECES.filter(p => p != 'k');
   }
 
   getReserveMoves([x, y]) {
     const p = V.RESERVE_PIECES[y];
     if (this.reserve[color][p] == 0) return [];
     let moves = [];
-    const pawnShift = p == V.PAWN ? 1 : 0;
-    for (let i = pawnShift; i < V.size.x - pawnShift; i++) {
+    let rank1 = 0;
+    let rank2 = V.size.x - 1;
+    if (['p', 's'].includes(p)) {
+      if (color == 'w') rank1++;
+      else rank2--;
+    }
+    for (let i = rank1; i <= rank2; i++) {
       for (let j = 0; j < V.size.y; j++) {
         if (this.board[i][j] == V.EMPTY) {
           let mv = new Move({
     return moves;
   }
 
-  // TODO: adapt all below:
   getPotentialMovesFrom([x, y]) {
-    if (x >= V.size.x) {
+    if (x >= V.size.x)
       // Reserves, outside of board: x == sizeX(+1)
       return this.getReserveMoves([x, y]);
-    }
     // Standard moves
-    return super.getPotentialMovesFrom([x, y]);
+    switch (this.getPiece(x, y)) {
+      case 's': return super.getPotentialPawnMoves([x, y]);
+      case 'u': return super.getPotentialRookMoves([x, y]);
+      case 'o': return super.getPotentialKnightMoves([x, y]);
+      case 'c': return super.getPotentialBishopMoves([x, y]);
+      case 't': return super.getPotentialQueenMoves([x, y]);
+      default: return super.getPotentialMovesFrom([x, y]);
+    }
+    return []; //never reached
   }
 
-  getPotentialPawnMoves([x, y]) {
-    
-    let moves = super.getPotentialPawnMoves([x, y]);
-    // Remove pawns on 8th rank ("fallen"):
-    const color = this.turn;
-    const lastRank = (color == "w" ? 0 : V.size.x - 1);
+  getPotentialPawnMoves(sq) {
+    let moves = super.getPotentialPawnMoves(sq);
     moves.forEach(m => {
-      if (m.appear[0].x == lastRank) m.appear.pop();
+      if (m.vanish[0].p == 's' && m.appear[0].p != 's') {
+        // Promotion pieces should be non-violent as well:
+        const pIdx = ChessRules.PIECES.findIndex(p => p == m.appear[0].p)
+        m.appear[0].p = V.NON_VIOLENT[pIdx];
+      }
     });
     return moves;
   }
 
+  getSlideNJumpMoves([x, y], steps, oneStep) {
+    let moves = [];
+    const canTake = ChessRules.PIECES.includes(this.getPiece(x, y));
+    outerLoop: for (let step of steps) {
+      let i = x + step[0];
+      let j = y + step[1];
+      while (V.OnBoard(i, j) && this.board[i][j] == V.EMPTY) {
+        moves.push(this.getBasicMove([x, y], [i, j]));
+        if (oneStep) continue outerLoop;
+        i += step[0];
+        j += step[1];
+      }
+      if (V.OnBoard(i, j) && canTake && this.canTake([x, y], [i, j]))
+        moves.push(this.getBasicMove([x, y], [i, j]));
+    }
+    return moves;
+  }
+
   getAllValidMoves() {
     let moves = super.getAllPotentialMoves();
     const color = this.turn;
     return true;
   }
 
-  canTake([x1, y1], [x2, y2]) {
-    // Self-captures allowed, except for the king:
-    return this.getPiece(x2, y2) != V.KING;
-  }
-
   prePlay(move) {
     super.prePlay(move);
     // Skip castle:
     if (move.vanish.length == 2 && move.appear.length == 2) return;
     const color = this.turn;
     if (move.vanish.length == 0) this.reserve[color][move.appear[0].p]--;
-    else if (move.vanish.length == 2 && move.vanish[1].c == color)
-      // Self-capture
-      this.reserve[color][move.vanish[1].p]++;
+    else if (move.vanish.length == 2) {
+      // Capture
+      const normal = ChessRules.PIECES.includes(move.vanish[1].p);
+      const pIdx =
+        normal
+          ? ChessRules.PIECES.findIndex(p => p == move.vanish[1].p)
+          : V.NON_VIOLENT.findIndex(p => p == move.vanish[1].p);
+      const rPiece = (normal ? V.NON_VIOLENT : ChessRules.PIECES)[pIdx];
+      this.reserve[move.vanish[1].c][rPiece]++;
+    }
   }
 
   postUndo(move) {
     if (move.vanish.length == 2 && move.appear.length == 2) return;
     const color = this.turn;
     if (move.vanish.length == 0) this.reserve[color][move.appear[0].p]++;
-    else if (move.vanish.length == 2 && move.vanish[1].c == color)
-      this.reserve[color][move.vanish[1].p]--;
+    else if (move.vanish.length == 2) {
+      const normal = ChessRules.PIECES.includes(move.vanish[1].p);
+      const pIdx =
+        normal
+          ? ChessRules.PIECES.findIndex(p => p == move.vanish[1].p)
+          : V.NON_VIOLENT.findIndex(p => p == move.vanish[1].p);
+      const rPiece = (normal ? V.NON_VIOLENT : ChessRules.PIECES)[pIdx];
+      this.reserve[move.vanish[1].c][rPiece]--;
+    }
   }
 
   static get SEARCH_DEPTH() {
     return 2;
   }
 
+  static get VALUES() {
+    return Object.assign(
+      {
+        s: 0.75,
+        u: 4,
+        o: 2,
+        c: 2,
+        t: 7
+      },
+      ChessRules.VALUES
+    );
+  }
+
   evalPosition() {
     let evaluation = super.evalPosition();
     // Add reserves:
   getNotation(move) {
     const finalSquare = V.CoordsToSquare(move.end);
     if (move.vanish.length > 0) {
-      if (move.appear.length > 0) {
-        // Standard move
-        return super.getNotation(move);
-      } else {
-        // Pawn fallen: capturing or not
-        let res = "";
-        if (move.vanish.length == 2)
-          res += V.CoordToColumn(move.start.y) + "x";
-        return res + finalSquare;
-      }
+      // Standard move (maybe with non-violent piece)
+      let notation = super.getNotation(move);
+      if (move.vanish[0].p == 's' && move.appear[0].p != 's')
+        // Fix non-violent promotions:
+        notation += "=" + move.appear[0].p.toUpperCase();
+      return notation;
     }
     // Rebirth:
     const piece =
 
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
         if (!!bishop1Options[pos]) delete bishop1Options[pos];
         else if (!!bishop2Options[pos]) delete bishop2Options[pos];
       });
-      const bishop1Pos = parseInt(sample(Object.keys(bishop1Options), 1)[0]);
-      const bishop2Pos = parseInt(sample(Object.keys(bishop2Options), 1)[0]);
+      const bishop1Pos =
+        parseInt(sample(Object.keys(bishop1Options), 1)[0], 10);
+      const bishop2Pos =
+        parseInt(sample(Object.keys(bishop2Options), 1)[0], 10);
 
       // Knights' positions are now determined
       const forbidden = [
 
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[2]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[3]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[4])
+        [V.PAWN]: reserve[0],
+        [V.ROOK]: reserve[1],
+        [V.KNIGHT]: reserve[2],
+        [V.BISHOP]: reserve[3],
+        [V.QUEEN]: reserve[4]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[5]),
-        [V.ROOK]: parseInt(fenParsed.reserve[6]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[7]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[8]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[9])
+        [V.PAWN]: reserve[5],
+        [V.ROOK]: reserve[6],
+        [V.KNIGHT]: reserve[7],
+        [V.BISHOP]: reserve[8],
+        [V.QUEEN]: reserve[9]
       }
     };
     this.promoted = ArrayFun.init(V.size.x, V.size.y, false);
 
     let pieces = {};
     for (let row of rows) {
       for (let i = 0; i < row.length; i++) {
-        if (isNaN(parseInt(row[i])) && !pieces[row[i]])
+        if (isNaN(parseInt(row[i], 10)) && !pieces[row[i]])
           pieces[row[i]] = true;
       }
     }
 
           pieces[row[i] == lowerRi ? "b" : "w"]++;
           sumElts++;
         } else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
             this.INIT_COL_KING["w"] = k;
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const captured = V.ParseFen(fen).captured.split("").map(parseInt);
+    const captured =
+      V.ParseFen(fen).captured.split("").map(x => parseInt(x, 10));
     // Initialize captured pieces' counts from FEN
     this.captured = {
       w: {
 
       for (let i = 0; i < row.length; i++) {
         if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
           }
           sumElts++;
         } else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
+    const captured =
+      V.ParseFen(fen).captured.split("").map(x => parseInt(x, 10));
     // Initialize captured pieces' counts from FEN
     this.captured = {
       w: {
-        [V.ROOK]: parseInt(fenParsed.captured[0]),
-        [V.KNIGHT]: parseInt(fenParsed.captured[1]),
-        [V.BISHOP]: parseInt(fenParsed.captured[2]),
+        [V.ROOK]: captured[0],
+        [V.KNIGHT]: captured[1],
+        [V.BISHOP]: captured[2]
       },
       b: {
-        [V.ROOK]: parseInt(fenParsed.captured[3]),
-        [V.KNIGHT]: parseInt(fenParsed.captured[4]),
-        [V.BISHOP]: parseInt(fenParsed.captured[5]),
+        [V.ROOK]: captured[3],
+        [V.KNIGHT]: captured[4],
+        [V.BISHOP]: captured[5]
       }
     };
     // Stack of "last move" only for intermediate captures
 
           if (lowerRi == 'p') pawns[row[i] == lowerRi ? "b" : "w"]++;
           sumElts++;
         } else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
   }
 
   getStunnedFen() {
-    return (
-      Object.keys(this.stunned)
-      .map(square => square + this.stunned[square])
-      .join(",")
-    );
+    const squares = Object.keys(this.stunned);
+    if (squares.length == 0) return "-";
+    return squares.map(square => square + this.stunned[square]).join(",");
   }
 
   // Base GenRandInitFen() is fine because en-passant indicator will
             this.INIT_COL_KING["w"] = k;
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
         .map(s => {
           return {
             square: s.substr(0, 2),
-            state: parseInt(s[2])
+            state: parseInt(s[2], 10)
           };
         });
     }
 
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(position[i].charAt(j));
+            const num = parseInt(position[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[2]),
-        [V.GOLD_G]: parseInt(fenParsed.reserve[3]),
-        [V.SILVER_G]: parseInt(fenParsed.reserve[4])
+        [V.PAWN]: reserve[0],
+        [V.ROOK]: reserve[1],
+        [V.BISHOP]: reserve[2],
+        [V.GOLD_G]: reserve[3],
+        [V.SILVER_G]: reserve[4]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[5]),
-        [V.ROOK]: parseInt(fenParsed.reserve[6]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[7]),
-        [V.GOLD_G]: parseInt(fenParsed.reserve[8]),
-        [V.SILVER_G]: parseInt(fenParsed.reserve[9])
+        [V.PAWN]: reserve[5],
+        [V.ROOK]: reserve[6],
+        [V.BISHOP]: reserve[7],
+        [V.GOLD_G]: reserve[8],
+        [V.SILVER_G]: reserve[9]
       }
     };
   }
 
       for (let i = 0; i < row.length; i++) {
         if (V.PIECES.includes(row[i])) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
         if (['K','k'].includes(row[i])) kingsCount++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
             this.INIT_COL_KING["w"] = k;
             break;
           default: {
-            const num = parseInt(fenRows[i].charAt(j));
+            const num = parseInt(fenRows[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
       for (let i = 0; i < row.length; i++) {
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[2]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[3]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[4]),
-        [V.KING]: parseInt(fenParsed.reserve[5])
+        [V.PAWN]: reserve[0],
+        [V.ROOK]: reserve[1],
+        [V.KNIGHT]: reserve[2],
+        [V.BISHOP]: reserve[3],
+        [V.QUEEN]: reserve[4],
+        [V.KING]: reserve[5]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[6]),
-        [V.ROOK]: parseInt(fenParsed.reserve[7]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[8]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[9]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[10]),
-        [V.KING]: parseInt(fenParsed.reserve[11])
+        [V.PAWN]: reserve[6],
+        [V.ROOK]: reserve[7],
+        [V.KNIGHT]: reserve[8],
+        [V.BISHOP]: reserve[9],
+        [V.QUEEN]: reserve[10],
+        [V.KING]: reserve[11]
       }
     };
   }
 
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[2]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[3]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[4])
+        [V.PAWN]: reserve[0],
+        [V.ROOK]: reserve[1],
+        [V.KNIGHT]: reserve[2],
+        [V.BISHOP]: reserve[3],
+        [V.QUEEN]: reserve[4]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[5]),
-        [V.ROOK]: parseInt(fenParsed.reserve[6]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[7]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[8]),
-        [V.QUEEN]: parseInt(fenParsed.reserve[9])
+        [V.PAWN]: reserve[5],
+        [V.ROOK]: reserve[6],
+        [V.KNIGHT]: reserve[7],
+        [V.BISHOP]: reserve[8],
+        [V.QUEEN]: reserve[9]
       }
     };
   }
   }
 
   getPotentialMovesFrom([x, y]) {
-    if (x >= V.size.x) {
+    if (x >= V.size.x)
       // Reserves, outside of board: x == sizeX(+1)
       return this.getReserveMoves([x, y]);
-    }
     // Standard moves
     return super.getPotentialMovesFrom([x, y]);
   }
 
             this.kingPos["w"] = [i, k];
             break;
           default: {
-            const num = parseInt(position[i].charAt(j));
+            const num = parseInt(position[i].charAt(j), 10);
             if (!isNaN(num)) k += num - 1;
           }
         }
 
     const fenParsed = V.ParseFen(fen);
     this.pocket = {
       "w": {
-        h: parseInt(fenParsed.pocket[0]),
-        e: parseInt(fenParsed.pocket[1])
+        h: parseInt(fenParsed.pocket[0], 10),
+        e: parseInt(fenParsed.pocket[1], 10)
       },
       "b": {
-        h: parseInt(fenParsed.pocket[2]),
-        e: parseInt(fenParsed.pocket[3])
+        h: parseInt(fenParsed.pocket[2], 10),
+        e: parseInt(fenParsed.pocket[3], 10)
       }
     };
   }
 
 
   setOtherVariables(fen) {
     super.setOtherVariables(fen);
-    const fenParsed = V.ParseFen(fen);
     // Also init reserves (used by the interface to show landable pieces)
+    const reserve =
+      V.ParseFen(fen).reserve.split("").map(x => parseInt(x, 10));
     this.reserve = {
       w: {
-        [V.PAWN]: parseInt(fenParsed.reserve[0]),
-        [V.ROOK]: parseInt(fenParsed.reserve[1]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[2]),
-        [V.GOLD_G]: parseInt(fenParsed.reserve[3]),
-        [V.SILVER_G]: parseInt(fenParsed.reserve[4]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[5]),
-        [V.LANCE]: parseInt(fenParsed.reserve[6])
+        [V.PAWN]: reserve[0],
+        [V.ROOK]: reserve[1],
+        [V.BISHOP]: reserve[2],
+        [V.GOLD_G]: reserve[3],
+        [V.SILVER_G]: reserve[4],
+        [V.KNIGHT]: reserve[5],
+        [V.LANCE]: reserve[6]
       },
       b: {
-        [V.PAWN]: parseInt(fenParsed.reserve[7]),
-        [V.ROOK]: parseInt(fenParsed.reserve[8]),
-        [V.BISHOP]: parseInt(fenParsed.reserve[9]),
-        [V.GOLD_G]: parseInt(fenParsed.reserve[10]),
-        [V.SILVER_G]: parseInt(fenParsed.reserve[11]),
-        [V.KNIGHT]: parseInt(fenParsed.reserve[12]),
-        [V.LANCE]: parseInt(fenParsed.reserve[13])
+        [V.PAWN]: reserve[7],
+        [V.ROOK]: reserve[8],
+        [V.BISHOP]: reserve[9],
+        [V.GOLD_G]: reserve[10],
+        [V.SILVER_G]: reserve[11],
+        [V.KNIGHT]: reserve[12],
+        [V.LANCE]: reserve[13]
       }
     };
   }
 
           pieces[row[i] == lowerRi ? "b" : "w"]++;
           sumElts++;
         } else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
     this.checkFlags = { w: 0, b: 0 };
     const flags = fenflags.substr(4); //skip first 4 digits, for castle
     for (let c of ["w", "b"]) {
-      this.checkFlags[c] = parseInt(flags.charAt(c == "w" ? 0 : 1));
+      this.checkFlags[c] = parseInt(flags.charAt(c == "w" ? 0 : 1), 10);
     }
   }
 
 
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (V.PIECES.includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
         if (['K','k'].includes(row[i])) kings[row[i]]++;
         if (['x'].concat(V.PIECES).includes(row[i].toLowerCase())) sumElts++;
         else {
-          const num = parseInt(row[i]);
+          const num = parseInt(row[i], 10);
           if (isNaN(num)) return false;
           sumElts += num;
         }
 
     //  - from server (one correspondance game I play[ed] or not)
     //  - from remote peer (one live game I don't play, finished or not)
     fetchGame: function(callback) {
-      if (Number.isInteger(this.gameRef) || !isNaN(parseInt(this.gameRef))) {
+      if (
+        Number.isInteger(this.gameRef) ||
+        !isNaN(parseInt(this.gameRef, 10))
+      ) {
         // corr games identifiers are integers
         ajax(
           "/games",
 
       infoMessage: "",
       newchallenge: {
         fen: "",
-        vid: parseInt(localStorage.getItem("vid")) || 0,
+        vid: parseInt(localStorage.getItem("vid"), 10) || 0,
         to: "", //name of challenged player (if any)
         cadence: localStorage.getItem("cadence") || "",
         randomness:
           // Warning: randomness can be 0, then !!randomness is false
-          (parseInt(localStorage.getItem("challRandomness"))+1 || 3) - 1,
+          (parseInt(localStorage.getItem("challRandomness"),10)+1 || 3) - 1,
         // VariantRules object, stored to not interfere with
         // diagrams of targetted challenges:
         V: null,
 
         case "notifyturn":
         case "notifyscore": {
           const info = data.data;
-          const type = (!!parseInt(info.gid) ? "corr" : "live");
+          const type = (!!parseInt(info.gid, 10) ? "corr" : "live");
           let game = gamesArrays[type].find(g => g.id == info.gid);
           // "notifything" --> "thing":
           const thing = data.code.substr(6);
 
   ('Doublearmy', '64 pieces on the board'),
   ('Doublemove1', 'Double moves (v1)'),
   ('Doublemove2', 'Double moves (v2)'),
-  ('Doubleorda', 'Mongolian Horde (v2)'),
   ('Dynamo', 'Push and pull'),
   ('Eightpieces', 'Each piece is unique'),
   ('Enpassant', 'Capture en passant'),
   ('Monster', 'White move twice'),
   ('Omega', 'A wizard in the corner'),
   ('Orda', 'Mongolian Horde (v1)'),
+  ('Ordamirror', 'Mongolian Horde (v2)'),
   ('Pacifist1', 'Convert & support (v1)'),
   ('Pacifist2', 'Convert & support (v2)'),
   ('Parachute', 'Landing on the board'),