Some code cleaning + clarifying (TODO: work on variables names)
[vchess.git] / public / javascripts / variants / Antiking.js
index ac25c73..014a9c8 100644 (file)
-class AntikingRules
+class AntikingRules extends ChessRules
 {
-       // Path to pieces
        static getPpath(b)
        {
                return b[1]=='a' ? "Antiking/"+b : b;
        }
 
        static get ANTIKING() { return 'a'; }
+       
+       initVariables(fen)
+       {
+               super.initVariables(fen);
+               this.antikingPos = {'w':[-1,-1], 'b':[-1,-1]};
+               const position = fen.split(" ")[0].split("/");
+               for (let i=0; i<position.length; i++)
+               {
+                       let k = 0;
+                       for (let j=0; j<position[i].length; j++)
+                       {
+                               switch (position[i].charAt(j))
+                               {
+                                       case 'a':
+                                               this.antikingPos['b'] = [i,k];
+                                               break;
+                                       case 'A':
+                                               this.antikingPos['w'] = [i,k];
+                                               break;
+                                       default:
+                                               let num = parseInt(position[i].charAt(j));
+                                               if (!isNaN(num))
+                                                       k += (num-1);
+                               }
+                               k++;
+                       }
+               }
+       }
 
-       canTake(color1, color2, [x,y])
+       canTake([x1,y1], [x2,y2])
        {
-               const piece = this.getPiece(x,y);
-               return (piece != "a" && color1 != color2) || (piece == "a" && color1 == color2);
+               const piece1 = this.getPiece(x1,y1);
+               const piece2 = this.getPiece(x2,y2);
+               const color1 = this.getColor(x1,y1);
+               const color2 = this.getColor(x2,y2);
+               return piece2 != "a" &&
+                       ((piece1 != "a" && color1 != color2) || (piece1 == "a" && color1 == color2));
        }
 
        getPotentialMovesFrom([x,y])
        {
-               let c = this.getColor(x,y);
                switch (this.getPiece(x,y))
                {
                        case VariantRules.ANTIKING:
-                               return this.getPotentialAntikingMoves(x,y,c);
+                               return this.getPotentialAntikingMoves([x,y]);
                        default:
-                               return super.getPotentielMovesFrom([x,y]);
+                               return super.getPotentialMovesFrom([x,y]);
                }
        }
 
-// TODO: generaliser (à moindre coût) base_rules ? Ou spécialiser variantes ?
-
-       getPotentialAntikingMoves(x, y, c)
+       getPotentialAntikingMoves(sq)
        {
-               // TODO
+               const V = VariantRules;
+               return this.getSlideNJumpMoves(sq,
+                       V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
        }
 
-// TODO: need to re-think some logic, since antikings capture same color
+       isAttacked(sq, colors)
+       {
+               return (super.isAttacked(sq, colors) || this.isAttackedByAntiking(sq, colors));
+       }
 
-       isAttacked(sq, color)
+       isAttackedByKing([x,y], colors)
        {
-               return (this.isAttackedByPawn(sq, color)
-                       || this.isAttackedByRook(sq, color)
-                       || this.isAttackedByKnight(sq, color)
-                       || this.isAttackedByBishop(sq, color)
-                       || this.isAttackedByQueen(sq, color)
-                       || this.isAttackedByKing(sq, color)); //...
+               const V = VariantRules;
+               if (this.getPiece(x,y) == V.ANTIKING)
+                       return false; //antiking is not attacked by king
+               return this.isAttackedBySlideNJump([x,y], colors, V.KING,
+                       V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
        }
 
-       isAttackedByAntiking(sq, color)
+       isAttackedByAntiking([x,y], colors)
        {
-               // TODO
+               const V = VariantRules;
+               if ([V.KING,V.ANTIKING].includes(this.getPiece(x,y)))
+                       return false; //(anti)king is not attacked by antiking
+               return this.isAttackedBySlideNJump([x,y], colors, V.ANTIKING,
+                       V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep");
        }
 
-       underCheck(move, c)
+       underCheck(move)
        {
-               this.play(move);
-               let res = this.isAttacked(this.kingPos[c], this.getOppCol(c));
-               // TODO: also check that antiking is still in check
+               const c = this.turn;
+               const oppCol = this.getOppCol(c);
+               this.play(move)
+               let res = this.isAttacked(this.kingPos[c], [oppCol])
+                       || !this.isAttacked(this.antikingPos[c], [oppCol]);
                this.undo(move);
                return res;
        }
 
-       getCheckSquares(move, c)
+       getCheckSquares(move)
        {
+               let res = super.getCheckSquares(move);
                this.play(move);
-               // TODO
-               let res = this.isAttacked(this.kingPos[c], this.getOppCol(c))
-                       ? [ JSON.parse(JSON.stringify(this.kingPos[c])) ] //need to duplicate!
-                       : [ ];
+               const c = this.turn;
+               if (!this.isAttacked(this.antikingPos[c], [this.getOppCol(c)]))
+                       res.push(JSON.parse(JSON.stringify(this.antikingPos[c])));
                this.undo(move);
                return res;
        }
 
-       // Apply a move on board
-       static PlayOnBoard(board, move)
-       {
-               for (let psq of move.vanish)
-                       board[psq.x][psq.y] = VariantRules.EMPTY;
-               for (let psq of move.appear)
-                       board[psq.x][psq.y] = psq.c + psq.p;
-       }
-       // Un-apply the played move
-       static UndoOnBoard(board, move)
-       {
-               for (let psq of move.appear)
-                       board[psq.x][psq.y] = VariantRules.EMPTY;
-               for (let psq of move.vanish)
-                       board[psq.x][psq.y] = psq.c + psq.p;
-       }
-
-       // TODO: need antikingPos as well
        updateVariables(move)
        {
-               // ...
+               super.updateVariables(move);
+               const piece = this.getPiece(move.start.x,move.start.y);
+               const c = this.getColor(move.start.x,move.start.y);
+               // Update antiking position
+               if (piece == VariantRules.ANTIKING)
+               {
+                       this.antikingPos[c][0] = move.appear[0].x;
+                       this.antikingPos[c][1] = move.appear[0].y;
+               }
        }
 
        unupdateVariables(move)
        {
-               // TODO
+               super.unupdateVariables(move);
+               const c = this.getColor(move.start.x,move.start.y);
+               if (this.getPiece(move.start.x,move.start.y) == VariantRules.ANTIKING)
+                       this.antikingPos[c] = [move.start.x, move.start.y];
        }
 
-       checkGameEnd(color)
+       checkGameEnd()
        {
-               // TODO
-               if (!this.isAttacked(this.kingPos[color], this.getOppCol(color)))
+               const color = this.turn;
+               const oppCol = this.getOppCol(color);
+               if (!this.isAttacked(this.kingPos[color], [oppCol])
+                       && this.isAttacked(this.antikingPos[color], [oppCol]))
+               {
                        return "1/2";
+               }
                return color == "w" ? "0-1" : "1-0";
        }
 
-       // Pieces values
        static get VALUES() {
-               return {
-                       'p': 1,
-                       'r': 5,
-                       'n': 3,
-                       'b': 3,
-                       'q': 9,
-                       'k': 1000,
-                       'a': 1000
-               };
+               return Object.assign(
+                       ChessRules.VALUES,
+                       { 'a': 1000 }
+               );
        }
 
        static GenRandInitFen()
        {
-               // TODO: no need all code, just add an antiking at rondom on 3rd ranks
-               let pieces = [new Array(8), new Array(8)];
-               // Shuffle pieces on first and last rank
-               for (let c = 0; c <= 1; c++)
+               let pieces = { "w": new Array(8), "b": new Array(8) };
+               let antikingPos = { "w": -1, "b": -1 };
+               for (let c of ["w","b"])
                {
                        let positions = _.range(8);
 
-                       // Get random squares for bishops
-                       let randIndex = 2 * _.random(3);
-                       let bishop1Pos = positions[randIndex];
-                       // The second bishop must be on a square of different color
-                       let randIndex_tmp = 2 * _.random(3) + 1;
-                       let bishop2Pos = positions[randIndex_tmp];
-                       // Remove chosen squares
+                       // Get random squares for bishops, but avoid corners; because,
+                       // if an antiking blocks a cornered bishop, it can never be checkmated
+                       let randIndex = 2 * _.random(1,3);
+                       const bishop1Pos = positions[randIndex];
+                       let randIndex_tmp = 2 * _.random(2) + 1;
+                       const bishop2Pos = positions[randIndex_tmp];
                        positions.splice(Math.max(randIndex,randIndex_tmp), 1);
                        positions.splice(Math.min(randIndex,randIndex_tmp), 1);
 
-                       // Get random squares for knights
                        randIndex = _.random(5);
-                       let knight1Pos = positions[randIndex];
+                       const knight1Pos = positions[randIndex];
                        positions.splice(randIndex, 1);
                        randIndex = _.random(4);
-                       let knight2Pos = positions[randIndex];
+                       const knight2Pos = positions[randIndex];
                        positions.splice(randIndex, 1);
 
-                       // Get random square for queen
                        randIndex = _.random(3);
-                       let queenPos = positions[randIndex];
+                       const queenPos = positions[randIndex];
                        positions.splice(randIndex, 1);
 
-                       // Rooks and king positions are now fixed, because of the ordering rook-king-rook
-                       let rook1Pos = positions[0];
-                       let kingPos = positions[1];
-                       let rook2Pos = positions[2];
+                       const rook1Pos = positions[0];
+                       const kingPos = positions[1];
+                       const rook2Pos = positions[2];
+
+                       // Random squares for antikings
+                       antikingPos[c] = _.random(7);
 
-                       // Finally put the shuffled pieces in the board array
                        pieces[c][rook1Pos] = 'r';
                        pieces[c][knight1Pos] = 'n';
                        pieces[c][bishop1Pos] = 'b';
@@ -166,10 +192,14 @@ class AntikingRules
                        pieces[c][knight2Pos] = 'n';
                        pieces[c][rook2Pos] = 'r';
                }
-               let fen = pieces[0].join("") +
-                       "/pppppppp/8/8/8/8/PPPPPPPP/" +
-                       pieces[1].join("").toUpperCase() +
-                       " 1111"; //add flags
+               const ranks23_black = "pppppppp/" + (antikingPos["w"]>0?antikingPos["w"]:"")
+                       + "A" + (antikingPos["w"]<7?7-antikingPos["w"]:"");
+               const ranks23_white = (antikingPos["b"]>0?antikingPos["b"]:"") + "a"
+                       + (antikingPos["b"]<7?7-antikingPos["b"]:"") + "/PPPPPPPP";
+               let fen = pieces["b"].join("") + "/" + ranks23_black +
+                       "/8/8/" +
+                       ranks23_white + "/" + pieces["w"].join("").toUpperCase() +
+                       " 1111";
                return fen;
        }
 }