X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fbase_rules.js;h=9f6ec9ecbb2b2e7ff3d197422d37462cb50cb9a7;hb=b955c65b942d09d24b5c3bed0d755d4f2f8f71f1;hp=8f875e4f918d727d99a2e5e404c30703bc5f5f3b;hpb=edcd679ab1fe609641451586ef1e9484925c4f83;p=vchess.git diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 8f875e4f..9f6ec9ec 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -66,10 +66,13 @@ class ChessRules // 2) Check turn if (!fenParsed.turn || !V.IsGoodTurn(fenParsed.turn)) return false; - // 3) Check flags + // 3) Check moves count + if (!fenParsed.movesCount || !(parseInt(fenParsed.movesCount) >= 0)) + return false; + // 4) Check flags if (V.HasFlags && (!fenParsed.flags || !V.IsGoodFlags(fenParsed.flags))) return false; - // 4) Check enpassant + // 5) Check enpassant if (V.HasEnpassant && (!fenParsed.enpassant || !V.IsGoodEnpassant(fenParsed.enpassant))) { @@ -218,7 +221,7 @@ class ChessRules // On which squares is color under check ? (for interface) getCheckSquares(color) { - return this.isAttacked(this.kingPos[color], [this.getOppCol(color)]) + return this.isAttacked(this.kingPos[color], [V.GetOppCol(color)]) ? [JSON.parse(JSON.stringify(this.kingPos[color]))] //need to duplicate! : []; } @@ -277,7 +280,7 @@ class ChessRules return pieces["b"].join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + pieces["w"].join("").toUpperCase() + - " w 1111 -"; //add turn + flags + enpassant + " w 0 1111 -"; //add turn + flags + enpassant } // "Parse" FEN: just return untransformed string data @@ -288,8 +291,9 @@ class ChessRules { position: fenParts[0], turn: fenParts[1], + movesCount: fenParts[2], }; - let nextIdx = 2; + let nextIdx = 3; if (V.HasFlags) Object.assign(res, {flags: fenParts[nextIdx++]}); if (V.HasEnpassant) @@ -300,7 +304,8 @@ class ChessRules // Return current fen (game state) getFen() { - return this.getBaseFen() + " " + this.getTurnFen() + + return this.getBaseFen() + " " + + this.getTurnFen() + " " + this.movesCount + (V.HasFlags ? (" " + this.getFlagsFen()) : "") + (V.HasEnpassant ? (" " + this.getEnpassantFen()) : ""); } @@ -401,12 +406,12 @@ class ChessRules // INITIALIZATION // Fen string fully describes the game state - constructor(fen, moves) + constructor(fen) { - this.moves = moves; const fenParsed = V.ParseFen(fen); this.board = V.GetBoard(fenParsed.position); this.turn = fenParsed.turn[0]; //[0] to work with MarseilleRules + this.movesCount = parseInt(fenParsed.movesCount); this.setOtherVariables(fen); } @@ -493,15 +498,15 @@ class ChessRules } // Get opponent color - getOppCol(color) + static GetOppCol(color) { return (color=="w" ? "b" : "w"); } - get lastMove() + // Get next color (for compatibility with 3 and 4 players games) + static GetNextCol(color) { - const L = this.moves.length; - return (L>0 ? this.moves[L-1] : null); + return V.GetOppCol(color); } // Pieces codes (for a clearer code) @@ -729,7 +734,7 @@ class ChessRules return []; //x isn't first rank, or king has moved (shortcut) // Castling ? - const oppCol = this.getOppCol(c); + const oppCol = V.GetOppCol(c); let moves = []; let i = 0; const finalSquares = [ [2,3], [V.size.y-2,V.size.y-3] ]; //king, then rook @@ -819,7 +824,7 @@ class ChessRules getAllValidMoves() { const color = this.turn; - const oppCol = this.getOppCol(color); + const oppCol = V.GetOppCol(color); let potentialMoves = []; for (let i=0; i { return a+b; }, 0) - // Update this.hashStates with last move (or all moves if continuation) - // NOTE: redundant storage, but faster and moderate size - for (let i=startIndex; i { return (elt >= 3); }); - } - - // Is game over ? And if yes, what is the score ? - checkGameOver() + // What is the score ? (Interesting if game is over) + getCurrentScore() { - if (this.checkRepetition()) - return "1/2"; - if (this.atLeastOneMove()) // game not over return "*"; // Game over - return this.checkGameEnd(); - } - - // No moves are possible: compute score - checkGameEnd() - { const color = this.turn; // No valid move: stalemate or checkmate? - if (!this.isAttacked(this.kingPos[color], [this.getOppCol(color)])) + if (!this.isAttacked(this.kingPos[color], [V.GetOppCol(color)])) return "1/2"; // OK, checkmate return (color == "w" ? "0-1" : "1-0"); @@ -1166,11 +1136,10 @@ class ChessRules { this.play(moves1[i]); let finish = (Math.abs(this.evalPosition()) >= V.THRESHOLD_MATE); - if (!finish && !this.atLeastOneMove()) + if (!finish) { - // Test mate (for other variants) - const score = this.checkGameEnd(); - if (score != "1/2") + const score = this.getCurrentScore(); + if (["1-0","0-1"].includes(score)) finish = true; } this.undo(moves1[i]); @@ -1184,8 +1153,9 @@ class ChessRules // Initial self evaluation is very low: "I'm checkmated" moves1[i].eval = (color=="w" ? -1 : 1) * maxeval; this.play(moves1[i]); + const score1 = this.getCurrentScore(); let eval2 = undefined; - if (this.atLeastOneMove()) + if (score1 == "*") { // Initial enemy evaluation is very low too, for him eval2 = (color=="w" ? 1 : -1) * maxeval; @@ -1194,15 +1164,10 @@ class ChessRules for (let j=0; j eval2)) { @@ -1212,10 +1177,7 @@ class ChessRules } } else - { - const score = this.checkGameEnd(); - eval2 = (score=="1/2" ? 0 : (score=="1-0" ? 1 : -1) * maxeval); - } + eval2 = (score1=="1/2" ? 0 : (score1=="1-0" ? 1 : -1) * maxeval); if ((color=="w" && eval2 > moves1[i].eval) || (color=="b" && eval2 < moves1[i].eval)) { @@ -1263,17 +1225,9 @@ class ChessRules { const maxeval = V.INFINITY; const color = this.turn; - if (!this.atLeastOneMove()) - { - switch (this.checkGameEnd()) - { - case "1/2": - return 0; - default: - const score = this.checkGameEnd(); - return (score=="1/2" ? 0 : (score=="1-0" ? 1 : -1) * maxeval); - } - } + const score = this.getCurrentScore(); + if (score != "*") + return (score=="1/2" ? 0 : (score=="1-0" ? 1 : -1) * maxeval); if (depth == 0) return this.evalPosition(); const moves = this.getAllValidMoves("computer"); @@ -1328,6 +1282,7 @@ class ChessRules ///////////////////////// // Context: just before move is played, turn hasn't changed + // TODO: un-ambiguous notation (switch on piece type, check directions...) getNotation(move) { if (move.appear.length == 2 && move.appear[0].p == V.KING) //castle @@ -1361,52 +1316,4 @@ class ChessRules (move.vanish.length > move.appear.length ? "x" : "") + finalSquare; } } - - // Complete the usual notation, may be required for de-ambiguification - getLongNotation(move) - { - // Not encoding move. But short+long is enough - return V.CoordsToSquare(move.start) + V.CoordsToSquare(move.end); - } - - // The score is already computed when calling this function - getPGN(mycolor, score, fenStart, mode) - { - let pgn = ""; - pgn += '[Site "vchess.club"]\n'; - const opponent = mode=="human" ? "Anonymous" : "Computer"; - pgn += '[Variant "' + variant + '"]\n'; - pgn += '[Date "' + getDate(new Date()) + '"]\n'; - // TODO: later when users are a bit less anonymous, use better names - const whiteName = ["human","computer"].includes(mode) - ? (mycolor=='w'?'Myself':opponent) - : "analyze"; - const blackName = ["human","computer"].includes(mode) - ? (mycolor=='b'?'Myself':opponent) - : "analyze"; - pgn += '[White "' + whiteName + '"]\n'; - pgn += '[Black "' + blackName + '"]\n'; - pgn += '[FenStart "' + fenStart + '"]\n'; - pgn += '[Fen "' + this.getFen() + '"]\n'; - pgn += '[Result "' + score + '"]\n\n'; - - // Standard PGN - for (let i=0; i