X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FOtage.js;h=caf55c9ccecb6888137594672a0dec52c19dc641;hb=4313762da3237b04f204e121a20cab3ba7bb5dd2;hp=b6f38b33ecdbe9d36d57d0c2e3b9a30443fac0e6;hpb=ca4d732ac23cc46c4bfd9c765f6fa309c3d0cbc5;p=vchess.git diff --git a/client/src/variants/Otage.js b/client/src/variants/Otage.js index b6f38b33..caf55c9c 100644 --- a/client/src/variants/Otage.js +++ b/client/src/variants/Otage.js @@ -36,7 +36,7 @@ export class OtageRules extends ChessRules { x: ['b', 'k'], y: ['q', 'q'], z: ['q', 'k'], - '_': ['k', 'k'] + '@': ['k', 'k'] }; } @@ -55,19 +55,21 @@ export class OtageRules extends ChessRules { if (position.length == 0) return false; const rows = position.split("/"); if (rows.length != V.size.x) return false; - let kingSymb = ['k', 'g', 'm', 'u', 'x', '_']; let kings = { 'k': 0, 'K': 0 }; for (let row of rows) { let sumElts = 0; for (let i = 0; i < row.length; i++) { - const lowR = row[i].toLowerCase + const lowR = row[i].toLowerCase(); const readNext = !(ChessRules.PIECES.includes(lowR)); - if (!!(lowR.match(/[a-z_]/))) { + if (!!(lowR.match(/[a-z@]/))) { sumElts++; - if (kingSymb.includes(row[i])) kings['k']++; - // Not "else if", if two kings dancing together - if (kingSymb.some(s => row[i] == s.toUpperCase())) kings['K']++; - if (readNext) i++; + if (lowR == 'k') kings[row[i]]++; + else if (readNext) { + const up = this.getUnionPieces(row[++i], lowR); + if (up.w == V.KING) kings['K']++; + // NOTE: not "else if" because two kings might be in union + if (up.b == V.KING) kings['k']++; + } } else { const num = parseInt(row[i], 10); @@ -138,20 +140,19 @@ export class OtageRules extends ChessRules { this.kingPos = { w: [-1, -1], b: [-1, -1] }; const fenRows = V.ParseFen(fen).position.split("/"); const startRow = { 'w': V.size.x - 1, 'b': 0 }; - const kingSymb = ['k', 'g', 'm', 'u', 'x', '_']; for (let i = 0; i < fenRows.length; i++) { let k = 0; for (let j = 0; j < fenRows[i].length; j++) { const c = fenRows[i].charAt(j); const lowR = c.toLowerCase(); const readNext = !(ChessRules.PIECES.includes(lowR)); - if (!!(lowR.match(/[a-z_]/))) { - if (kingSymb.includes(c)) - this.kingPos["b"] = [i, k]; - // Not "else if", in case of two kings dancing together - if (kingSymb.some(s => c == s.toUpperCase())) - this.kingPos["w"] = [i, k]; - if (readNext) j++; + if (!!(lowR.match(/[a-z@]/))) { + if (lowR == 'k') this.kingPos[c == 'k' ? 'b' : 'w'] = [i, k]; + else if (readNext) { + const up = this.getUnionPieces(fenRows[i][++j], lowR); + if (up.w == V.KING) this.kingPos['w'] = [i, k]; + if (up.b == V.KING) this.kingPos['b'] = [i, k]; + } } else { const num = parseInt(fenRows[i].charAt(j), 10); @@ -166,6 +167,7 @@ export class OtageRules extends ChessRules { super.setOtherVariables(fen); // Stack of "last move" only for intermediate chaining this.lastMoveEnd = [null]; + this.repetitions = []; } static IsGoodFlags(flags) { @@ -195,9 +197,9 @@ export class OtageRules extends ChessRules { this.pawnFlags = flags[1]; } - static GenRandInitFen(randomness) { + static GenRandInitFen(options) { // Add 16 pawns flags: - return ChessRules.GenRandInitFen(randomness) + return ChessRules.GenRandInitFen(options) .slice(0, -2) + "1111111111111111 -"; } @@ -253,7 +255,14 @@ export class OtageRules extends ChessRules { // Transformation computed without taking union into account const up = this.getUnionPieces(initColor, initPiece); let args = [tr.p, up[oppCol]]; - if (['a', 'v'].includes(initColor)) args = args.reverse(); + if ( + ['a', 'v'].includes(initColor) || + // HACK: "ba" piece = two pawns, black controling. + // If promoting, must artificially imagine color was 'a': + (initPiece == 'a' && initColor == 'b') + ) { + args = args.reverse(); + } const capturer = (['a', 'b'].includes(initColor) ? 'b' : 'w'); const cp = this.getUnionCode(args[0], args[1], capturer); tr.c = cp.c; @@ -346,7 +355,7 @@ export class OtageRules extends ChessRules { } let baseMoves = []; const c = this.turn; - switch (piece || this.getPiece(x, y)) { + switch (piece) { case V.PAWN: { const firstRank = (c == 'w' ? 7 : 0); baseMoves = this.getPotentialPawnMoves([x, y]).filter(m => { @@ -381,12 +390,9 @@ export class OtageRules extends ChessRules { break; case V.KING: baseMoves = this.getSlideNJumpMoves( - [x, y], - V.steps[V.ROOK].concat(V.steps[V.BISHOP]), - "oneStep" - ); + [x, y], V.steps[V.ROOK].concat(V.steps[V.BISHOP]), 1); if (!noCastle && this.castleFlags[this.turn].some(v => v < V.size.y)) - baseMoves = baseMoves.concat(this.getCastleMoves(sq)); + baseMoves = baseMoves.concat(this.getCastleMoves([x, y])); break; } // When a pawn in an union reaches final rank with a non-standard @@ -637,8 +643,32 @@ export class OtageRules extends ChessRules { getCheckSquares() { return []; } + filterValid(moves) { - return moves; + if (moves.length == 0) return []; + return moves.filter(m => { + if (!m.end.released) return true; + // Check for repetitions: + V.PlayOnBoard(this.board, m); + const newState = { + piece: m.end.released, + square: { x: m.end.x, y: m.end.y }, + position: this.getBaseFen() + }; + const repet = + this.repetitions.some(r => { + return ( + r.piece == newState.piece && + ( + r.square.x == newState.square.x && + r.square.y == newState.square.y + ) && + r.position == newState.position + ); + }); + V.UndoOnBoard(this.board, m); + return !repet; + }); } updateCastleFlags(move, piece) { @@ -669,14 +699,22 @@ export class OtageRules extends ChessRules { const c = this.turn; const L = this.lastMoveEnd.length; const lm = this.lastMoveEnd[L-1]; - const piece = (!!lm ? lm.p : move.vanish[0].p); + const piece = + !!lm + ? lm.p + : this.getPiece(move.vanish[0].x, move.vanish[0].y); if (piece == V.KING) this.kingPos[c] = [move.appear[0].x, move.appear[0].y]; this.updateCastleFlags(move, piece); const pawnFirstRank = (c == 'w' ? 6 : 1); - if (move.start.x == pawnFirstRank) - // This move (potentially) turns off a 2-squares pawn flag + if ( + move.start.x == pawnFirstRank && + piece == V.PAWN && + Math.abs(move.end.x - move.start.x) == 2 + ) { + // This move turns off a 2-squares pawn flag this.pawnFlags[c][move.start.y] = false; + } } play(move) { @@ -693,6 +731,16 @@ export class OtageRules extends ChessRules { else this.lastMoveEnd.push(Object.assign({ p: move.end.released }, move.end)); V.PlayOnBoard(this.board, move); + if (!move.end.released) this.repetitions = []; + else { + this.repetitions.push( + { + piece: move.end.released, + square: { x: move.end.x, y: move.end.y }, + position: this.getBaseFen() + } + ); + } } undo(move) { @@ -704,12 +752,20 @@ export class OtageRules extends ChessRules { this.turn = V.GetOppCol(this.turn); this.movesCount--; } + if (!!move.end.released) this.repetitions.pop(); this.postUndo(move); } postUndo(move) { if (this.getPiece(move.start.x, move.start.y) == V.KING) this.kingPos[this.turn] = [move.start.x, move.start.y]; + else { + // Check if a king is being released: put it on releasing square + const L = this.lastMoveEnd.length; + const lm = this.lastMoveEnd[L-1]; + if (!!lm && lm.p == V.KING) + this.kingPos[this.turn] = [move.start.x, move.start.y]; + } } getCurrentScore() { @@ -752,6 +808,7 @@ export class OtageRules extends ChessRules { for (let i = mvArray.length - 1; i >= 0; i--) this.undo(mvArray[i]); if (!mv.end.released) return (mvArray.length > 1 ? mvArray : mvArray[0]); } + return null; //never reached } // NOTE: evalPosition() is wrong, but unused since bot plays at random @@ -789,8 +846,13 @@ export class OtageRules extends ChessRules { // Add potential promotion indications: const firstLastRank = (c == 'w' ? [7, 0] : [0, 7]); if (move.end.x == firstLastRank[1] && piece == V.PAWN) { - const up = this.getUnionPieces(move.appear[0].c, move.appear[0].p); - notation += "=" + up[c].toUpperCase(); + notation += "="; + if (ChessRules.PIECES.includes(move.appear[0].p)) + notation += move.appear[0].p.toUpperCase(); + else { + const up = this.getUnionPieces(move.appear[0].c, move.appear[0].p); + notation += up[c].toUpperCase(); + } } else if ( move.end.x == firstLastRank[0] &&