Various fixes, additions...
authorBenjamin Auder <benjamin.auder@somewhere>
Tue, 25 Dec 2018 08:14:11 +0000 (09:14 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Tue, 25 Dec 2018 08:14:11 +0000 (09:14 +0100)
18 files changed:
public/images/pieces/Baroque/bm.svg [moved from public/images/pieces/Ultima/bm.svg with 100% similarity]
public/images/pieces/Baroque/wm.svg [moved from public/images/pieces/Ultima/wm.svg with 100% similarity]
public/javascripts/base_rules.js
public/javascripts/utils/printDiagram.js
public/javascripts/variants/Alice.js
public/javascripts/variants/Baroque.js [moved from public/javascripts/variants/Ultima.js with 100% similarity]
public/javascripts/variants/Berolina.js
public/javascripts/variants/Checkered.js
public/javascripts/variants/Losers.js [moved from public/javascripts/variants/Loser.js with 98% similarity]
public/javascripts/variants/Switching.js
public/javascripts/variants/Upsidedown.js
public/stylesheets/layout.sass
views/rules/Baroque/en.pug [moved from views/rules/Ultima/en.pug with 96% similarity]
views/rules/Baroque/fr.pug [moved from views/rules/Ultima/fr.pug with 96% similarity]
views/rules/Checkered/en.pug
views/rules/Checkered/fr.pug
views/rules/Losers/en.pug [moved from views/rules/Loser/en.pug with 100% similarity]
views/rules/Losers/fr.pug [moved from views/rules/Loser/fr.pug with 100% similarity]

index 0bf5114..8b8165a 100644 (file)
@@ -77,7 +77,7 @@ class ChessRules
                        if (fenParsed.enpassant != "-")
                        {
                                const ep = V.SquareToCoords(fenParsed.enpassant);
                        if (fenParsed.enpassant != "-")
                        {
                                const ep = V.SquareToCoords(fenParsed.enpassant);
-                               if (ep.y < 0 || ep.y > V.size.y || isNaN(ep.x) || ep.x < 0 || ep.x > V.size.x)
+                               if (isNaN(ep.x) || !V.OnBoard(ep))
                                        return false;
                        }
                }
                                        return false;
                        }
                }
@@ -119,8 +119,14 @@ class ChessRules
                return !!flags.match(/^[01]{4,4}$/);
        }
 
                return !!flags.match(/^[01]{4,4}$/);
        }
 
-       // 3 --> d (column letter from number)
-       static GetColumn(colnum)
+       // 3 --> d (column number to letter)
+       static CoordToColumn(colnum)
+       {
+               return String.fromCharCode(97 + colnum);
+       }
+
+       // d --> 3 (column letter to number)
+       static ColumnToCoord(colnum)
        {
                return String.fromCharCode(97 + colnum);
        }
        {
                return String.fromCharCode(97 + colnum);
        }
@@ -129,6 +135,8 @@ class ChessRules
        static SquareToCoords(sq)
        {
                return {
        static SquareToCoords(sq)
        {
                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)),
                        y: sq[0].charCodeAt() - 97
                };
                        x: V.size.x - parseInt(sq.substr(1)),
                        y: sq[0].charCodeAt() - 97
                };
@@ -137,7 +145,7 @@ class ChessRules
        // {x:0,y:4} --> e8
        static CoordsToSquare(coords)
        {
        // {x:0,y:4} --> e8
        static CoordsToSquare(coords)
        {
-               return V.GetColumn(coords.y) + (V.size.x - coords.x);
+               return V.CoordToColumn(coords.y) + (V.size.x - coords.x);
        }
 
        // Aggregates flags into one object
        }
 
        // Aggregates flags into one object
@@ -217,31 +225,32 @@ class ChessRules
 
                        // Get random squares for bishops
                        let randIndex = 2 * _.random(3);
 
                        // Get random squares for bishops
                        let randIndex = 2 * _.random(3);
-                       let bishop1Pos = positions[randIndex];
+                       const bishop1Pos = positions[randIndex];
                        // The second bishop must be on a square of different color
                        let randIndex_tmp = 2 * _.random(3) + 1;
                        // The second bishop must be on a square of different color
                        let randIndex_tmp = 2 * _.random(3) + 1;
-                       let bishop2Pos = positions[randIndex_tmp];
+                       const bishop2Pos = positions[randIndex_tmp];
                        // Remove chosen squares
                        positions.splice(Math.max(randIndex,randIndex_tmp), 1);
                        positions.splice(Math.min(randIndex,randIndex_tmp), 1);
 
                        // Get random squares for knights
                        randIndex = _.random(5);
                        // Remove chosen squares
                        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);
                        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);
                        positions.splice(randIndex, 1);
 
                        // Get random square for queen
                        randIndex = _.random(3);
-                       let queenPos = positions[randIndex];
+                       const queenPos = positions[randIndex];
                        positions.splice(randIndex, 1);
 
                        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];
+                       // Rooks and king positions are now fixed,
+                       // because of the ordering rook-king-rook
+                       const rook1Pos = positions[0];
+                       const kingPos = positions[1];
+                       const rook2Pos = positions[2];
 
                        // Finally put the shuffled pieces in the board array
                        pieces[c][rook1Pos] = 'r';
 
                        // Finally put the shuffled pieces in the board array
                        pieces[c][rook1Pos] = 'r';
@@ -528,7 +537,8 @@ class ChessRules
                }
        }
 
                }
        }
 
-       // Build a regular move from its initial and destination squares; tr: transformation
+       // Build a regular move from its initial and destination squares.
+       // tr: transformation
        getBasicMove([sx,sy], [ex,ey], tr)
        {
                let mv = new Move({
        getBasicMove([sx,sy], [ex,ey], tr)
        {
                let mv = new Move({
@@ -565,7 +575,8 @@ class ChessRules
                return mv;
        }
 
                return mv;
        }
 
-       // Generic method to find possible moves of non-pawn pieces ("sliding or jumping")
+       // Generic method to find possible moves of non-pawn pieces:
+       // "sliding or jumping"
        getSlideNJumpMoves([x,y], steps, oneStep)
        {
                const color = this.getColor(x,y);
        getSlideNJumpMoves([x,y], steps, oneStep)
        {
                const color = this.getColor(x,y);
@@ -680,7 +691,8 @@ class ChessRules
        // What are the queen moves from square x,y ?
        getPotentialQueenMoves(sq)
        {
        // What are the queen moves from square x,y ?
        getPotentialQueenMoves(sq)
        {
-               return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
+               return this.getSlideNJumpMoves(sq,
+                       V.steps[V.ROOK].concat(V.steps[V.BISHOP]));
        }
 
        // What are the king moves from square x,y ?
        }
 
        // What are the king moves from square x,y ?
@@ -710,13 +722,15 @@ class ChessRules
                                continue;
                        // If this code is reached, rooks and king are on initial position
 
                                continue;
                        // If this code is reached, rooks and king are on initial position
 
-                       // Nothing on the path of the king (and no checks; OK also if y==finalSquare)?
+                       // Nothing on the path of the king ?
+                       // (And no checks; OK also if y==finalSquare)
                        let step = finalSquares[castleSide][0] < y ? -1 : 1;
                        for (i=y; i!=finalSquares[castleSide][0]; i+=step)
                        {
                                if (this.isAttacked([x,i], [oppCol]) || (this.board[x][i] != V.EMPTY &&
                                        // NOTE: next check is enough, because of chessboard constraints
                        let step = finalSquares[castleSide][0] < y ? -1 : 1;
                        for (i=y; i!=finalSquares[castleSide][0]; i+=step)
                        {
                                if (this.isAttacked([x,i], [oppCol]) || (this.board[x][i] != V.EMPTY &&
                                        // NOTE: next check is enough, because of chessboard constraints
-                                       (this.getColor(x,i) != c || ![V.KING,V.ROOK].includes(this.getPiece(x,i)))))
+                                       (this.getColor(x,i) != c
+                                               || ![V.KING,V.ROOK].includes(this.getPiece(x,i)))))
                                {
                                        continue castlingCheck;
                                }
                                {
                                        continue castlingCheck;
                                }
@@ -782,7 +796,8 @@ class ChessRules
                });
        }
 
                });
        }
 
-       // Search for all valid moves considering current turn (for engine and game end)
+       // Search for all valid moves considering current turn
+       // (for engine and game end)
        getAllValidMoves()
        {
                const color = this.turn;
        getAllValidMoves()
        {
                const color = this.turn;
@@ -792,13 +807,14 @@ class ChessRules
                {
                        for (let j=0; j<V.size.y; j++)
                        {
                {
                        for (let j=0; j<V.size.y; j++)
                        {
-                               // Next condition "!= oppCol" = harmless hack to work with checkered variant
+                               // Next condition "!= oppCol" to work with checkered variant
                                if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol)
                                if (this.board[i][j] != V.EMPTY && this.getColor(i,j) != oppCol)
-                                       Array.prototype.push.apply(potentialMoves, this.getPotentialMovesFrom([i,j]));
+                               {
+                                       Array.prototype.push.apply(potentialMoves,
+                                               this.getPotentialMovesFrom([i,j]));
+                               }
                        }
                }
                        }
                }
-               // NOTE: prefer lazy undercheck tests, letting the king being taken?
-               // No: if happen on last 1/2 move, could lead to forbidden moves, wrong evals
                return this.filterValid(potentialMoves);
        }
 
                return this.filterValid(potentialMoves);
        }
 
@@ -828,7 +844,7 @@ class ChessRules
                return false;
        }
 
                return false;
        }
 
-       // Check if pieces of color in array 'colors' are attacking (king) on square x,y
+       // Check if pieces of color in 'colors' are attacking (king) on square x,y
        isAttacked(sq, colors)
        {
                return (this.isAttackedByPawn(sq, colors)
        isAttacked(sq, colors)
        {
                return (this.isAttackedByPawn(sq, colors)
@@ -984,7 +1000,6 @@ class ChessRules
        play(move, ingame)
        {
                // DEBUG:
        play(move, ingame)
        {
                // DEBUG:
-//             console.log("DO");
 //             if (!this.states) this.states = [];
 //             if (!ingame) this.states.push(this.getFen());
 
 //             if (!this.states) this.states = [];
 //             if (!ingame) this.states.push(this.getFen());
 
@@ -1019,7 +1034,6 @@ class ChessRules
                this.unupdateVariables(move);
 
                // DEBUG:
                this.unupdateVariables(move);
 
                // DEBUG:
-//             console.log("UNDO "+this.getNotation(move));
 //             if (this.getFen() != this.states[this.states.length-1])
 //                     debugger;
 //             this.states.pop();
 //             if (this.getFen() != this.states[this.states.length-1])
 //                     debugger;
 //             this.states.pop();
@@ -1127,12 +1141,14 @@ class ChessRules
                // Rank moves using a min-max at depth 2
                for (let i=0; i<moves1.length; i++)
                {
                // Rank moves using a min-max at depth 2
                for (let i=0; i<moves1.length; i++)
                {
-                       moves1[i].eval = (color=="w" ? -1 : 1) * maxeval; //very low, I'm checkmated
+                       // Initial self evaluation is very low: "I'm checkmated"
+                       moves1[i].eval = (color=="w" ? -1 : 1) * maxeval;
                        this.play(moves1[i]);
                        let eval2 = undefined;
                        if (this.atLeastOneMove())
                        {
                        this.play(moves1[i]);
                        let eval2 = undefined;
                        if (this.atLeastOneMove())
                        {
-                               eval2 = (color=="w" ? 1 : -1) * maxeval; //initialized with checkmate value
+                               // Initial enemy evaluation is very low too, for him
+                               eval2 = (color=="w" ? 1 : -1) * maxeval;
                                // Second half-move:
                                let moves2 = this.getAllValidMoves("computer");
                                for (let j=0; j<moves2.length; j++)
                                // Second half-move:
                                let moves2 = this.getAllValidMoves("computer");
                                for (let j=0; j<moves2.length; j++)
@@ -1147,8 +1163,11 @@ class ChessRules
                                                const score = this.checkGameEnd();
                                                evalPos = (score=="1/2" ? 0 : (score=="1-0" ? 1 : -1) * maxeval);
                                        }
                                                const score = this.checkGameEnd();
                                                evalPos = (score=="1/2" ? 0 : (score=="1-0" ? 1 : -1) * maxeval);
                                        }
-                                       if ((color == "w" && evalPos < eval2) || (color=="b" && evalPos > eval2))
+                                       if ((color == "w" && evalPos < eval2)
+                                               || (color=="b" && evalPos > eval2))
+                                       {
                                                eval2 = evalPos;
                                                eval2 = evalPos;
+                                       }
                                        this.undo(moves2[j]);
                                }
                        }
                                        this.undo(moves2[j]);
                                }
                        }
@@ -1187,7 +1206,8 @@ class ChessRules
                                        this.alphabeta(V.SEARCH_DEPTH-1, -maxeval, maxeval);
                                this.undo(moves1[i]);
                        }
                                        this.alphabeta(V.SEARCH_DEPTH-1, -maxeval, maxeval);
                                this.undo(moves1[i]);
                        }
-                       moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
+                       moves1.sort( (a,b) => {
+                               return (color=="w" ? 1 : -1) * (b.eval - a.eval); });
                }
                else
                        return currentBest;
                }
                else
                        return currentBest;
@@ -1284,12 +1304,12 @@ class ChessRules
                        if (move.vanish.length > move.appear.length)
                        {
                                // Capture
                        if (move.vanish.length > move.appear.length)
                        {
                                // Capture
-                               const startColumn = String.fromCharCode(97 + move.start.y);
+                               const startColumn = V.CoordToColumn(move.start.y);
                                notation = startColumn + "x" + finalSquare;
                        }
                        else //no capture
                                notation = finalSquare;
                                notation = startColumn + "x" + finalSquare;
                        }
                        else //no capture
                                notation = finalSquare;
-                       if (move.appear.length > 0 && piece != move.appear[0].p) //promotion
+                       if (move.appear.length > 0 && move.appear[0].p != V.PAWN) //promotion
                                notation += "=" + move.appear[0].p.toUpperCase();
                        return notation;
                }
                                notation += "=" + move.appear[0].p.toUpperCase();
                        return notation;
                }
index ef75049..61c726e 100644 (file)
@@ -15,9 +15,8 @@ function getDiagram(args)
                for (let i=0; i<squares.length; i++)
                {
                        const res = /^([a-z]+)([0-9]+)$/i.exec(squares[i]);
                for (let i=0; i<squares.length; i++)
                {
                        const res = /^([a-z]+)([0-9]+)$/i.exec(squares[i]);
-                       const x = sizeX - parseInt(res[2]); //white at bottom, so counting is reversed
-                       const y = res[1].charCodeAt(0)-97; //always one char: max 26, big enough
-                       markArray[x][y] = true;
+                       const coords = V.SquareToCoords(res);
+                       markArray[coords.x][coords.y] = true;
                }
        }
        let boardDiv = "";
                }
        }
        let boardDiv = "";
index 2be714f..2788e21 100644 (file)
@@ -324,7 +324,7 @@ class AliceRules extends ChessRules
                const captureMark = (move.vanish.length > move.appear.length ? "x" : "");
                let pawnMark = "";
                if (["p","s"].includes(piece) && captureMark.length == 1)
                const captureMark = (move.vanish.length > move.appear.length ? "x" : "");
                let pawnMark = "";
                if (["p","s"].includes(piece) && captureMark.length == 1)
-                       pawnMark = V.GetColumn(move.start.y); //start column
+                       pawnMark = V.CoordToColumn(move.start.y); //start column
 
                // Piece or pawn movement
                let notation = piece.toUpperCase() + pawnMark + captureMark + finalSquare;
 
                // Piece or pawn movement
                let notation = piece.toUpperCase() + pawnMark + captureMark + finalSquare;
index dc9e257..be72e2d 100644 (file)
@@ -10,17 +10,26 @@ class BerolinaRules extends ChessRules
                        const square = moveOrSquare;
                        if (square == "-")
                                return undefined;
                        const square = moveOrSquare;
                        if (square == "-")
                                return undefined;
-                       return V.SquareToCoords(square);
+                       // Enemy pawn initial column must be given too:
+                       let res = [];
+                       const epParts = square.split(",");
+                       res.push(V.SquareToCoords(epParts[0]));
+                       res.push(V.ColumnToCoord(epParts[1]));
+                       return res;
                }
                // Argument is a move:
                const move = moveOrSquare;
                const [sx,ex,sy] = [move.start.x,move.end.x,move.start.y];
                if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2)
                {
                }
                // Argument is a move:
                const move = moveOrSquare;
                const [sx,ex,sy] = [move.start.x,move.end.x,move.start.y];
                if (this.getPiece(sx,sy) == V.PAWN && Math.abs(sx - ex) == 2)
                {
-                       return {
-                               x: (ex + sx)/2,
-                               y: (move.end.y + sy)/2
-                       };
+                       return
+                       [
+                               {
+                                       x: (ex + sx)/2,
+                                       y: (move.end.y + sy)/2
+                               },
+                               move.end.y
+                       ];
                }
                return undefined; //default
        }
                }
                return undefined; //default
        }
@@ -47,7 +56,10 @@ class BerolinaRules extends ChessRules
                                if (this.board[x+shiftX][y+shiftY] == V.EMPTY)
                                {
                                        for (let piece of finalPieces)
                                if (this.board[x+shiftX][y+shiftY] == V.EMPTY)
                                {
                                        for (let piece of finalPieces)
-                                               moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY], {c:color,p:piece}));
+                                       {
+                                               moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
+                                                       {c:color,p:piece}));
+                                       }
                                        if (x == startRank && y+2*shiftY>=0 && y+2*shiftY<sizeY
                                                && this.board[x+2*shiftX][y+2*shiftY] == V.EMPTY)
                                        {
                                        if (x == startRank && y+2*shiftY>=0 && y+2*shiftY<sizeY
                                                && this.board[x+2*shiftX][y+2*shiftY] == V.EMPTY)
                                        {
@@ -68,14 +80,15 @@ class BerolinaRules extends ChessRules
                // En passant
                const Lep = this.epSquares.length;
                const epSquare = this.epSquares[Lep-1]; //always at least one element
                // En passant
                const Lep = this.epSquares.length;
                const epSquare = this.epSquares[Lep-1]; //always at least one element
-               if (!!epSquare && epSquare.x == x+shiftX && epSquare.y == y)
+               if (!!epSquare && epSquare[0].x == x+shiftX && epSquare[0].y == y
+                       && Math.abs(epSquare[1] - y) == 1)
                {
                        let enpassantMove = this.getBasicMove([x,y], [x+shiftX,y]);
                        enpassantMove.vanish.push({
                {
                        let enpassantMove = this.getBasicMove([x,y], [x+shiftX,y]);
                        enpassantMove.vanish.push({
-                               x: epSquare.x,
-                               y: epSquare.y,
+                               x: x,
+                               y: epSquare[1],
                                p: 'p',
                                p: 'p',
-                               c: this.getColor(epSquare.x,epSquare.y)
+                               c: this.getColor(x,epSquare[1])
                        });
                        moves.push(enpassantMove);
                }
                        });
                        moves.push(enpassantMove);
                }
@@ -90,12 +103,37 @@ class BerolinaRules extends ChessRules
                        let pawnShift = (c=="w" ? 1 : -1);
                        if (x+pawnShift>=0 && x+pawnShift<V.size.x)
                        {
                        let pawnShift = (c=="w" ? 1 : -1);
                        if (x+pawnShift>=0 && x+pawnShift<V.size.x)
                        {
-                               if (this.getPiece(x+pawnShift,y)==V.PAWN && this.getColor(x+pawnShift,y)==c)
+                               if (this.getPiece(x+pawnShift,y)==V.PAWN
+                                       && this.getColor(x+pawnShift,y)==c)
+                               {
                                        return true;
                                        return true;
+                               }
                        }
                }
                return false;
        }
                        }
                }
                return false;
        }
+
+       getNotation(move)
+       {
+               const piece = this.getPiece(move.start.x, move.start.y);
+               if (piece == V.PAWN)
+               {
+                       // Pawn move
+                       let notation = "";
+                       if (move.vanish.length == 2) //capture
+                               notation = finalSquare;
+                       else
+                       {
+                               // No capture
+                               const startColumn = V.CoordToColumn(move.start.y);
+                               notation = startColumn + "x" + finalSquare;
+                       }
+                       if (move.appear[0].p != V.PAWN) //promotion
+                               notation += "=" + move.appear[0].p.toUpperCase();
+                       return notation;
+               }
+               return super.getNotation(move); //all other pieces are orthodox
+       }
 }
 
 const VariantRules = BerolinaRules;
 }
 
 const VariantRules = BerolinaRules;
index eee21b8..4a9419a 100644 (file)
@@ -278,7 +278,7 @@ class CheckeredRules extends ChessRules
                        if (move.vanish.length > 1)
                        {
                                // Capture
                        if (move.vanish.length > 1)
                        {
                                // Capture
-                               const startColumn = V.GetColumn(move.start.y);
+                               const startColumn = V.CoordToColumn(move.start.y);
                                notation = startColumn + "x" + finalSquare +
                                        "=" + move.appear[0].p.toUpperCase();
                        }
                                notation = startColumn + "x" + finalSquare +
                                        "=" + move.appear[0].p.toUpperCase();
                        }
similarity index 98%
rename from public/javascripts/variants/Loser.js
rename to public/javascripts/variants/Losers.js
index dcc5c11..c9509c6 100644 (file)
@@ -1,4 +1,4 @@
-class LoserRules extends ChessRules
+class LosersRules extends ChessRules
 {
        static get HasFlags() { return false; }
 
 {
        static get HasFlags() { return false; }
 
@@ -184,4 +184,4 @@ class LoserRules extends ChessRules
        }
 }
 
        }
 }
 
-const VariantRules = LoserRules;
+const VariantRules = LosersRules;
index 53b14d5..67078f5 100644 (file)
@@ -130,11 +130,7 @@ class SwitchingRules extends ChessRules
                if (move.appear[0].p == V.KING && move.appear[1].p == V.ROOK)
                        return (move.end.y < move.start.y ? "0-0-0" : "0-0");
                // Switch:
                if (move.appear[0].p == V.KING && move.appear[1].p == V.ROOK)
                        return (move.end.y < move.start.y ? "0-0-0" : "0-0");
                // Switch:
-               const startSquare =
-                       String.fromCharCode(97 + move.start.y) + (V.size.x-move.start.x);
-               const finalSquare =
-                       String.fromCharCode(97 + move.end.y) + (V.size.x-move.end.x);
-               return "S" + startSquare + finalSquare;
+               return "S" + V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end);
        }
 }
 
        }
 }
 
index f966899..1a81288 100644 (file)
@@ -2,13 +2,7 @@ class UpsidedownRules extends ChessRules
 {
        static HasFlags() { return false; }
 
 {
        static HasFlags() { return false; }
 
-       // Forbid two knights moves in a row at moves 1 and 2
-       getPotentialKnightMoves(sq)
-       {
-               // But this will also affect FEN for problems, and...
-               // does it really solve the problem ?
-               //if (this.moves. ...)
-       }
+       static HasEnpassant() { return false; }
 
        getPotentialKingMoves(sq)
        {
 
        getPotentialKingMoves(sq)
        {
@@ -24,27 +18,40 @@ class UpsidedownRules extends ChessRules
                {
                        let positions = _.range(8);
 
                {
                        let positions = _.range(8);
 
-                       let randIndex = 2 * _.random(3);
-                       let bishop1Pos = positions[randIndex];
-                       let randIndex_tmp = 2 * _.random(3) + 1;
-                       let bishop2Pos = positions[randIndex_tmp];
+                       let randIndex = _.random(7);
+                       const kingPos = positions[randIndex];
+                       positions.splice(randIndex, 1);
+
+                       // At least a knight must be next to the king:
+                       let knight1Pos = undefined;
+                       if (kingPos == 0)
+                               knight1Pos = 1;
+                       else if (kingPos == V.size.y-1)
+                               knight1Pos = V.size.y-2;
+                       else
+                               knight1Pos = kingPos + (Math.random() < 0.5 ? 1 : -1);
+                       // Search for knight1Pos index in positions and remove it
+                       const knight1Index = positions.indexOf(knight1Pos);
+                       positions.splice(knight1Index, 1);
+
+                       // King+knight1 are on two consecutive squares: one light, one dark
+                       randIndex = 2 * _.random(2);
+                       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);
 
                        positions.splice(Math.max(randIndex,randIndex_tmp), 1);
                        positions.splice(Math.min(randIndex,randIndex_tmp), 1);
 
-                       randIndex = _.random(5);
-                       let knight1Pos = positions[randIndex];
-                       positions.splice(randIndex, 1);
-                       randIndex = _.random(4);
-                       let knight2Pos = positions[randIndex];
+                       randIndex = _.random(3);
+                       const knight2Pos = positions[randIndex];
                        positions.splice(randIndex, 1);
 
                        positions.splice(randIndex, 1);
 
-                       randIndex = _.random(3);
-                       let queenPos = positions[randIndex];
+                       randIndex = _.random(2);
+                       const queenPos = positions[randIndex];
                        positions.splice(randIndex, 1);
 
                        positions.splice(randIndex, 1);
 
-                       let rook1Pos = positions[0];
-                       let kingPos = positions[1];
-                       let rook2Pos = positions[2];
+                       const rook1Pos = positions[0];
+                       const rook2Pos = positions[1];
 
                        pieces[c][rook1Pos] = 'r';
                        pieces[c][knight1Pos] = 'n';
 
                        pieces[c][rook1Pos] = 'r';
                        pieces[c][knight1Pos] = 'n';
index cb8f801..e70d3fe 100644 (file)
@@ -59,6 +59,9 @@ a
 .bigfont
   font-size: 1.2em
 
 .bigfont
   font-size: 1.2em
 
+.bold
+  font-weight: bold
+
 [type="checkbox"].modal+div .card
   max-width: 767px
   max-height: 100vh
 [type="checkbox"].modal+div .card
   max-width: 767px
   max-height: 100vh
similarity index 96%
rename from views/rules/Ultima/en.pug
rename to views/rules/Baroque/en.pug
index e2876fd..fb78164 100644 (file)
@@ -3,6 +3,13 @@ p.boxed
        | They generally move like an orthodox queen,
        | but capturing rules are complex.
 
        | They generally move like an orthodox queen,
        | but capturing rules are complex.
 
+p
+       | Note: 'Baroque' is the initial name thought by the author,
+       | but 'Ultima' is also largely adopted.
+       a(href="https://www.chessvariants.com/people.dir/abbott.html")
+               | He prefers 'Baroque'
+       | , and I think me too.
+
 h3 Specifications
 
 ul
 h3 Specifications
 
 ul
similarity index 96%
rename from views/rules/Ultima/fr.pug
rename to views/rules/Baroque/fr.pug
index 006df69..b49a66b 100644 (file)
@@ -2,6 +2,13 @@ p.boxed
        | La plupart des pièces sont connues mais se déplacent différemment ;
        | en général comme une dame orthodoxe, mais les captures sont complexes.
 
        | La plupart des pièces sont connues mais se déplacent différemment ;
        | en général comme une dame orthodoxe, mais les captures sont complexes.
 
+p
+       | Note : le nom initialement choisit par l'auteur est 'Baroque',
+       | mais 'Ultima' est également largement utilisé.
+       a(href="https://www.chessvariants.com/people.dir/abbott.html")
+               | Il préfère 'Baroque'
+       | , et moi aussi je crois.
+
 h3 Caractéristiques
 
 ul
 h3 Caractéristiques
 
 ul
index ac78d65..9ce4f10 100644 (file)
@@ -11,6 +11,8 @@ figure.showPieces.center-align
        img(src="/images/tmp_checkered/no_ck.png")
        figcaption Checkered pieces, born after captures.
 
        img(src="/images/tmp_checkered/no_ck.png")
        figcaption Checkered pieces, born after captures.
 
+p Note: the initial French name for this variant is "l'Échiqueté".
+
 h3 Specifications
 
 ul
 h3 Specifications
 
 ul
@@ -65,6 +67,28 @@ ul
                Checkered pawns cannot capture en passant, because while the pawn was "passing"
                they were of the same color.
 
                Checkered pawns cannot capture en passant, because while the pawn was "passing"
                they were of the same color.
 
+p.bold.bigfont If you wanna play, you can stop reading here.
+
+h3 Stalemate or checkmate?
+
+p.
+       The following diagram seems to show a mating pattern, but the king if
+       "attacked" by a checkered pawn &ndash; which still belongs to white.
+       Therefore, it can be considered that it's not really a check because
+       white is unable to "give back the turn".
+       Without the black bishop on a7 it would be mate (without debate), because
+       the king could virtually go to g1 before being captured by the pawn-chamaleon.
+
+figure.diagram-container
+       .diagram
+               | fen:7k/b5pp/8/8/8/8/6ss/7K:
+       figcaption After 1...g2+(#?)
+
+p.
+       The interface considers that it's mate in both cases, following the idea
+       "it's checkmate if we cannot move, and the opponent on its turn could
+       take the king" (maybe after an impossible move).
+
 h2.stageDelimiter Stage 2
 
 p.warn This stage is not (and probably will never be) implemented.
 h2.stageDelimiter Stage 2
 
 p.warn This stage is not (and probably will never be) implemented.
index 6528248..ddc9a6f 100644 (file)
@@ -11,6 +11,11 @@ figure.showPieces.center-align
        img(src="/images/tmp_checkered/no_ck.png")
        figcaption Pièces échiquetées, nées suite aux captures.
 
        img(src="/images/tmp_checkered/no_ck.png")
        figcaption Pièces échiquetées, nées suite aux captures.
 
+p.
+       Note : le (vrai) nom initial de cette variante est "l'Échiqueté".
+       "Checkered" en est la traduction anglaise, et ce dernier terme me paraît
+       plus lisible pour des non francophones.
+
 h3 Caractéristiques
 
 ul
 h3 Caractéristiques
 
 ul
@@ -67,6 +72,28 @@ ul
                Les pions échiquetés ne peuvent capturer en passant, puisque pendant que
                le pion adverse "passait" ils étaient dans le même camp.
 
                Les pions échiquetés ne peuvent capturer en passant, puisque pendant que
                le pion adverse "passait" ils étaient dans le même camp.
 
+p.bold.bigfont Pour jouer, vous pouvez arrêter de lire ici.
+
+h3 Mat ou pat ?
+
+p.
+       La situation du diagramme suivant ressemble à un mat, mais le roi est
+       "attaqué" par un pion échiqueté : celui-ci appartient pour l'instant aux blancs.
+       On peut donc considérer qu'ils ne sont pas vraiment en échec
+       puisqu'incapables de "rendre le trait".
+       Sans le fou noir en a7 ce serait mat (indiscutable), car le roi pourrait
+       virtuellement aller en g1 avant de se faire capturer par le pion caméléon.
+
+figure.diagram-container
+       .diagram
+               | fen:7k/b5pp/8/8/8/8/6ss/7K:
+       figcaption Après 1...g2+(#?)
+
+p.
+       L'interface considère que c'est mat dans les deux cas, partant
+       du principe que "c'est mat si on ne peut pas bouger et que l'adversaire
+       au trait peut capturer le roi" (éventuellement après un coup interdit).
+
 h2.stageDelimiter Phase 2
 
 p.warn Cette étape n'est pas (et ne sera probablement jamais) implémentée ici.
 h2.stageDelimiter Phase 2
 
 p.warn Cette étape n'est pas (et ne sera probablement jamais) implémentée ici.
@@ -102,5 +129,5 @@ ul
                Les règles de l'Échiqueté ont été déterminées par Patrick Bernier, puis
                développées avec l'aide de Benjamin Auder.
        li.
                Les règles de l'Échiqueté ont été déterminées par Patrick Bernier, puis
                développées avec l'aide de Benjamin Auder.
        li.
-               Merci également à Olive Martin, Christian Poisson, Bevis Martin, Laurent Nouhaud
-               et Frédéric Fradet.
+               Merci également à Olive Martin, Christian Poisson, Bevis Martin,
+               Laurent Nouhaud et Frédéric Fradet.