X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fbase_rules.js;h=750cd2d4ab72313fc4e1149dd76103ff4926147a;hb=32cfcea44bf00b0c6c4d172cca715823076ff490;hp=79301f950833e360d2b1a67995ad636a2a3b9070;hpb=04449c9757e5a39628dcefccdc7be5f95c068fcd;p=vchess.git diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index 79301f95..750cd2d4 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -1,3 +1,6 @@ +// (Orthodox) Chess rules are defined in ChessRules class. +// Variants generally inherit from it, and modify some parts. + class PiPo //Piece+Position { // o: {piece[p], color[c], posX[x], posY[y]} @@ -10,6 +13,7 @@ class PiPo //Piece+Position } } +// TODO: for animation, moves should contains "moving" and "fading" maybe... class Move { // o: {appear, vanish, [start,] [end,]} @@ -60,7 +64,7 @@ class ChessRules { this.INIT_COL_KING = {'w':-1, 'b':-1}; this.INIT_COL_ROOK = {'w':[-1,-1], 'b':[-1,-1]}; - this.kingPos = {'w':[-1,-1], 'b':[-1,-1]}; //respective squares of white and black king + this.kingPos = {'w':[-1,-1], 'b':[-1,-1]}; //squares of white and black king const fenParts = fen.split(" "); const position = fenParts[0].split("/"); for (let i=0; i= 8) @@ -818,10 +825,11 @@ class ChessRules // NOTE: works also for extinction chess because depth is 3... getComputerMove() { - this.shouldReturn = false; const maxeval = VariantRules.INFINITY; const color = this.turn; - let moves1 = this.getAllValidMoves(); + // Some variants may show a bigger moves list to the human (Switching), + // thus the argument "computer" below (which is generally ignored) + let moves1 = this.getAllValidMoves("computer"); // Can I mate in 1 ? (for Magnetic & Extinction) for (let i of _.shuffle(_.range(moves1.length))) @@ -843,7 +851,7 @@ class ChessRules { eval2 = (color=="w" ? 1 : -1) * maxeval; //initialized with checkmate value // Second half-move: - let moves2 = this.getAllValidMoves(); + let moves2 = this.getAllValidMoves("computer"); for (let j=0; j moves1[i].eval) || (color=="b" && eval2 < moves1[i].eval)) + if ((color=="w" && eval2 > moves1[i].eval) + || (color=="b" && eval2 < moves1[i].eval)) + { moves1[i].eval = eval2; + } this.undo(moves1[i]); } moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); @@ -878,14 +889,17 @@ class ChessRules candidates.push(j); let currentBest = moves1[_.sample(candidates, 1)]; + // From here, depth >= 3: may take a while, so we control time + const timeStart = Date.now(); + // Skip depth 3+ if we found a checkmate (or if we are checkmated in 1...) if (VariantRules.SEARCH_DEPTH >= 3 && Math.abs(moves1[0].eval) < VariantRules.THRESHOLD_MATE) { for (let i=0; i= 5000) //more than 5 seconds + return currentBest; //depth 2 at least this.play(moves1[i]); // 0.1 * oldEval : heuristic to avoid some bad moves (not all...) moves1[i].eval = 0.1*moves1[i].eval + @@ -921,7 +935,7 @@ class ChessRules } if (depth == 0) return this.evalPosition(); - const moves = this.getAllValidMoves(); + const moves = this.getAllValidMoves("computer"); let v = color=="w" ? -maxeval : maxeval; if (color == "w") { @@ -975,9 +989,9 @@ class ChessRules // Setup the initial random (assymetric) position static GenRandInitFen() { - let pieces = [new Array(8), new Array(8)]; + let pieces = { "w": new Array(8), "b": new Array(8) }; // Shuffle pieces on first and last rank - for (let c = 0; c <= 1; c++) + for (let c of ["w","b"]) { let positions = _.range(8); @@ -1019,9 +1033,9 @@ class ChessRules pieces[c][knight2Pos] = 'n'; pieces[c][rook2Pos] = 'r'; } - let fen = pieces[0].join("") + + let fen = pieces["b"].join("") + "/pppppppp/8/8/8/8/PPPPPPPP/" + - pieces[1].join("").toUpperCase() + + pieces["w"].join("").toUpperCase() + " 1111"; //add flags return fen; } @@ -1074,7 +1088,7 @@ class ChessRules for (let i of ['w','b']) { for (let j=0; j<2; j++) - fen += this.castleFlags[i][j] ? '1' : '0'; + fen += (this.castleFlags[i][j] ? '1' : '0'); } return fen; } @@ -1082,14 +1096,8 @@ class ChessRules // Context: just before move is played, turn hasn't changed getNotation(move) { - if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) - { - // Castle - if (move.end.y < move.start.y) - return "0-0-0"; - else - return "0-0"; - } + if (move.appear.length == 2 && move.appear[0].p == VariantRules.KING) //castle + return (move.end.y < move.start.y ? "0-0-0" : "0-0"); // Translate final square const finalSquare = @@ -1134,12 +1142,14 @@ class ChessRules // The score is already computed when calling this function getPGN(mycolor, score, fenStart, mode) { + const zeroPad = x => { return (x<10 ? "0" : "") + x; }; let pgn = ""; pgn += '[Site "vchess.club"]
'; const d = new Date(); const opponent = mode=="human" ? "Anonymous" : "Computer"; pgn += '[Variant "' + variant + '"]
'; - pgn += '[Date "' + d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate() + '"]
'; + pgn += '[Date "' + d.getFullYear() + '-' + (d.getMonth()+1) + + '-' + zeroPad(d.getDate()) + '"]
'; pgn += '[White "' + (mycolor=='w'?'Myself':opponent) + '"]
'; pgn += '[Black "' + (mycolor=='b'?'Myself':opponent) + '"]
'; pgn += '[FenStart "' + fenStart + '"]
'; @@ -1153,7 +1163,7 @@ class ChessRules pgn += ((i/2)+1) + "."; pgn += this.moves[i].notation[0] + " "; } - pgn += score + "

"; + pgn += "

"; // "Complete moves" PGN (helping in ambiguous cases) for (let i=0; i