X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fbase_rules.js;h=856893695ac7f09deaad28cabafae8d33a6f49ea;hb=a0f5dbaac2a9c028aa0ca2559d157b34aeafd3c9;hp=0868a3670178e8a855786f9b422f9d38ca52478b;hpb=46302e643947a66a5593a8eb1140d314effcea95;p=vchess.git diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 0868a367..85689369 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); } @@ -65,37 +65,37 @@ class ChessRules const position = fenParts[0].split("/"); for (let i=0; i 0 ? this.getEpSquare(this.lastMove) : undefined; @@ -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 @@ -467,8 +479,7 @@ class ChessRules { if (moves.length == 0) return []; - let color = this.turn; - return moves.filter(m => { return !this.underCheck(m, color); }); + return moves.filter(m => { return !this.underCheck(m); }); } // Search for all valid moves considering current turn (for engine and game end) @@ -491,25 +502,25 @@ class ChessRules // No: if happen on last 1/2 move, could lead to forbidden moves, wrong evals return this.filterValid(potentialMoves); } - + // Stop at the first move found atLeastOneMove() { const color = this.turn; const oppCol = this.getOppCol(color); let [sizeX,sizeY] = VariantRules.size; - for (var i=0; i 0) { - for (let i=0; i 0) + if (this.filterValid([moves[k]]).length > 0) return true; } } @@ -621,7 +632,7 @@ class ChessRules getCheckSquares(move) { this.play(move); - const color = this.turn; + const color = this.turn; //opponent let res = this.isAttacked(this.kingPos[color], this.getOppCol(color)) ? [ JSON.parse(JSON.stringify(this.kingPos[color])) ] //need to duplicate! : [ ]; @@ -658,7 +669,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 +677,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)) + && this.INIT_COL_ROOK[oppCol].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 +698,14 @@ class ChessRules play(move, ingame) { + // DEBUG: +// if (!this.states) this.states = []; +// if (!ingame) this.states.push(JSON.stringify(this.board)); + 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,13 +718,18 @@ class ChessRules this.epSquares.pop(); this.moves.pop(); this.unupdateVariables(move); - this.flags = JSON.parse(move.flags); + this.parseFlags(JSON.parse(move.flags)); + + // DEBUG: +// let state = this.states.pop(); +// if (JSON.stringify(this.board) != state) +// debugger; } ////////////// // END OF GAME - checkGameOver() + checkRepetition() { // Check for 3 repetitions if (this.moves.length >= 8) @@ -722,15 +741,19 @@ class ChessRules _.isEqual(this.moves[L-3], this.moves[L-7]) && _.isEqual(this.moves[L-4], this.moves[L-8])) { - return "1/2 (repetition)"; + return true; } } + return false; + } - if (this.atLeastOneMove()) - { - // game not over + checkGameOver() + { + if (this.checkRepetition()) + return "1/2"; + + if (this.atLeastOneMove()) // game not over return "*"; - } // Game over return this.checkGameEnd(); @@ -766,10 +789,9 @@ class ChessRules getComputerMove() { const color = this.turn; - - // Rank moves using a min-max at depth 2 let moves1 = this.getAllValidMoves(); + // Rank moves using a min-max at depth 2 for (let i=0; i { return [this.getNotation(m), m.eval]; })); +// console.log(moves1.map(m => { return [this.getNotation(m), m.eval]; })); return moves1[_.sample(candidates, 1)]; } @@ -978,7 +1000,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; } @@ -986,7 +1008,7 @@ class ChessRules // Context: just before move is played, turn hasn't changed getNotation(move) { - if (move.appear.length == 2) + if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) { // Castle if (move.end.y < move.start.y) @@ -996,18 +1018,18 @@ class ChessRules } // Translate final square - let finalSquare = + const finalSquare = String.fromCharCode(97 + move.end.y) + (VariantRules.size[0]-move.end.x); - let piece = this.getPiece(move.start.x, move.start.y); + const piece = this.getPiece(move.start.x, move.start.y); if (piece == VariantRules.PAWN) { // Pawn move let notation = ""; - if (move.vanish.length > 1) + if (move.vanish.length > move.appear.length) { // Capture - let startColumn = String.fromCharCode(97 + move.start.y); + const startColumn = String.fromCharCode(97 + move.start.y); notation = startColumn + "x" + finalSquare; } else //no capture @@ -1020,7 +1042,8 @@ class ChessRules else { // Piece movement - return piece.toUpperCase() + (move.vanish.length > 1 ? "x" : "") + finalSquare; + return piece.toUpperCase() + + (move.vanish.length > move.appear.length ? "x" : "") + finalSquare; } } @@ -1030,7 +1053,8 @@ class ChessRules let pgn = ""; pgn += '[Site "vchess.club"]
'; const d = new Date(); - const opponent = this.mode=="human" ? "Anonymous" : "Computer"; + const opponent = mode=="human" ? "Anonymous" : "Computer"; + pgn += '[Variant "' + variant + '"]
'; pgn += '[Date "' + d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate() + '"]
'; pgn += '[White "' + (mycolor=='w'?'Myself':opponent) + '"]
'; pgn += '[Black "' + (mycolor=='b'?'Myself':opponent) + '"]
';