X-Git-Url: https://git.auder.net/?p=vchess.git;a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FDoublemove1.js;h=95d94d7a8021386c2a27e0c2633819d44700535b;hp=7d1ee4dc5bc4b013b751645b3c88043abc58e897;hb=c3ff3a0c807d97c0311a06491318fe02440266db;hpb=b406466b0f0ce67451f1718053e5f5691d6507fb diff --git a/client/src/variants/Doublemove1.js b/client/src/variants/Doublemove1.js index 7d1ee4dc..95d94d7a 100644 --- a/client/src/variants/Doublemove1.js +++ b/client/src/variants/Doublemove1.js @@ -1,5 +1,4 @@ import { ChessRules } from "@/base_rules"; -import { randInt } from "@/utils/alea"; export class Doublemove1Rules extends ChessRules { static IsGoodEnpassant(enpassant) { @@ -77,29 +76,65 @@ export class Doublemove1Rules extends ChessRules { return moves; } + atLeastOneMove() { + const color = this.turn; + for (let i = 0; i < V.size.x; i++) { + for (let j = 0; j < V.size.y; j++) { + if (this.board[i][j] != V.EMPTY && this.getColor(i, j) == color) { + const moves = this.getPotentialMovesFrom([i, j]); + if (moves.length > 0) { + for (let k = 0; k < moves.length; k++) { + const m = moves[k]; + // NOTE: not using play() here (=> infinite loop) + V.PlayOnBoard(this.board, m); + if (m.vanish[0].p == V.KING) + this.kingPos[color] = [m.appear[0].x, m.appear[0].y]; + const res = !this.underCheck(color); + V.UndoOnBoard(this.board, m); + if (m.vanish[0].p == V.KING) + this.kingPos[color] = [m.start.x, m.start.y]; + if (res) return true; + } + } + } + } + } + return false; + } + play(move) { move.flags = JSON.stringify(this.aggregateFlags()); - move.turn = this.turn + this.subTurn; + move.turn = [this.turn, this.subTurn]; V.PlayOnBoard(this.board, move); const epSq = this.getEpSquare(move); + const oppCol = V.GetOppCol(this.turn); if (this.movesCount == 0) { // First move in game this.turn = "b"; this.epSquares.push([epSq]); this.movesCount = 1; } - // Does this move give check on subturn 1? If yes, skip subturn 2 - else if (this.subTurn == 1 && this.underCheck(V.GetOppCol(this.turn))) { - this.turn = V.GetOppCol(this.turn); + // Does this move give check on subturn 1 or reach stalemate? + // If yes, skip subturn 2 + else if ( + this.subTurn == 1 && + ( + this.underCheck(V.GetOppCol(this.turn)) || + !this.atLeastOneMove() + ) + ) { + this.turn = oppCol; this.epSquares.push([epSq]); move.checkOnSubturn1 = true; this.movesCount++; - } else { + } + else { if (this.subTurn == 2) { - this.turn = V.GetOppCol(this.turn); + this.turn = oppCol; let lastEpsq = this.epSquares[this.epSquares.length - 1]; lastEpsq.push(epSq); - } else { + } + else { this.epSquares.push([epSq]); this.movesCount++; } @@ -109,13 +144,12 @@ export class Doublemove1Rules extends ChessRules { } postPlay(move) { - const c = move.turn.charAt(0); + const c = move.turn[0]; const piece = move.vanish[0].p; const firstRank = c == "w" ? V.size.x - 1 : 0; - if (piece == V.KING && move.appear.length > 0) { - this.kingPos[c][0] = move.appear[0].x; - this.kingPos[c][1] = move.appear[0].y; + if (piece == V.KING) { + this.kingPos[c] = [move.appear[0].x, move.appear[0].y]; this.castleFlags[c] = [V.size.y, V.size.y]; return; } @@ -127,7 +161,8 @@ export class Doublemove1Rules extends ChessRules { ) { const flagIdx = (move.start.y == this.castleFlags[c][0] ? 0 : 1); this.castleFlags[c][flagIdx] = V.size.y; - } else if ( + } + if ( move.end.x == oppFirstRank && //we took opponent rook? this.castleFlags[oppCol].includes(move.end.y) ) { @@ -144,13 +179,14 @@ export class Doublemove1Rules extends ChessRules { this.epSquares.pop(); // Moves counter was just incremented: this.movesCount--; - } else { + } + else { // Undo the second half of a move let lastEpsq = this.epSquares[this.epSquares.length - 1]; lastEpsq.pop(); } this.turn = move.turn[0]; - this.subTurn = parseInt(move.turn[1]); + this.subTurn = move.turn[1]; super.postUndo(move); } @@ -201,42 +237,40 @@ export class Doublemove1Rules extends ChessRules { return res; }; - let moves11 = this.getAllValidMoves(); - let doubleMoves = []; + const moves11 = this.getAllValidMoves(); + let doubleMove = null; + let bestEval = Number.POSITIVE_INFINITY * (color == 'w' ? -1 : 1); // Rank moves using a min-max at depth 2 for (let i = 0; i < moves11.length; i++) { this.play(moves11[i]); if (this.turn != color) { // We gave check with last move: search the best opponent move - doubleMoves.push({ moves: [moves11[i]], eval: getBestMoveEval() }); - } else { + const evalM = getBestMoveEval() + 0.05 - Math.random() / 10; + if ( + (color == 'w' && evalM > bestEval) || + (color == 'b' && evalM < bestEval) + ) { + doubleMove = moves11[i]; + bestEval = evalM; + } + } + else { let moves12 = this.getAllValidMoves(); for (let j = 0; j < moves12.length; j++) { this.play(moves12[j]); - doubleMoves.push({ - moves: [moves11[i], moves12[j]], - eval: getBestMoveEval() - }); + const evalM = getBestMoveEval() + 0.05 - Math.random() / 10 + if ( + (color == 'w' && evalM > bestEval) || + (color == 'b' && evalM < bestEval) + ) { + doubleMove = [moves11[i], moves12[j]]; + bestEval = evalM; + } this.undo(moves12[j]); } } this.undo(moves11[i]); } - - doubleMoves.sort((a, b) => { - return (color == "w" ? 1 : -1) * (b.eval - a.eval); - }); - let candidates = [0]; //indices of candidates moves - for ( - let i = 1; - i < doubleMoves.length && doubleMoves[i].eval == doubleMoves[0].eval; - i++ - ) { - candidates.push(i); - } - - const selected = doubleMoves[randInt(candidates.length)].moves; - if (selected.length == 1) return selected[0]; - return selected; + return doubleMove; } };