Bugs fixing, finalization of rules in french+english
authorBenjamin Auder <benjamin.auder@somewhere>
Wed, 26 Dec 2018 21:45:23 +0000 (22:45 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Wed, 26 Dec 2018 21:45:23 +0000 (22:45 +0100)
21 files changed:
TODO [new file with mode: 0644]
public/javascripts/base_rules.js
public/javascripts/components/game.js
public/javascripts/utils/printDiagram.js
public/javascripts/variants/Baroque.js
public/javascripts/variants/Berolina.js
public/javascripts/variants/Dark.js
public/javascripts/variants/Grand.js
public/javascripts/variants/Marseille.js
public/javascripts/variants/Upsidedown.js
public/javascripts/variants/Wildebeest.js
public/javascripts/variants/Zen.js
public/stylesheets/variant.sass
views/rules/Berolina/en.pug
views/rules/Berolina/fr.pug [new file with mode: 0644]
views/rules/Dark/en.pug
views/rules/Dark/fr.pug [new file with mode: 0644]
views/rules/Marseille/en.pug
views/rules/Marseille/fr.pug [new file with mode: 0644]
views/rules/Upsidedown/en.pug
views/rules/Upsidedown/fr.pug [new file with mode: 0644]

diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..3f79e69
--- /dev/null
+++ b/TODO
@@ -0,0 +1,19 @@
+Finish rules translation in Spanish
+
+Design: final touch (gain extra space on top, using space on the right)
+Crazyhouse: my reserve vertically on the right, opponent just below board
+
+Bug MarseilleRules turn issue in computer game (last move is wrong)
+
+[Site "vchess.club"]
+[Variant "Marseille"]
+[Date "2018-12-26"]
+[White "Myself"]
+[Black "Computer"]
+[FenStart "nrqkbrnb/pppppppp/8/8/8/8/PPPPPPPP/RKQBNRBN"]
+[Fen "1rq3nb/1pk1p1p1/1Np1p2p/p7/8/2P5/PP2P1PP/RK1B2B1 w1 1000 -"]
+[Result "0-1"]
+
+1.f4 a5,h6 2.d3,c3 c6,Kc7 3.Qe3,Qe5 d6,dxe5 4.fxe5,e6 fxe6,Rxf1 5.Ng3,Nxf1 Nb6,Bg6 6.Nd2,Ne4 Bxe4,Bxd3 7.Nxd3,Nc5 Na4,Nxb6
+
+1.f2f4 a7a5,h7h6 2.d2d3,c2c3 c7c6,d8c7 3.c1e3,e3e5 d7d6,d6e5 4.f4e5,e5e6 f7e6,f8f1 5.h1g3,g3f1 a8b6,e8g6 6.f1d2,d2e4 g6e4,e4d3 7.e1d3,d3c5 c5a4,a4b6
index 891948b..9599fdb 100644 (file)
@@ -628,7 +628,8 @@ class ChessRules
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const pawnColor = this.getColor(x,y); //can be different for checkered
 
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const pawnColor = this.getColor(x,y); //can be different for checkered
 
-               if (x+shiftX >= 0 && x+shiftX < sizeX) //TODO: always true
+               // NOTE: next condition is generally true (no pawn on last rank)
+               if (x+shiftX >= 0 && x+shiftX < sizeX)
                {
                        const finalPieces = x + shiftX == lastRank
                                ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
                {
                        const finalPieces = x + shiftX == lastRank
                                ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
@@ -1001,22 +1002,27 @@ class ChessRules
                {
                        this.kingPos[c][0] = move.appear[0].x;
                        this.kingPos[c][1] = move.appear[0].y;
                {
                        this.kingPos[c][0] = move.appear[0].x;
                        this.kingPos[c][1] = move.appear[0].y;
-                       this.castleFlags[c] = [false,false];
+                       if (V.HasFlags)
+                               this.castleFlags[c] = [false,false];
                        return;
                }
                        return;
                }
-               const oppCol = this.getOppCol(c);
-               const oppFirstRank = (V.size.x-1) - firstRank;
-               if (move.start.x == firstRank //our rook moves?
-                       && this.INIT_COL_ROOK[c].includes(move.start.y))
-               {
-                       const flagIdx = (move.start.y == this.INIT_COL_ROOK[c][0] ? 0 : 1);
-                       this.castleFlags[c][flagIdx] = false;
-               }
-               else if (move.end.x == oppFirstRank //we took opponent rook?
-                       && this.INIT_COL_ROOK[oppCol].includes(move.end.y))
+               if (V.HasFlags)
                {
                {
-                       const flagIdx = (move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1);
-                       this.castleFlags[oppCol][flagIdx] = false;
+                       // Update castling flags if rooks are moved
+                       const oppCol = this.getOppCol(c);
+                       const oppFirstRank = (V.size.x-1) - firstRank;
+                       if (move.start.x == firstRank //our rook moves?
+                               && this.INIT_COL_ROOK[c].includes(move.start.y))
+                       {
+                               const flagIdx = (move.start.y == this.INIT_COL_ROOK[c][0] ? 0 : 1);
+                               this.castleFlags[c][flagIdx] = false;
+                       }
+                       else if (move.end.x == oppFirstRank //we took opponent rook?
+                               && this.INIT_COL_ROOK[oppCol].includes(move.end.y))
+                       {
+                               const flagIdx = (move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1);
+                               this.castleFlags[oppCol][flagIdx] = false;
+                       }
                }
        }
 
                }
        }
 
@@ -1244,7 +1250,7 @@ class ChessRules
                }
                else
                        return currentBest;
                }
                else
                        return currentBest;
-               //console.log(moves1.map(m => { return [this.getNotation(m), m.eval]; }));
+//             console.log(moves1.map(m => { return [this.getNotation(m), m.eval]; }));
 
                candidates = [0];
                for (let j=1; j<moves1.length && moves1[j].eval == moves1[0].eval; j++)
 
                candidates = [0];
                for (let j=1; j<moves1.length && moves1[j].eval == moves1[0].eval; j++)
index 6627252..ac03c8f 100644 (file)
@@ -1287,6 +1287,12 @@ Vue.component('my-game', {
                },
                clickComputerGame: function(e) {
                        this.getRidOfTooltip(e.currentTarget);
                },
                clickComputerGame: function(e) {
                        this.getRidOfTooltip(e.currentTarget);
+                       if (this.mode == "computer" && this.score == "*"
+                               && this.vr.turn != this.mycolor)
+                       {
+                               // Wait for computer reply first (avoid potential "ghost move" bug)
+                               return;
+                       }
                        this.newGame("computer");
                },
                clickFriendGame: function(e) {
                        this.newGame("computer");
                },
                clickFriendGame: function(e) {
@@ -1344,8 +1350,6 @@ Vue.component('my-game', {
                                                        return;
                                                }
                                        }
                                                        return;
                                                }
                                        }
-                                       else if (score == "*")
-                                               return this.continueGame("computer");
                                }
                        }
                        else if (mode == "friend")
                                }
                        }
                        else if (mode == "friend")
@@ -1416,7 +1420,7 @@ Vue.component('my-game', {
                        else if (mode == "computer")
                        {
                                this.compWorker.postMessage(["init",fen]);
                        else if (mode == "computer")
                        {
                                this.compWorker.postMessage(["init",fen]);
-                               if (this.mycolor != this.vr.turn)
+                               if (score == "*" && this.mycolor != this.vr.turn)
                                        this.playComputerMove();
                        }
                        //else: nothing special to do in friend mode
                                        this.playComputerMove();
                        }
                        //else: nothing special to do in friend mode
index b7282fe..4727430 100644 (file)
@@ -42,6 +42,32 @@ function getDiagram(args)
                                        shadowArray[i][colnum] = true;
                                continue;
                        }
                                        shadowArray[i][colnum] = true;
                                continue;
                        }
+                       if (squares[i].indexOf("-") >= 0)
+                       {
+                               // Shadow a range of squares, horizontally or vertically
+                               const firstLastSq = squares[i].split("-");
+                               const range =
+                               [
+                                       V.SquareToCoords(firstLastSq[0]),
+                                       V.SquareToCoords(firstLastSq[1])
+                               ];
+                               const step =
+                               [
+                                       range[1].x == range[0].x
+                                               ? 0
+                                               : (range[1].x - range[0].x) / Math.abs(range[1].x - range[0].x),
+                                       range[1].y == range[0].y
+                                               ? 0
+                                               : (range[1].y - range[0].y) / Math.abs(range[1].y - range[0].y)
+                               ];
+                               // Convention: range always from smaller to larger number
+                               for (let x=range[0].x, y=range[0].y; x <= range[1].x && y <= range[1].y;
+                                       x += step[0], y += step[1])
+                               {
+                                       shadowArray[x][y] = true;
+                               }
+                               continue;
+                       }
                        // Shadow just one square:
                        const coords = V.SquareToCoords(squares[i]);
                        shadowArray[coords.x][coords.y] = true;
                        // Shadow just one square:
                        const coords = V.SquareToCoords(squares[i]);
                        shadowArray[coords.x][coords.y] = true;
index 0b00c26..fe0e846 100644 (file)
@@ -1,4 +1,4 @@
-class UltimaRules extends ChessRules
+class BaroqueRules extends ChessRules
 {
        static get HasFlags() { return false; }
 
 {
        static get HasFlags() { return false; }
 
@@ -7,7 +7,7 @@ class UltimaRules extends ChessRules
        static getPpath(b)
        {
                if (b[1] == "m") //'m' for Immobilizer (I is too similar to 1)
        static getPpath(b)
        {
                if (b[1] == "m") //'m' for Immobilizer (I is too similar to 1)
-                       return "Ultima/" + b;
+                       return "Baroque/" + b;
                return b; //usual piece
        }
 
                return b; //usual piece
        }
 
@@ -169,7 +169,7 @@ class UltimaRules extends ChessRules
                });
        }
 
                });
        }
 
-       // "Pincher"
+       // "Pincer"
        getPotentialPawnMoves([x,y])
        {
                let moves = super.getPotentialRookMoves([x,y]);
        getPotentialPawnMoves([x,y])
        {
                let moves = super.getPotentialRookMoves([x,y]);
@@ -526,18 +526,6 @@ class UltimaRules extends ChessRules
                return false;
        }
 
                return false;
        }
 
-       updateVariables(move)
-       {
-               // Just update king(s) position(s)
-               const piece = move.vanish[0].p;
-               const c = move.vanish[0].c;
-               if (piece == V.KING && move.appear.length > 0)
-               {
-                       this.kingPos[c][0] = move.appear[0].x;
-                       this.kingPos[c][1] = move.appear[0].y;
-               }
-       }
-
        static get VALUES()
        {
                // TODO: totally experimental!
        static get VALUES()
        {
                // TODO: totally experimental!
@@ -627,4 +615,4 @@ class UltimaRules extends ChessRules
        }
 }
 
        }
 }
 
-const VariantRules = UltimaRules;
+const VariantRules = BaroqueRules;
index 8ea3c9c..31630ab 100644 (file)
@@ -44,37 +44,34 @@ class BerolinaRules extends ChessRules
                const firstRank = (color == 'w' ? sizeX-1 : 0);
                const startRank = (color == "w" ? sizeX-2 : 1);
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const firstRank = (color == 'w' ? sizeX-1 : 0);
                const startRank = (color == "w" ? sizeX-2 : 1);
                const lastRank = (color == "w" ? 0 : sizeX-1);
+               const finalPieces = x + shiftX == lastRank
+                       ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
+                       : [V.PAWN];
 
 
-               if (x+shiftX >= 0 && x+shiftX < sizeX) //TODO: always true
+               // One square diagonally
+               for (let shiftY of [-1,1])
                {
                {
-                       const finalPieces = x + shiftX == lastRank
-                               ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
-                               : [V.PAWN]
-                       // One square diagonally
-                       for (let shiftY of [-1,1])
+                       if (this.board[x+shiftX][y+shiftY] == V.EMPTY)
                        {
                        {
-                               if (this.board[x+shiftX][y+shiftY] == V.EMPTY)
+                               for (let piece of finalPieces)
                                {
                                {
-                                       for (let piece of finalPieces)
-                                       {
-                                               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)
-                                       {
-                                               // Two squares jump
-                                               moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]));
-                                       }
+                                       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)
+                               {
+                                       // Two squares jump
+                                       moves.push(this.getBasicMove([x,y], [x+2*shiftX,y+2*shiftY]));
                                }
                        }
                                }
                        }
-                       // Capture
-                       if (this.board[x+shiftX][y] != V.EMPTY
-                               && this.canTake([x,y], [x+shiftX,y]))
-                       {
-                               for (let piece of finalPieces)
-                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
-                       }
+               }
+               // Capture
+               if (this.board[x+shiftX][y] != V.EMPTY
+                       && this.canTake([x,y], [x+shiftX,y]))
+               {
+                       for (let piece of finalPieces)
+                               moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
                }
 
                // En passant
                }
 
                // En passant
index 96f50de..f1bd6c0 100644 (file)
@@ -16,6 +16,7 @@ class DarkRules extends ChessRules
 
        updateEnlightened()
        {
 
        updateEnlightened()
        {
+               const pawnShift = {"w":-1, "b":1};
                // Initialize with pieces positions (which are seen)
                for (let i=0; i<V.size.x; i++)
                {
                // Initialize with pieces positions (which are seen)
                for (let i=0; i<V.size.x; i++)
                {
@@ -24,7 +25,22 @@ class DarkRules extends ChessRules
                                this.enlightened["w"][i][j] = false;
                                this.enlightened["b"][i][j] = false;
                                if (this.board[i][j] != V.EMPTY)
                                this.enlightened["w"][i][j] = false;
                                this.enlightened["b"][i][j] = false;
                                if (this.board[i][j] != V.EMPTY)
-                                       this.enlightened[this.getColor(i,j)][i][j] = true;
+                               {
+                                       const color = this.getColor(i,j);
+                                       this.enlightened[color][i][j] = true;
+                                       // Add potential squares visible by "impossible pawn capture"
+                                       if (this.getPiece(i,j) == V.PAWN)
+                                       {
+                                               for (let shiftY of [-1,1])
+                                               {
+                                                       if (V.OnBoard(i+pawnShift[color],j+shiftY)
+                                                               && this.board[i+pawnShift[color]][j+shiftY] == V.EMPTY)
+                                                       {
+                                                               this.enlightened[color][i+pawnShift[color]][j+shiftY] = true;
+                                                       }
+                                               }
+                                       }
+                               }
                        }
                }
                const currentTurn = this.turn;
                        }
                }
                const currentTurn = this.turn;
@@ -75,19 +91,11 @@ class DarkRules extends ChessRules
 
        updateVariables(move)
        {
 
        updateVariables(move)
        {
-               // Update kings positions
-               const piece = move.vanish[0].p;
-               const c = move.vanish[0].c;
-               if (piece == V.KING && move.appear.length > 0)
-               {
-                       this.kingPos[c][0] = move.appear[0].x;
-                       this.kingPos[c][1] = move.appear[0].y;
-               }
+               super.updateVariables(move);
                if (move.vanish.length >= 2 && move.vanish[1].p == V.KING)
                {
                        // We took opponent king !
                if (move.vanish.length >= 2 && move.vanish[1].p == V.KING)
                {
                        // We took opponent king !
-                       const oppCol = this.getOppCol(c);
-                       this.kingPos[oppCol] = [-1,-1];
+                       this.kingPos[this.turn] = [-1,-1];
                }
 
                // Update moves for both colors:
                }
 
                // Update moves for both colors:
index 7f5fe42..16963f8 100644 (file)
@@ -13,7 +13,7 @@ class GrandRules extends ChessRules
                        return false;
                const fenParsed = V.ParseFen(fen);
                // 5) Check captures
                        return false;
                const fenParsed = V.ParseFen(fen);
                // 5) Check captures
-               if (!fenParsed.captured || !fenParsed.captured.match(/^[0-9]{10,10}$/))
+               if (!fenParsed.captured || !fenParsed.captured.match(/^[0-9]{14,14}$/))
                        return false;
                return true;
        }
                        return false;
                return true;
        }
@@ -51,11 +51,15 @@ class GrandRules extends ChessRules
 
        getCapturedFen()
        {
 
        getCapturedFen()
        {
-               let counts = _.map(_.range(10), 0);
-               for (let i=0; i<V.PIECES.length-1; i++) //-1: no king captured
+               let counts = _.map(_.range(14), 0);
+               let i = 0;
+               for (let j=0; j<V.PIECES.length; j++)
                {
                {
+                       if (V.PIECES[j] == V.KING) //no king captured
+                               continue;
                        counts[i] = this.captured["w"][V.PIECES[i]];
                        counts[i] = this.captured["w"][V.PIECES[i]];
-                       counts[5+i] = this.captured["b"][V.PIECES[i]];
+                       counts[7+i] = this.captured["b"][V.PIECES[i]];
+                       i++;
                }
                return counts.join("");
        }
                }
                return counts.join("");
        }
@@ -74,14 +78,18 @@ class GrandRules extends ChessRules
                                [V.KNIGHT]: parseInt(fenParsed.captured[2]),
                                [V.BISHOP]: parseInt(fenParsed.captured[3]),
                                [V.QUEEN]: parseInt(fenParsed.captured[4]),
                                [V.KNIGHT]: parseInt(fenParsed.captured[2]),
                                [V.BISHOP]: parseInt(fenParsed.captured[3]),
                                [V.QUEEN]: parseInt(fenParsed.captured[4]),
+                               [V.MARSHALL]: parseInt(fenParsed.captured[5]),
+                               [V.CARDINAL]: parseInt(fenParsed.captured[6]),
                        },
                        "b":
                        {
                        },
                        "b":
                        {
-                               [V.PAWN]: parseInt(fenParsed.captured[5]),
-                               [V.ROOK]: parseInt(fenParsed.captured[6]),
-                               [V.KNIGHT]: parseInt(fenParsed.captured[7]),
-                               [V.BISHOP]: parseInt(fenParsed.captured[8]),
-                               [V.QUEEN]: parseInt(fenParsed.captured[9]),
+                               [V.PAWN]: parseInt(fenParsed.captured[7]),
+                               [V.ROOK]: parseInt(fenParsed.captured[8]),
+                               [V.KNIGHT]: parseInt(fenParsed.captured[9]),
+                               [V.BISHOP]: parseInt(fenParsed.captured[10]),
+                               [V.QUEEN]: parseInt(fenParsed.captured[11]),
+                               [V.MARSHALL]: parseInt(fenParsed.captured[12]),
+                               [V.CARDINAL]: parseInt(fenParsed.captured[13]),
                        }
                };
        }
                        }
                };
        }
@@ -167,80 +175,75 @@ class GrandRules extends ChessRules
                const color = this.turn;
                let moves = [];
                const [sizeX,sizeY] = [V.size.x,V.size.y];
                const color = this.turn;
                let moves = [];
                const [sizeX,sizeY] = [V.size.x,V.size.y];
-               const shift = (color == "w" ? -1 : 1);
+               const shiftX = (color == "w" ? -1 : 1);
                const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
                const lastRanks = (color == "w" ? [0,1,2] : [sizeX-1,sizeX-2,sizeX-3]);
                const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
                const lastRanks = (color == "w" ? [0,1,2] : [sizeX-1,sizeX-2,sizeX-3]);
+               const promotionPieces =
+                       [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN,V.MARSHALL,V.CARDINAL];
 
 
-               if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRanks[0])
+               // Always x+shiftX >= 0 && x+shiftX < sizeX, because no pawns on last rank
+               let finalPieces = undefined;
+               if (lastRanks.includes(x + shiftX))
                {
                {
-                       // Normal moves
-                       if (this.board[x+shift][y] == V.EMPTY)
+                       finalPieces = promotionPieces.filter(p => this.captured[color][p] > 0);
+                       if (x + shiftX != lastRanks[0])
+                               finalPieces.push(V.PAWN);
+               }
+               else
+                       finalPieces = [V.PAWN];
+               if (this.board[x+shiftX][y] == V.EMPTY)
+               {
+                       // One square forward
+                       for (let piece of finalPieces)
+                               moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
+                       if (startRanks.includes(x))
                        {
                        {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y]));
-                               if (startRanks.includes(x) && this.board[x+2*shift][y] == V.EMPTY)
+                               if (this.board[x+2*shiftX][y] == V.EMPTY)
                                {
                                        // Two squares jump
                                {
                                        // Two squares jump
-                                       moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
-                                       if (x == startRanks[0] && this.board[x+3*shift][y] == V.EMPTY)
+                                       moves.push(this.getBasicMove([x,y], [x+2*shiftX,y]));
+                                       if (x==startRanks[0] && this.board[x+3*shiftX][y] == V.EMPTY)
                                        {
                                        {
-                                               // 3-squares jump
-                                               moves.push(this.getBasicMove([x,y], [x+3*shift,y]));
+                                               // Three squares jump
+                                               moves.push(this.getBasicMove([x,y], [x+3*shiftX,y]));
                                        }
                                }
                        }
                                        }
                                }
                        }
-                       // Captures
-                       if (y>0 && this.canTake([x,y], [x+shift,y-1])
-                               && this.board[x+shift][y-1] != V.EMPTY)
-                       {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
-                       }
-                       if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
-                               && this.board[x+shift][y+1] != V.EMPTY)
-                       {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
-                       }
                }
                }
-
-               if (lastRanks.includes(x+shift))
+               // Captures
+               for (let shiftY of [-1,1])
                {
                {
-                       // Promotion
-                       let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN,V.MARSHALL,V.CARDINAL];
-                       promotionPieces.forEach(p => {
-                               if (this.captured[color][p]==0)
-                                       return;
-                               // Normal move
-                               if (this.board[x+shift][y] == V.EMPTY)
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
-                               // Captures
-                               if (y>0 && this.canTake([x,y], [x+shift,y-1])
-                                       && this.board[x+shift][y-1] != V.EMPTY)
-                               {
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:p}));
-                               }
-                               if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
-                                       && this.board[x+shift][y+1] != V.EMPTY)
+                       if (y + shiftY >= 0 && y + shiftY < sizeY
+                               && this.board[x+shiftX][y+shiftY] != V.EMPTY
+                               && this.canTake([x,y], [x+shiftX,y+shiftY]))
+                       {
+                               for (let piece of finalPieces)
                                {
                                {
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:p}));
+                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
+                                               {c:color,p:piece}));
                                }
                                }
-                       });
+                       }
                }
 
                // En passant
                const Lep = this.epSquares.length;
                }
 
                // En passant
                const Lep = this.epSquares.length;
-               const epSquare = Lep>0 ? this.epSquares[Lep-1] : undefined;
+               const epSquare = this.epSquares[Lep-1];
                if (!!epSquare)
                {
                        for (let epsq of epSquare)
                        {
                                // TODO: some redundant checks
                if (!!epSquare)
                {
                        for (let epsq of epSquare)
                        {
                                // TODO: some redundant checks
-                               if (epsq.x == x+shift && Math.abs(epsq.y - y) == 1)
+                               if (epsq.x == x+shiftX && Math.abs(epsq.y - y) == 1)
                                {
                                {
-                                       var enpassantMove = this.getBasicMove([x,y], [x+shift,epsq.y]);
+                                       var enpassantMove = this.getBasicMove([x,y], [epsq.x,epsq.y]);
+                                       // WARNING: the captured pawn may be diagonally behind us,
+                                       // if it's a 3-squares jump and we take on 1st passing square
+                                       const px = (this.board[x][epsq.y] != V.EMPTY ? x : x - shiftX);
                                        enpassantMove.vanish.push({
                                        enpassantMove.vanish.push({
-                                               x: x,
+                                               x: px,
                                                y: epsq.y,
                                                p: 'p',
                                                y: epsq.y,
                                                p: 'p',
-                                               c: this.getColor(x,epsq.y)
+                                               c: this.getColor(px,epsq.y)
                                        });
                                        moves.push(enpassantMove);
                                }
                                        });
                                        moves.push(enpassantMove);
                                }
@@ -288,18 +291,25 @@ class GrandRules extends ChessRules
        updateVariables(move)
        {
                super.updateVariables(move);
        updateVariables(move)
        {
                super.updateVariables(move);
-               if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN)
+               if (move.vanish.length == 2 && move.appear.length == 1)
                {
                        // Capture: update this.captured
                        this.captured[move.vanish[1].c][move.vanish[1].p]++;
                }
                {
                        // Capture: update this.captured
                        this.captured[move.vanish[1].c][move.vanish[1].p]++;
                }
+               if (move.vanish[0].p != move.appear[0].p)
+               {
+                       // Promotion: update this.captured
+                       this.captured[move.vanish[0].c][move.appear[0].p]--;
+               }
        }
 
        unupdateVariables(move)
        {
                super.unupdateVariables(move);
        }
 
        unupdateVariables(move)
        {
                super.unupdateVariables(move);
-               if (move.vanish.length==2 && move.appear.length==1 && move.vanish[1].p != V.PAWN)
+               if (move.vanish.length == 2 && move.appear.length == 1)
                        this.captured[move.vanish[1].c][move.vanish[1].p]--;
                        this.captured[move.vanish[1].c][move.vanish[1].p]--;
+               if (move.vanish[0].p != move.appear[0].p)
+                       this.captured[move.vanish[0].c][move.appear[0].p]++;
        }
 
        static get VALUES()
        }
 
        static get VALUES()
@@ -374,7 +384,7 @@ class GrandRules extends ChessRules
                return pieces["b"].join("") +
                        "/pppppppppp/10/10/10/10/10/10/PPPPPPPPPP/" +
                        pieces["w"].join("").toUpperCase() +
                return pieces["b"].join("") +
                        "/pppppppppp/10/10/10/10/10/10/PPPPPPPPPP/" +
                        pieces["w"].join("").toUpperCase() +
-                       " w 1111 - 0000000000";
+                       " w 1111 - 00000000000000";
        }
 }
 
        }
 }
 
index 6e72a23..618e833 100644 (file)
@@ -73,40 +73,37 @@ class MarseilleRules extends ChessRules
                const startRank = (color == "w" ? sizeX-2 : 1);
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const pawnColor = this.getColor(x,y); //can be different for checkered
                const startRank = (color == "w" ? sizeX-2 : 1);
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const pawnColor = this.getColor(x,y); //can be different for checkered
+               const finalPieces = x + shiftX == lastRank
+                       ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
+                       : [V.PAWN];
 
 
-               if (x+shiftX >= 0 && x+shiftX < sizeX) //TODO: always true
+               // One square forward
+               if (this.board[x+shiftX][y] == V.EMPTY)
                {
                {
-                       const finalPieces = x + shiftX == lastRank
-                               ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
-                               : [V.PAWN]
-                       // One square forward
-                       if (this.board[x+shiftX][y] == V.EMPTY)
+                       for (let piece of finalPieces)
                        {
                        {
-                               for (let piece of finalPieces)
-                               {
-                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y],
-                                               {c:pawnColor,p:piece}));
-                               }
-                               // Next condition because pawns on 1st rank can generally jump
-                               if ([startRank,firstRank].includes(x)
-                                       && this.board[x+2*shiftX][y] == V.EMPTY)
-                               {
-                                       // Two squares jump
-                                       moves.push(this.getBasicMove([x,y], [x+2*shiftX,y]));
-                               }
+                               moves.push(this.getBasicMove([x,y], [x+shiftX,y],
+                                       {c:pawnColor,p:piece}));
                        }
                        }
-                       // Captures
-                       for (let shiftY of [-1,1])
+                       // Next condition because pawns on 1st rank can generally jump
+                       if ([startRank,firstRank].includes(x)
+                               && this.board[x+2*shiftX][y] == V.EMPTY)
                        {
                        {
-                               if (y + shiftY >= 0 && y + shiftY < sizeY
-                                       && this.board[x+shiftX][y+shiftY] != V.EMPTY
-                                       && this.canTake([x,y], [x+shiftX,y+shiftY]))
+                               // Two squares jump
+                               moves.push(this.getBasicMove([x,y], [x+2*shiftX,y]));
+                       }
+               }
+               // Captures
+               for (let shiftY of [-1,1])
+               {
+                       if (y + shiftY >= 0 && y + shiftY < sizeY
+                               && this.board[x+shiftX][y+shiftY] != V.EMPTY
+                               && this.canTake([x,y], [x+shiftX,y+shiftY]))
+                       {
+                               for (let piece of finalPieces)
                                {
                                {
-                                       for (let piece of finalPieces)
-                                       {
-                                               moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
-                                                       {c:pawnColor,p:piece}));
-                                       }
+                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
+                                               {c:pawnColor,p:piece}));
                                }
                        }
                }
                                }
                        }
                }
@@ -127,6 +124,7 @@ class MarseilleRules extends ChessRules
                {
                        if (this.subTurn == 1 || (epSqs.length == 2 &&
                                // Was this en-passant capture already played at subturn 1 ?
                {
                        if (this.subTurn == 1 || (epSqs.length == 2 &&
                                // Was this en-passant capture already played at subturn 1 ?
+                               // (Or maybe the opponent filled the en-passant square with a piece)
                                this.board[epSqs[0].x][epSqs[0].y] != V.EMPTY))
                        {
                                if (sq.x == x+shiftX && Math.abs(sq.y - y) == 1)
                                this.board[epSqs[0].x][epSqs[0].y] != V.EMPTY))
                        {
                                if (sq.x == x+shiftX && Math.abs(sq.y - y) == 1)
@@ -362,7 +360,6 @@ class MarseilleRules extends ChessRules
 
                return pgn;
        }
 
                return pgn;
        }
-
 }
 
 const VariantRules = MarseilleRules;
 }
 
 const VariantRules = MarseilleRules;
index 1a81288..3e389d0 100644 (file)
@@ -1,8 +1,8 @@
 class UpsidedownRules extends ChessRules
 {
 class UpsidedownRules extends ChessRules
 {
-       static HasFlags() { return false; }
+       static get HasFlags() { return false; }
 
 
-       static HasEnpassant() { return false; }
+       static get HasEnpassant() { return false; }
 
        getPotentialKingMoves(sq)
        {
 
        getPotentialKingMoves(sq)
        {
@@ -65,7 +65,7 @@ class UpsidedownRules extends ChessRules
                return pieces["w"].join("").toUpperCase() +
                        "/PPPPPPPP/8/8/8/8/pppppppp/" +
                        pieces["b"].join("") +
                return pieces["w"].join("").toUpperCase() +
                        "/PPPPPPPP/8/8/8/8/pppppppp/" +
                        pieces["b"].join("") +
-                       " w 1111 -"; //add turn + flags + enpassant
+                       " w"; //no castle, no en-passant
        }
 }
 
        }
 }
 
index 357a5eb..293b3b1 100644 (file)
@@ -110,78 +110,66 @@ class WildebeestRules extends ChessRules
                const color = this.turn;
                let moves = [];
                const [sizeX,sizeY] = [V.size.x,V.size.y];
                const color = this.turn;
                let moves = [];
                const [sizeX,sizeY] = [V.size.x,V.size.y];
-               const shift = (color == "w" ? -1 : 1);
+               const shiftX = (color == "w" ? -1 : 1);
                const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
                const lastRank = (color == "w" ? 0 : sizeX-1);
                const startRanks = (color == "w" ? [sizeX-2,sizeX-3] : [1,2]);
                const lastRank = (color == "w" ? 0 : sizeX-1);
+               const finalPieces = x + shiftX == lastRank
+                       ? [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN]
+                       : [V.PAWN];
 
 
-               if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
+               if (this.board[x+shiftX][y] == V.EMPTY)
                {
                {
-                       // Normal moves
-                       if (this.board[x+shift][y] == V.EMPTY)
+                       // One square forward
+                       for (let piece of finalPieces)
+                               moves.push(this.getBasicMove([x,y], [x+shiftX,y], {c:color,p:piece}));
+                       if (startRanks.includes(x))
                        {
                        {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y]));
-                               if (startRanks.includes(x) && this.board[x+2*shift][y] == V.EMPTY)
+                               if (this.board[x+2*shiftX][y] == V.EMPTY)
                                {
                                        // Two squares jump
                                {
                                        // Two squares jump
-                                       moves.push(this.getBasicMove([x,y], [x+2*shift,y]));
-                                       if (x == startRanks[0] && this.board[x+3*shift][y] == V.EMPTY)
+                                       moves.push(this.getBasicMove([x,y], [x+2*shiftX,y]));
+                                       if (x==startRanks[0] && this.board[x+3*shiftX][y] == V.EMPTY)
                                        {
                                        {
-                                               // 3-squares jump
-                                               moves.push(this.getBasicMove([x,y], [x+3*shift,y]));
+                                               // Three squares jump
+                                               moves.push(this.getBasicMove([x,y], [x+3*shiftX,y]));
                                        }
                                }
                        }
                                        }
                                }
                        }
-                       // Captures
-                       if (y>0 && this.canTake([x,y], [x+shift,y-1])
-                               && this.board[x+shift][y-1] != V.EMPTY)
-                       {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y-1]));
-                       }
-                       if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
-                               && this.board[x+shift][y+1] != V.EMPTY)
-                       {
-                               moves.push(this.getBasicMove([x,y], [x+shift,y+1]));
-                       }
                }
                }
-
-               if (x+shift == lastRank)
+               // Captures
+               for (let shiftY of [-1,1])
                {
                {
-                       // Promotion
-                       let promotionPieces = [V.QUEEN,V.WILDEBEEST];
-                       promotionPieces.forEach(p => {
-                               // Normal move
-                               if (this.board[x+shift][y] == V.EMPTY)
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y], {c:color,p:p}));
-                               // Captures
-                               if (y>0 && this.canTake([x,y], [x+shift,y-1])
-                                       && this.board[x+shift][y-1] != V.EMPTY)
-                               {
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y-1], {c:color,p:p}));
-                               }
-                               if (y<sizeY-1 && this.canTake([x,y], [x+shift,y+1])
-                                       && this.board[x+shift][y+1] != V.EMPTY)
+                       if (y + shiftY >= 0 && y + shiftY < sizeY
+                               && this.board[x+shiftX][y+shiftY] != V.EMPTY
+                               && this.canTake([x,y], [x+shiftX,y+shiftY]))
+                       {
+                               for (let piece of finalPieces)
                                {
                                {
-                                       moves.push(this.getBasicMove([x,y], [x+shift,y+1], {c:color,p:p}));
+                                       moves.push(this.getBasicMove([x,y], [x+shiftX,y+shiftY],
+                                               {c:color,p:piece}));
                                }
                                }
-                       });
+                       }
                }
 
                // En passant
                const Lep = this.epSquares.length;
                }
 
                // En passant
                const Lep = this.epSquares.length;
-               const epSquare = Lep>0 ? this.epSquares[Lep-1] : undefined;
+               const epSquare = this.epSquares[Lep-1];
                if (!!epSquare)
                {
                        for (let epsq of epSquare)
                        {
                                // TODO: some redundant checks
                if (!!epSquare)
                {
                        for (let epsq of epSquare)
                        {
                                // TODO: some redundant checks
-                               if (epsq.x == x+shift && Math.abs(epsq.y - y) == 1)
+                               if (epsq.x == x+shiftX && Math.abs(epsq.y - y) == 1)
                                {
                                {
-                                       var enpassantMove = this.getBasicMove([x,y], [x+shift,epsq.y]);
+                                       var enpassantMove = this.getBasicMove([x,y], [epsq.x,epsq.y]);
+                                       // WARNING: the captured pawn may be diagonally behind us,
+                                       // if it's a 3-squares jump and we take on 1st passing square
+                                       const px = (this.board[x][epsq.y] != V.EMPTY ? x : x - shiftX);
                                        enpassantMove.vanish.push({
                                        enpassantMove.vanish.push({
-                                               x: x,
+                                               x: px,
                                                y: epsq.y,
                                                p: 'p',
                                                y: epsq.y,
                                                p: 'p',
-                                               c: this.getColor(x,epsq.y)
+                                               c: this.getColor(px,epsq.y)
                                        });
                                        moves.push(enpassantMove);
                                }
                                        });
                                        moves.push(enpassantMove);
                                }
index 66cd61f..0675fbc 100644 (file)
@@ -97,7 +97,7 @@ class ZenRules extends ChessRules
                const firstRank = (color == 'w' ? sizeY-1 : 0);
                const lastRank = (color == "w" ? 0 : sizeY-1);
 
                const firstRank = (color == 'w' ? sizeY-1 : 0);
                const lastRank = (color == "w" ? 0 : sizeY-1);
 
-               if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank)
+               if (x+shift != lastRank)
                {
                        // Normal moves
                        if (this.board[x+shift][y] == V.EMPTY)
                {
                        // Normal moves
                        if (this.board[x+shift][y] == V.EMPTY)
@@ -111,9 +111,8 @@ class ZenRules extends ChessRules
                        }
                }
 
                        }
                }
 
-               if (x+shift == lastRank)
+               else //promotion
                {
                {
-                       // Promotion
                        let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
                        promotionPieces.forEach(p => {
                                // Normal move
                        let promotionPieces = [V.ROOK,V.KNIGHT,V.BISHOP,V.QUEEN];
                        promotionPieces.forEach(p => {
                                // Normal move
index c2e28a1..c5e38a8 100644 (file)
@@ -195,9 +195,8 @@ div.board11
     background-color: #e6ee9c
     &:hover
       background-color: skyblue
     background-color: #e6ee9c
     &:hover
       background-color: skyblue
-    .choice-piece
-      width: 90%
-      max-width: 100%
+    &.choice-piece
+      width: 100%
       height: auto
       display: block
 
       height: auto
       display: block
 
@@ -313,6 +312,7 @@ figure.diagram-container
     display: block
     clear: both
     padding-top: 5px
     display: block
     clear: both
     padding-top: 5px
+    font-size: 0.8em
 
 p.boxed
   background-color: #FFCC66
 
 p.boxed
   background-color: #FFCC66
index 5cdfff9..d723bc4 100644 (file)
@@ -15,21 +15,35 @@ h3 Basics
 
 p.
        Only the pawn movements change, but since there are many on the board it's a
 
 p.
        Only the pawn movements change, but since there are many on the board it's a
-       consequent change. They move diagonally instead of moving forward, and capture by
-       advancing to the next square vertically. The initial 2-squares jump is allowed,
-       as well as en-passant captures: after 1.d2b4 on the diagram,
-       1...Pxc3 e.p. is possible.
+       consequent change. They move forward diagonally instead of moving straight,
+       and capture by advancing to the next square vertically.
+
+figure.diagram-container
+       .diagram
+               | fen:8/8/5p2/5P2/P7/8/5P2/8 b5,e3,d4,g3,h4,e6,f6,g6:
+       figcaption Possible pawn moves
 
 p.
 
 p.
-       Note about notation: pawns
+       The initial 2-squares jump is allowed, as well as en-passant captures:
+       after 1.d2b4 on the diagram, 1...Pxc3 e.p. is possible.
+
+p.
+       About notation: since pawn captures are non-ambigous they writes e.g.
+       "Pxe6" ('P' is redundant but looks nicer); simple pawn moves are often
+       ambiguous, so they write for example "f2g3" (again, the starting row is
+       redundant but this also looks better).
 
 figure.diagram-container
        .diagram
 
 figure.diagram-container
        .diagram
-               | fen:r3kbnr/pp3ppp/3p4/4p3/8/8/PPPPPPPP/R1BQKBNR:
-       figcaption After the moves 1.Nc3 d6?? 2.Nd5 e5 3.Nxc7
+               | fen:rnbqkbnr/p1pppppp/8/8/1Pp2P2/5N2/PPP1PPP1/R1BQKBNR c3:
+       figcaption.
+               After 1.Nf3 b7d5 2.h2f4 d5c4 3.d2b4, en-passant capture on marked square
+               is possible
 
 
-h3 More information
+h3 Other source
 
 
-p.
-       Possible starting point Wikipedia page ?
+p
+       | See for example the 
+       a(href="https://brainking.com/en/GameRules?tp=59") Berolina chess
+       | &nbsp;page on brainking.com.
 
 
diff --git a/views/rules/Berolina/fr.pug b/views/rules/Berolina/fr.pug
new file mode 100644 (file)
index 0000000..4ee1c25
--- /dev/null
@@ -0,0 +1,51 @@
+p.boxed
+       | Les pions avancent en diagonale, et capturent en montant
+       | d'une case verticalement.
+
+h3 Caractéristiques
+
+ul
+       li Échiquier: standard.
+       li Matériel: standard.
+       li Coups non capturants: mouvements de pions différents.
+       li Coups spéciaux: standards (prise en passant adaptée.
+       li Captures: standards (excepté les pions).
+       li Fin de partie: standard.
+
+h3 Bases
+
+p.
+       Seuls les déplacements de pions changent, mais puisqu'il y en a beaucoup sur
+       l'échiquier c'est un changement important. Ils se déplacent en diagonale
+       (toujours vers l'avant) au lieu d'avancer tout droit, et capturent en
+       montant d'une case verticalement.
+
+figure.diagram-container
+       .diagram
+               | fen:8/8/5p2/5P2/P7/8/5P2/8 b5,e3,d4,g3,h4,e6,f6,g6:
+       figcaption Possibles coups de pion
+
+p.
+       Le saut initial de deux cases est permis, ainsi que la prise en passant :
+       après 3.d2b4 sur le diagrame, 3...Pxc3 e.p. est possible.
+
+p.
+       Au sujet de la notation : puisque les captures effectuées par les pions ne
+       sont pas ambigues on les note par exemple "Pxe6" ('P' est redondant mais
+       l'écriture est plus jolie ainsi) ; en revanche les simples déplacements sont
+       en général ambigus, et donc notés par exemple "f2g3" (ici encore,
+       la rangée de départ est inutile mais l'écriture paraît mieux ainsi).
+
+figure.diagram-container
+       .diagram
+               | fen:rnbqkbnr/p1pppppp/8/8/1Pp2P2/5N2/PPP1PPP1/R1BQKBNR c3:
+       figcaption.
+               Après 1.Nf3 b7d5 2.h2f4 d5c4 3.d2b4, il est possible de capturer en passant
+               sur la case marquée
+
+h3 Autre source
+
+p
+       | Visitez par exemple la page 
+       a(href="https://brainking.com/fr/GameRules?tp=59") Échecs Berolina
+       | &nbsp;page sur brainking.com.
index 7dc9aa9..f4585e3 100644 (file)
@@ -1,17 +1,14 @@
 p.boxed
        | You only see what your pieces can reach. Incomplete information game.
 
 p.boxed
        | You only see what your pieces can reach. Incomplete information game.
 
-h3 Specifications
+h3 Divergences
 
 ul
 
 ul
-       li Chessboard: standard.
-       li Material: standard.
-       li Non-capturing moves: standard.
-       li Special moves: standard.
-       li Captures: standard.
        li End of game: capture the king.
 
        li End of game: capture the king.
 
-p Incomplete information version of the orthodox game (also shuffled).
+p.
+       Incomplete information version of the orthodox game
+       (with randomized initial position).
 
 h3 Basics
 
 
 h3 Basics
 
@@ -20,11 +17,13 @@ p.
        That is to say: empty squares where your pieces can go,
        but also occupied squares where captures can be made.
        For example on the illustration next, after 1.e4 d5 white sees a black
        That is to say: empty squares where your pieces can go,
        but also occupied squares where captures can be made.
        For example on the illustration next, after 1.e4 d5 white sees a black
-       pawn on d5, the squares e5, h5, b5, a6 and all four first ranks.
+       pawn on d5, the squares e5, f5, h5, b5, a6 and all four first ranks.
+       The f5 square is visible (and empty) because of the
+       special case of pawn capture.
 
 figure.diagram-container
        .diagram
 
 figure.diagram-container
        .diagram
-               | fen:8/8/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR - w 8,7,b6,c6,d6,e6,f6,g6,h6,a5,c5,f5,g5:
+               | fen:8/8/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR - w 8,7,b6-h6,a5,c5,g5:
        figcaption Standard initial position after 1.e4 d5
 
 p.
        figcaption Standard initial position after 1.e4 d5
 
 p.
@@ -33,13 +32,13 @@ p.
        Good luck!
 
 p.
        Good luck!
 
 p.
-       Note: the bot is not cheating - it really uses only the information described earlier.
-       Moreover, it is very basic and clearly less challenging that a human.
-       But it may be a fun start :)
+       Note: the bot is not cheating - it really uses only the information
+       described earlier. Moreover, it is very basic and clearly less
+       challenging that a human. But it may be a fun start :)
 
 h3 End of the game
 
 
 h3 End of the game
 
-p Win by capturing the king (no checks, no stalemate).
+p Win by capturing the enemy king (no checks, no stalemate).
 
 h3 More information
 
 
 h3 More information
 
diff --git a/views/rules/Dark/fr.pug b/views/rules/Dark/fr.pug
new file mode 100644 (file)
index 0000000..b64224e
--- /dev/null
@@ -0,0 +1,53 @@
+p.boxed
+       | Vous ne voyez que ce que vos pièces peuvent atteindre.
+       | Jeu à information incomplète.
+
+h3 Divergences
+
+ul
+       li Fin de partie: capturer le roi.
+
+p.
+       Version à information incomplète du jeu d'échecs orthodoxe
+       (avec position initiale aléatoire).
+
+p Incomplete information version of the orthodox game (also shuffled).
+
+h3 Bases
+
+p.
+       Avant chaque coup, les joueurs ne voient que ce que leurs pièces peuvent
+       atteindre. C'est-à-dire : les cases vides où peuvent se déplacer les pièces,
+       mais aussi les cases occupées où des captures sont possibles.
+       Par exemple sur l'illustration suivante, après 1.e4 d5 les blancs voient
+       un pion noir en d5, les cases e5, f5, h5, b5, a6 et les quatre premières
+       rangées. La case f5 est visible (et vide) grâce au mode de capture
+       particulier des pions.
+
+figure.diagram-container
+       .diagram
+               | fen:8/8/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR - w 8,7,b6-h6,a5,c5,g5:
+       figcaption Position de départ habituelle après 1.e4 d5
+
+p.
+       Choisissez votre coup prudemment, en vous basant sur ce qui est devinable des
+       derniers coups adverses. En particulier, compter le matériel est
+       indispensable. Bonne chance !
+
+p.
+       Note : le robot joueur ne triche pas - il n'utilise que l'information décrite
+       plus haut. De plus il est très basique et clairement moins performant qu'un
+       humain. Ceci dit il peut être amusant de commencer contre lui :)
+
+h3 Fin de partie
+
+p Gagnez en capturant le roi adverse (pas d'échecs, pas de pat).
+
+h3 Plus d'information
+
+p
+       | J'ai découvert cette variante sur 
+       a(href="https://www.buho21.com/") Buho21
+       | , qui dispose d'une belle interface mais dont l'esprit est très différent
+       | d'ici (système de classement, abonnement VIP ou publicités, etc.).
+       | Il semblait être le seul endroit où jouer en direct à cette variante.
index 5c66e78..a390e9d 100644 (file)
@@ -18,24 +18,43 @@ p.
 h3 Basics
 
 p.
 h3 Basics
 
 p.
-       TODO: explain, every turn twice except if check on 1st turn, or
-       very first move in game.
-       En-passant: possible in any order if 2 ep squares,
-       otherwise has to be the first move.
-       OK even if opponent moved his pawn at subturn 1.
+       At the very first move of the game, white make only one move - as usual.
+       However, after that and for all the game each side must play twice at
+       every turn. There are two exceptions:
+
+ul
+       li.
+               If the first move gives check (maybe checkmate),
+               then a second move isn't played.
+       li.
+               If no move is available after the first move, then it's stalemate
+               and again, there is no second move.
 
 p.
 
 p.
-       PGN game notation: since there are two moves at each turn except on move 1,
-       a double move in the game is indicated as two comma-separated (ordered) moves,
-       as in 3.Na5,Bd3 e6,f4 (the two first are white moves,
+       About the PGN game notation: when a side plays two moves in a row,
+       they are separated (in order) by a comma in the PGN.
+       Example: 3.Na5,Bd3 e6,f4 (the two first are white moves,
        the two others are black moves).
        the two others are black moves).
-       Sometimes a move gives check, or stalemate occurs after subTurn 1 :: just one move
 
 figure.diagram-container
        .diagram
                | fen:r1bqkbnr/pppp1p1p/2n5/4p2p/4P3/5N2/PPPP1PPP/RNB1KB1R:
        figcaption After the moves 1.e4 e5,Nc6 2.Qh5,Nf3 g6,gxh5
 
 
 figure.diagram-container
        .diagram
                | fen:r1bqkbnr/pppp1p1p/2n5/4p2p/4P3/5N2/PPPP1PPP/RNB1KB1R:
        figcaption After the moves 1.e4 e5,Nc6 2.Qh5,Nf3 g6,gxh5
 
+h3 En-passant capture
+
+p.
+       Capturing en-passant is allowed under certain conditions.
+       If the opponent moved a pawn allowing such a capture (once or twice),
+       then (to take it) you must capture en-passant at the first move of your turn.
+       After that, if (and only if) there is another en-passant capture available
+       you can play it on the second move.
+
+p.
+       Note: if a pawn 2-squares jump was made and then a piece landed at the
+       en-passant square at the second move, a pawn capture on this square
+       takes only the piece.
+
 h3 More information
 
 p
 h3 More information
 
 p
diff --git a/views/rules/Marseille/fr.pug b/views/rules/Marseille/fr.pug
new file mode 100644 (file)
index 0000000..51c0fcd
--- /dev/null
@@ -0,0 +1,56 @@
+p.boxed
+       | Jouez deux coups à chaque tour.
+
+h3 Divergences
+
+p.
+       La seule différence avec le jeu orthodoxe est la règle du double-coup, mais cela
+       affecte beaucoup le jeu.
+
+h3 Bases
+
+p.
+       Au tout début de la partie les blancs ne jouent qu'un seul coup, comme
+       d'habitude. Cependant, après cela et ce pour tout le reste de la partie
+       chaque camp doit jouer deux coups à chaque tour. Avec deux exceptions :
+
+ul
+       li.
+               Si le premier coup donne échec (peut-être mat),
+               alors un second coup n'est pas joué.
+       li.
+               Si aucun coup n'est autorisé après le premier, alors c'est pat et
+               une fois encore il n'y a pas de deuxième coup.
+
+p.
+       Au sujet du format PGN de la partie : quand un camp joue deux coups d'affilée,
+       ils sont séparés (dans l'ordre) par une virgule. Exemple : 3.Na5,Bd3 e6,f4
+       (les deux premiers sont des coups blancs, les deux suivants
+       sont des coups noirs).
+
+figure.diagram-container
+       .diagram
+               | fen:r1bqkbnr/pppp1p1p/2n5/4p2p/4P3/5N2/PPPP1PPP/RNB1KB1R:
+       figcaption Après les coups 1.e4 e5,Nc6 2.Qh5,Nf3 g6,gxh5
+
+h3 Prise en passant
+
+p.
+       Capturer en passant est autorisé sous certaines conditions.
+       Si l'adversaire a déplacé un pion permettant une telle capture
+       (une fois ou deux fois), alors pour en profiter il faut prendre en passant
+       dès le premier coup de votre tour. Ensuite, si (et seulement si) il y a
+       une autre prise en passant disponible, vous pouvez l'exécuter au second coup.
+
+p.
+       Note : si un pion se déplace de deux cases puis qu'une pièce occupe la case de
+       prise en passant au second coup d'un tour, une capture sur cette case ne
+       prendra que la pièce.
+
+h3 Plus d'information
+
+p
+       | Voir par exemple la page 
+       a(href="https://www.chessvariants.com/multimove.dir/marseill.html")
+               |       Échecs Marseillais
+       | &nbsp;sur chessvariants.com.
index ff70cd3..8d4fa73 100644 (file)
@@ -1,37 +1,32 @@
 p.boxed
        | Pawns start on the 7th rank. Move a knight to promote them.
 
 p.boxed
        | Pawns start on the 7th rank. Move a knight to promote them.
 
-h3 Specifications
+h3 Divergences
 
 
-ul
-       li Chessboard: standard.
-       li Material: standard.
-       li Non-capturing moves: standard.
-       li Special moves: no castling (and no en-passant).
-       li Captures: standard.
-       li End of game: standard.
+p No castle, no en-passant capture.
 
 p.
 
 p.
-       ...(Almost) Only the initial position changes, but this is a very big change.
+       ...Only the initial position changes, but this makes a huge difference.
        In particular, castling would be rather pointless so it's disabled here.
        En-passant captures are impossible because all pawns already reached 7th rank.
 
        In particular, castling would be rather pointless so it's disabled here.
        En-passant captures are impossible because all pawns already reached 7th rank.
 
-h3 Note on initial position
+h3 About the initial position
 
 p.
 
 p.
-       Since truly random start can allow un-defendable mate in 3 with a knight,
-       the kings touch at least one knight in the initial position.
+       Since truly random start can allow a mate in 3 with a knight,
+       the kings have at least one knight neighbor in the initial position.
        This allows to move free out of potential check from the very beginning.
 
 p.
        This allows to move free out of potential check from the very beginning.
 
 p.
-       To illustrate this phenomenon, although it's defendable the standard initial
-       position allows the attack as 1.Na6 (threatening Nc5-Nd3#),
-       forcing the defense Nf3-Ne5. With a knight next to the king you have more options.
+       A less constraining condition would be to require the two knights to stand on
+       two squares of different colors, but it's not enough as proved by the
+       following diagram.
+       White can mate in 3: 1.Nc6 followed by Nb4 threatening both a2 and d3.
 
 figure.diagram-container
        .diagram
 
 figure.diagram-container
        .diagram
-               | fen:R1BQKBNR/PPPPPPP/N7/8/8/8/pppppppp/rnbqkbnr:
-       figcaption Standard initial position after 1.Na6
+               | fen:RBN1BRRQ/PPPPPPP/8/4n3/8/8/Nppppppp/brkbqr1n:
+       figcaption After 1.Nc6 Nf3 2.Nb4 Ne5 (covers d3 but not a2) 3.Nxa2#
 
 h3 Source
 
 
 h3 Source
 
diff --git a/views/rules/Upsidedown/fr.pug b/views/rules/Upsidedown/fr.pug
new file mode 100644 (file)
index 0000000..bc0a708
--- /dev/null
@@ -0,0 +1,38 @@
+p.boxed
+       | Pawns start on the 7th rank. Move a knight to promote them.
+
+h3 Specifications
+
+p Pas de roque ni prise en passant.
+
+p.
+       ...Seule la position de départ change, mais c'est une énorme différence.
+       En particulier, le roque serait sans intérêt et est donc désactivé ici.
+       Les captures en passant sont également impossible car tous les pions
+       sont déjà sur la 7eme rangée.
+
+h3 Au sujet de la position initiale
+
+p.
+       Un placement complètement aléatoire des pièces peut permettre un mat en 3
+       à l'aide d'un cavalier : c'est pourquoi le roi est toujours à côté d'au moins
+       un cavalier en début de partie. Cela permet de se dégager des échecs dès le
+       premier coup.
+
+p.
+       Pour illustrer ce phénomène, les blancs peuvent mater en 3 dans la position
+       du diagramme suivant : 1.Na6 suivi de Nc5 puis Nd3#.
+       Si le cavalier noir était en g1 une défense serait possible par Nf3-Ne5 ;
+       mais avec un cavalier voisin du roi plus d'options sont offertes.
+
+figure.diagram-container
+       .diagram
+               | fen:R1BQKBNR/PPPPPPP/N7/8/8/8/pppppppp/rnbqkbrn c5,d3:
+       figcaption Standard initial position after 1.Na6
+
+h3 Source
+
+p
+       | Voir par exemple la page 
+       a(href="https://www.chessvariants.com/diffsetup.dir/upside.html") Échecs Upside down
+       | &nbsp;sur chessvariants.com.