From 2526c041baf44968b0aa7b98af56730e88f6a595 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Wed, 21 Nov 2018 13:05:33 +0100 Subject: [PATCH] Remove some redundant code [Checkered/Magnetic still buggish] --- TODO | 1 + public/javascripts/base_rules.js | 63 +++--- public/javascripts/components/game.js | 4 +- public/javascripts/variants/Atomic.js | 8 +- public/javascripts/variants/Checkered.js | 258 ++++------------------- public/javascripts/variants/Magnetic.js | 188 +++-------------- 6 files changed, 117 insertions(+), 405 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 00000000..5ad48808 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +For animation, moves should contains "moving" and "fading" maybe... diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 7c52fc1c..f07aaff2 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -52,7 +52,7 @@ class ChessRules this.moves = moves; // Use fen string to initialize variables, flags and board this.board = VariantRules.GetBoard(fen); - this.flags = VariantRules.GetFlags(fen); + this.setFlags(fen); this.initVariables(fen); } @@ -125,14 +125,13 @@ class ChessRules } // Overridable: flags can change a lot - static GetFlags(fen) + setFlags(fen) { // white a-castle, h-castle, black a-castle, h-castle - let flags = {'w': new Array(2), 'b': new Array(2)}; - let fenFlags = fen.split(" ")[1]; //flags right after position + this.castleFlags = {'w': new Array(2), 'b': new Array(2)}; + let flags = fen.split(" ")[1]; //flags right after position for (let i=0; i<4; i++) - flags[i < 2 ? 'w' : 'b'][i%2] = (fenFlags.charAt(i) == '1'); - return flags; + this.castleFlags[i < 2 ? 'w' : 'b'][i%2] = (flags.charAt(i) == '1'); } /////////////////// @@ -176,6 +175,17 @@ class ChessRules }; } + // Aggregates flags into one object + get flags() { + return this.castleFlags; + } + + // Reverse operation + parseFlags(flags) + { + this.castleFlags = flags; + } + // En-passant square, if any getEpSquare(move) { @@ -222,7 +232,7 @@ class ChessRules // Build a regular move from its initial and destination squares; tr: transformation getBasicMove([sx,sy], [ex,ey], tr) { - var mv = new Move({ + let mv = new Move({ appear: [ new PiPo({ x: ex, @@ -260,7 +270,7 @@ class ChessRules getSlideNJumpMoves([x,y], steps, oneStep) { const color = this.getColor(x,y); - var moves = []; + let moves = []; const [sizeX,sizeY] = VariantRules.size; outerLoop: for (let step of steps) @@ -284,13 +294,14 @@ class ChessRules // What are the pawn moves from square x,y considering color "color" ? getPotentialPawnMoves([x,y]) { - const color = this.getColor(x,y); - var moves = []; - var V = VariantRules; + const color = this.turn; + let moves = []; + const V = VariantRules; const [sizeX,sizeY] = VariantRules.size; - let shift = (color == "w" ? -1 : 1); - let startRank = (color == "w" ? sizeY-2 : 1); - let lastRank = (color == "w" ? 0 : sizeY-1); + const shift = (color == "w" ? -1 : 1); + const firstRank = (color == 'w' ? sizeY-1 : 0); + const startRank = (color == "w" ? sizeY-2 : 1); + const lastRank = (color == "w" ? 0 : sizeY-1); if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank) { @@ -298,7 +309,8 @@ class ChessRules if (this.board[x+shift][y] == V.EMPTY) { moves.push(this.getBasicMove([x,y], [x+shift,y])); - if (x==startRank && this.board[x+2*shift][y] == V.EMPTY) + // Next condition because variants with pawns on 1st rank generally allow them to jump + if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY) { // Two squares jump moves.push(this.getBasicMove([x,y], [x+2*shift,y])); @@ -394,7 +406,7 @@ class ChessRules castlingCheck: for (let castleSide=0; castleSide < 2; castleSide++) //large, then small { - if (!this.flags[c][castleSide]) + if (!this.castleFlags[c][castleSide]) continue; // If this code is reached, rooks and king are on initial position @@ -658,7 +670,7 @@ class ChessRules { this.kingPos[c][0] = move.appear[0].x; this.kingPos[c][1] = move.appear[0].y; - this.flags[c] = [false,false]; + this.castleFlags[c] = [false,false]; return; } const oppCol = this.getOppCol(c); @@ -666,14 +678,14 @@ class ChessRules 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.flags[c][flagIdx] = false; + 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[c].includes(move.end.y)) { - const flagIdx = move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1; - this.flags[oppCol][flagIdx] = false; + const flagIdx = (move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1); + this.castleFlags[oppCol][flagIdx] = false; } } @@ -687,11 +699,11 @@ class ChessRules play(move, ingame) { + console.log("AVANT " + this.getNotation(move) + " " + this.board[1][5]); if (!!ingame) move.notation = this.getNotation(move); - // Save flags (for undo) - move.flags = JSON.stringify(this.flags); //TODO: less costly? + move.flags = JSON.stringify(this.flags); //save flags (for undo) this.updateVariables(move); this.moves.push(move); this.epSquares.push( this.getEpSquare(move) ); @@ -704,7 +716,8 @@ class ChessRules this.epSquares.pop(); this.moves.pop(); this.unupdateVariables(move); - this.flags = JSON.parse(move.flags); + this.parseFlags(JSON.parse(move.flags)); + console.log("APRES " + this.getNotation(move) + " " + this.board[1][5]); } ////////////// @@ -982,7 +995,7 @@ class ChessRules for (let i of ['w','b']) { for (let j=0; j<2; j++) - fen += this.flags[i][j] ? '1' : '0'; + fen += this.castleFlags[i][j] ? '1' : '0'; } return fen; } diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index 18632858..170aeac9 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -575,7 +575,7 @@ Vue.component('my-game', { this.newGame("computer"); }, newGame: function(mode, fenInit, color, oppId, moves, continuation) { - const fen = fenInit || VariantRules.GenRandInitFen(); + const fen = "brnbnkrq/pppppppp/8/8/8/8/PPPPPPPP/BNNRKBQR 11111111111111111111";//fenInit || VariantRules.GenRandInitFen(); console.log(fen); //DEBUG this.score = "*"; if (mode=="human" && !oppId) @@ -635,7 +635,7 @@ Vue.component('my-game', { } else //against computer { - this.mycolor = Math.random() < 0.5 ? 'w' : 'b'; + this.mycolor = "w";//Math.random() < 0.5 ? 'w' : 'b'; if (this.mycolor == 'b') setTimeout(this.playComputerMove, 500); } diff --git a/public/javascripts/variants/Atomic.js b/public/javascripts/variants/Atomic.js index f32e21d1..2b7b1ac3 100644 --- a/public/javascripts/variants/Atomic.js +++ b/public/javascripts/variants/Atomic.js @@ -72,7 +72,7 @@ class AtomicRules extends ChessRules && Math.abs(this.kingPos[c][1]-move.end.y) <= 1) { this.kingPos[c] = [-1,-1]; - this.flags[c] = [false,false]; + this.castleFlags[c] = [false,false]; } // Did we explode opponent king ? @@ -80,7 +80,7 @@ class AtomicRules extends ChessRules && Math.abs(this.kingPos[oppCol][1]-move.end.y) <= 1) { this.kingPos[oppCol] = [-1,-1]; - this.flags[oppCol] = [false,false]; + this.castleFlags[oppCol] = [false,false]; } else { @@ -88,9 +88,9 @@ class AtomicRules extends ChessRules if (Math.abs(move.end.x-oppFirstRank) <= 1) { if (Math.abs(move.end.y-this.INIT_COL_ROOK[oppCol][0]) <= 1) - this.flags[oppCol][0] = false; + this.castleFlags[oppCol][0] = false; if (Math.abs(move.end.y-this.INIT_COL_ROOK[oppCol][1]) <= 1) - this.flags[oppCol][1] = false; + this.castleFlags[oppCol][1] = false; } } } diff --git a/public/javascripts/variants/Checkered.js b/public/javascripts/variants/Checkered.js index 6ed73a8b..4f523edb 100644 --- a/public/javascripts/variants/Checkered.js +++ b/public/javascripts/variants/Checkered.js @@ -32,205 +32,71 @@ class CheckeredRules extends ChessRules return ChessRules.fen2board(f); } - static GetFlags(fen) + setFlags(fen) { - let flags = [ - ChessRules.GetFlags(fen), //castle - { - "w": new Array(8), //pawns can move 2 squares - "b": new Array(8) - } - ]; - const fenFlags = fen.split(" ")[1].substr(4); //skip first 4 digits, for castle + super.setFlags(fen); //castleFlags + this.pawnFlags = + { + "w": new Array(8), //pawns can move 2 squares? + "b": new Array(8) + }; + const flags = fen.split(" ")[1].substr(4); //skip first 4 digits, for castle for (let c of ['w','b']) { for (let i=0; i<8; i++) - flags[1][c][i] = (fenFlags.charAt((c=='w'?0:8)+i) == '1'); + this.pawnFlags[c][i] = (flags.charAt((c=='w'?0:8)+i) == '1'); } - return flags; } - canTake([x1,y1], [x2,y2]) - { - const color1 = this.getColor(x1,y1); - const color2 = this.getColor(x2,y2); - // Checkered aren't captured - return color1 != color2 && color2 != 'c' && (color1 != 'c' || color2 != this.turn); + // Aggregates flags into one object + get flags() { + return [this.castleFlags, this.pawnFlags]; } - addCaptures([sx,sy], [ex,ey], moves) + // Reverse operation + parseFlags(flags) { - const piece = this.getPiece(sx,sy); - if (piece != VariantRules.KING) - { - moves.push(this.getBasicMove([sx,sy], [ex,ey], {c:'c',p:piece})); - const takePiece = this.getPiece(ex,ey); - if (takePiece != piece) - moves.push(this.getBasicMove([sx,sy], [ex,ey], {c:'c',p:takePiece})); - } - else - moves.push(this.getBasicMove([sx,sy], [ex,ey])); + this.castleFlags = flags[0]; + this.pawnFlags = flags[1]; } - // Generic method to find possible moves of non-pawn pieces ("sliding or jumping") - getSlideNJumpMoves([x,y], steps, oneStep) - { - const color = this.getColor(x,y); - let moves = []; - const [sizeX,sizeY] = VariantRules.size; - outerLoop: - for (var loop=0; loop=0 && i=0 && j=0 && i<8 && j>=0 && j<8 && this.canTake([x,y], [i,j])) - this.addCaptures([x,y], [i,j], moves); - } - return moves; - } - - // What are the pawn moves from square x,y considering color "color" ? - getPotentialPawnMoves([x,y]) + canTake([x1,y1], [x2,y2]) { - const color = this.getColor(x,y); - var moves = []; - var V = VariantRules; - let [sizeX,sizeY] = VariantRules.size; - const c = (color == 'c' ? this.turn : color); - const shift = (c == "w" ? -1 : 1); - let startRank = (c == "w" ? sizeY-2 : 1); - let lastRank = (c == "w" ? 0 : sizeY-1); - - if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank) - { - // Normal moves - if (this.board[x+shift][y] == V.EMPTY) - { - moves.push(this.getBasicMove([x,y], [x+shift,y])); - if (x==startRank && this.board[x+2*shift][y] == V.EMPTY && this.flags[1][c][y]) - { - // Two squares jump - moves.push(this.getBasicMove([x,y], [x+2*shift,y])); - } - } - // Captures - if (y>0 && this.canTake([x,y], [x+shift,y-1]) && this.board[x+shift][y-1] != V.EMPTY) - this.addCaptures([x,y], [x+shift,y-1], moves); - if (y { - // 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:'c',p:p})); - if (y0 ? this.epSquares[Lep-1] : undefined; - if (!!epSquare && epSquare.x == x+shift && Math.abs(epSquare.y - y) == 1) - { - let epStep = epSquare.y - y; - var enpassantMove = this.getBasicMove([x,y], [x+shift,y+epStep]); - enpassantMove.vanish.push({ - x: x, - y: y+epStep, - p: 'p', - c: this.getColor(x,y+epStep) - }); - enpassantMove.appear[0].c = 'c'; - moves.push(enpassantMove); - } - - return moves; + const color1 = this.getColor(x1,y1); + const color2 = this.getColor(x2,y2); + // Checkered aren't captured + return color1 != color2 && color2 != 'c' && (color1 != 'c' || color2 != this.turn); } - getCastleMoves([x,y]) + // Post-processing: apply "checkerization" of standard moves + getPotentialMovesFrom([x,y]) { - const c = this.getColor(x,y); - if (x != (c=="w" ? 7 : 0) || y != this.INIT_COL_KING[c]) - return []; //x isn't first rank, or king has moved (shortcut) - - const V = VariantRules; - - // Castling ? - const oppCol = this.getOppCol(c); + let standardMoves = super.getPotentialMovesFrom([x,y]); + if (this.getPiece(x,y) == VariantRules.KING) + return standardMoves; //king has to be treated differently (for castles) let moves = []; - let i = 0; - const finalSquares = [ [2,3], [6,5] ]; //king, then rook - castlingCheck: - for (let castleSide=0; castleSide < 2; castleSide++) //large, then small - { - if (!this.flags[0][c][castleSide]) - 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)? - let step = finalSquares[castleSide][0] < y ? -1 : 1; - for (i=y; i!=finalSquares[castleSide][0]; i+=step) + standardMoves.forEach(m => { + if (m.vanish[0].p == VariantRules.PAWN && Math.abs(m.end.x-m.start.x)==2 + && !this.pawnFlags[this.turn][m.start.y]) { - 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))))) - { - continue castlingCheck; - } + return; //skip forbidden 2-squares jumps } - - // Nothing on the path to the rook? - step = castleSide == 0 ? -1 : 1; - for (i = y + step; i != this.INIT_COL_ROOK[c][castleSide]; i += step) - { - if (this.board[x][i] != V.EMPTY) - continue castlingCheck; - } - const rookPos = this.INIT_COL_ROOK[c][castleSide]; - - // Nothing on final squares, except maybe king and castling rook? - for (i=0; i<2; i++) + if (m.vanish.length == 1) + moves.push(m); //no capture + else { - if (this.board[x][finalSquares[castleSide][i]] != V.EMPTY && - this.getPiece(x,finalSquares[castleSide][i]) != V.KING && - finalSquares[castleSide][i] != rookPos) + // A capture occured (m.vanish.length == 2) + m.appear[0].c = "c"; + moves.push(JSON.parse(JSON.stringify(m))); + if (m.appear[0].p != m.vanish[1].p) { - continue castlingCheck; + // Add transformation into captured piece + let m2 = JSON.parse(JSON.stringify(m)); + m2.vanish[1].p = m.appear[0].p; + moves.push(m2); } } - - // If this code is reached, castle is valid - moves.push( new Move({ - appear: [ - new PiPo({x:x,y:finalSquares[castleSide][0],p:V.KING,c:c}), - new PiPo({x:x,y:finalSquares[castleSide][1],p:V.ROOK,c:c})], - vanish: [ - new PiPo({x:x,y:y,p:V.KING,c:c}), - new PiPo({x:x,y:rookPos,p:V.ROOK,c:c})], - end: Math.abs(y - rookPos) <= 2 - ? {x:x, y:rookPos} - : {x:x, y:y + 2 * (castleSide==0 ? -1 : 1)} - }) ); - } - + }); return moves; } @@ -310,40 +176,14 @@ class CheckeredRules extends ChessRules updateVariables(move) { - const piece = this.getPiece(move.start.x,move.start.y); const c = this.getColor(move.start.x,move.start.y); - if (c != 'c') //checkered not concerned by castle flags - { - const firstRank = (c == "w" ? 7 : 0); - // Update king position + flags - if (piece == VariantRules.KING && move.appear.length > 0) - { - this.kingPos[c][0] = move.appear[0].x; - this.kingPos[c][1] = move.appear[0].y; - this.flags[0][c] = [false,false]; - return; - } - const oppCol = this.getOppCol(c); - const oppFirstRank = 7 - 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.flags[0][c][flagIdx] = false; - } - else if (move.end.x == oppFirstRank //we took opponent rook? - && this.INIT_COL_ROOK[c].includes(move.end.y)) - { - const flagIdx = move.end.y == this.INIT_COL_ROOK[oppCol][0] ? 0 : 1; - this.flags[0][oppCol][flagIdx] = false; - } - } + super.updateVariables(move); // Does it turn off a 2-squares pawn flag? const secondRank = [1,6]; if (secondRank.includes(move.start.x) && move.vanish[0].p == VariantRules.PAWN) - this.flags[1][move.start.x==6 ? "w" : "b"][move.start.y] = false; + this.pawnFlags[move.start.x==6 ? "w" : "b"][move.start.y] = false; } checkGameEnd() @@ -385,18 +225,12 @@ class CheckeredRules extends ChessRules getFlagsFen() { - let fen = ""; - // Add castling flags - for (let c of ['w','b']) - { - for (let i=0; i<2; i++) - fen += this.flags[0][c][i] ? '1' : '0'; - } + let fen = super.getFlagsFen(); // Add pawns flags for (let c of ['w','b']) { for (let i=0; i<8; i++) - fen += this.flags[1][c][i] ? '1' : '0'; + fen += this.pawnFlags[c][i] ? '1' : '0'; } return fen; } diff --git a/public/javascripts/variants/Magnetic.js b/public/javascripts/variants/Magnetic.js index 4151f9ad..d5731a63 100644 --- a/public/javascripts/variants/Magnetic.js +++ b/public/javascripts/variants/Magnetic.js @@ -5,10 +5,24 @@ class MagneticRules extends ChessRules return undefined; //no en-passant } + getPotentialMovesFrom([x,y]) + { + const standardMoves = super.getPotentialMovesFrom([x,y]); + let moves = []; + standardMoves.forEach(m => { + let newMove_s = this.applyMagneticLaws(m); + if (newMove_s.length == 1) + moves.push(newMove_s[0]); + else //promotion + moves = moves.concat(moves, newMove_s); + }); + } + // Complete a move with magnetic actions - applyMagneticLaws([x,y], move) + applyMagneticLaws(standardMove) { - const standardMove = JSON.parse(JSON.stringify(move)); + const [x,y] = [moves.start.x, move.start.y]; + let move = JSON.parse(JSON.stringify(standardMove)); this.play(standardMove); const color = this.getColor(x,y); const [sizeX,sizeY] = VariantRules.size; @@ -88,172 +102,22 @@ class MagneticRules extends ChessRules } } this.undo(standardMove); - } - - // TODO: when pawn is pushed to 8th rank, apply promotions (similar change as in Checkered) - getBasicMove([sx,sy], [ex,ey], tr) - { - var mv = new Move({ - appear: [ - new PiPo({ - x: ex, - y: ey, - c: !!tr ? tr.c : this.getColor(sx,sy), - p: !!tr ? tr.p : this.getPiece(sx,sy) - }) - ], - vanish: [ - new PiPo({ - x: sx, - y: sy, - c: this.getColor(sx,sy), - p: this.getPiece(sx,sy) - }) - ] - }); - - if (this.board[ex][ey] != VariantRules.EMPTY) - { - mv.vanish.push( - new PiPo({ - x: ex, - y: ey, - c: this.getColor(ex,ey), - p: this.getPiece(ex,ey) - }) - ); - } - this.applyMagneticLaws([ex,ey], mv); - return mv; - } - - getPotentialPawnMoves([x,y]) - { - const color = this.getColor(x,y); - var moves = []; - var V = VariantRules; - const [sizeX,sizeY] = VariantRules.size; - let shift = (color == "w" ? -1 : 1); - let startRank = (color == "w" ? sizeY-2 : 1); - let firstRank = (color == 'w' ? sizeY-1 : 0); - let lastRank = (color == "w" ? 0 : sizeY-1); - - if (x+shift >= 0 && x+shift < sizeX && x+shift != lastRank) - { - // Normal moves - if (this.board[x+shift][y] == V.EMPTY) - { - moves.push(this.getBasicMove([x,y], [x+shift,y])); - if ([startRank,firstRank].includes(x) && this.board[x+2*shift][y] == V.EMPTY) - { - // Two squares jump - moves.push(this.getBasicMove([x,y], [x+2*shift,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 { - // 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