X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=public%2Fjavascripts%2Fbase_rules.js;h=f466624d653ebc5ec50e46036c7c3785ecb4b82d;hb=a37076f1ac8f4c19d9b34a60cbe89df86b88fa0b;hp=d63806752f726e2f686b23e7ea2516f293418cd5;hpb=5bfb09560aa346d132e829a7c63558407bcc8091;p=vchess.git diff --git a/public/javascripts/base_rules.js b/public/javascripts/base_rules.js index d6380675..f466624d 100644 --- a/public/javascripts/base_rules.js +++ b/public/javascripts/base_rules.js @@ -171,7 +171,6 @@ class ChessRules 'r': [ [-1,0],[1,0],[0,-1],[0,1] ], 'n': [ [-1,-2],[-1,2],[1,-2],[1,2],[-2,-1],[-2,1],[2,-1],[2,1] ], 'b': [ [-1,-1],[-1,1],[1,-1],[1,1] ], - 'q': [ [-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1] ] }; } @@ -379,14 +378,17 @@ class ChessRules // What are the queen moves from square x,y ? getPotentialQueenMoves(sq) { - return this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN]); + const V = VariantRules; + return this.getSlideNJumpMoves(sq, V.steps[V.ROOK].concat(V.steps[V.BISHOP])); } // What are the king moves from square x,y ? getPotentialKingMoves(sq) { + const V = VariantRules; // Initialize with normal moves - let moves = this.getSlideNJumpMoves(sq, VariantRules.steps[VariantRules.QUEEN], "oneStep"); + let moves = this.getSlideNJumpMoves(sq, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); return moves.concat(this.getCastleMoves(sq)); } @@ -479,8 +481,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) @@ -503,25 +504,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; } } @@ -587,15 +588,17 @@ class ChessRules // Is square x,y attacked by queens of color c ? isAttackedByQueen(sq, colors) { - return this.isAttackedBySlideNJump(sq, colors, - VariantRules.QUEEN, VariantRules.steps[VariantRules.QUEEN]); + const V = VariantRules; + return this.isAttackedBySlideNJump(sq, colors, V.QUEEN, + V.steps[V.ROOK].concat(V.steps[V.BISHOP])); } // Is square x,y attacked by king of color c ? isAttackedByKing(sq, colors) { - return this.isAttackedBySlideNJump(sq, colors, - VariantRules.KING, VariantRules.steps[VariantRules.QUEEN], "oneStep"); + const V = VariantRules; + return this.isAttackedBySlideNJump(sq, colors, V.KING, + V.steps[V.ROOK].concat(V.steps[V.BISHOP]), "oneStep"); } // Generic method for non-pawn pieces ("sliding or jumping"): is x,y attacked by piece != color ? @@ -699,6 +702,10 @@ 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); @@ -716,6 +723,11 @@ class ChessRules this.moves.pop(); this.unupdateVariables(move); this.parseFlags(JSON.parse(move.flags)); + + // DEBUG: +// let state = this.states.pop(); +// if (JSON.stringify(this.board) != state) +// debugger; } ////////////// @@ -777,18 +789,28 @@ class ChessRules }; } + static get INFINITY() { + return 9999; //"checkmate" (unreachable eval) + } + + static get THRESHOLD_MATE() { + // At this value or above, the game is over + return VariantRules.INFINITY; + } + // Assumption: at least one legal move - getComputerMove() + getComputerMove(moves1) //moves1 might be precomputed (Magnetic chess) { + const maxeval = VariantRules.INFINITY; const color = this.turn; + if (!moves1) + moves1 = this.getAllValidMoves(); // Rank moves using a min-max at depth 2 - let moves1 = this.getAllValidMoves(); - for (let i=0; i { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); - // TODO: show current analyzed move for depth 3, allow stopping eval (return moves1[0]) - for (let i=0; i { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); } - moves1.sort( (a,b) => { return (color=="w" ? 1 : -1) * (b.eval - a.eval); }); let candidates = [0]; //indices of candidates moves for (let j=1; j { return [this.getNotation(m), m.eval]; })); +// console.log(moves1.map(m => { return [this.getNotation(m), m.eval]; })); return moves1[_.sample(candidates, 1)]; } alphabeta(depth, alpha, beta) { + const maxeval = VariantRules.INFINITY; const color = this.turn; if (!this.atLeastOneMove()) { switch (this.checkGameEnd()) { case "1/2": return 0; - default: return color=="w" ? -1000 : 1000; + default: return color=="w" ? -maxeval : maxeval; } } if (depth == 0) return this.evalPosition(); const moves = this.getAllValidMoves(); - let v = color=="w" ? -1000 : 1000; + let v = color=="w" ? -maxeval : maxeval; if (color == "w") { for (let i=0; i 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 @@ -1035,7 +1061,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; } } @@ -1046,6 +1073,7 @@ class ChessRules 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 += '[White "' + (mycolor=='w'?'Myself':opponent) + '"]
'; pgn += '[Black "' + (mycolor=='b'?'Myself':opponent) + '"]
';