X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FBario.js;h=57dd18ea13282bdf9cdf89c8d1146be035c1c537;hb=2da551a3aafd653a9b40bde5e182761bc6c12ae5;hp=5b5b33c39ba28326448a6dd4b1571758fba9c891;hpb=0b0f03354fdb4ffbcf9c0dd208d42c80235ade45;p=vchess.git diff --git a/client/src/variants/Bario.js b/client/src/variants/Bario.js index 5b5b33c3..57dd18ea 100644 --- a/client/src/variants/Bario.js +++ b/client/src/variants/Bario.js @@ -2,13 +2,11 @@ import { ChessRules, PiPo, Move } from "@/base_rules"; import { ArrayFun } from "@/utils/array"; import { randInt } from "@/utils/alea"; -// TODO: issue with undo of specialisation to cover check, subTurn decremented to 0 - export class BarioRules extends ChessRules { // Does not really seem necessary (although the author mention it) // Instead, first move = pick a square for the king. - static get HasCastle() { + static get HasFlags() { return false; } @@ -111,8 +109,8 @@ export class BarioRules extends ChessRules { getReserveFen() { let counts = new Array(8); for (let i = 0; i < V.RESERVE_PIECES.length; i++) { - counts[i] = this.reserve["w"][V.PIECES[i]]; - counts[4 + i] = this.reserve["b"][V.PIECES[i]]; + counts[i] = this.reserve["w"][V.RESERVE_PIECES[i]]; + counts[4 + i] = this.reserve["b"][V.RESERVE_PIECES[i]]; } return counts.join(""); } @@ -194,17 +192,15 @@ export class BarioRules extends ChessRules { if (this.subTurn == 0) { const L = this.captureUndefined.length; const cu = this.captureUndefined[L-1]; - return ( + return [ + // Nothing changes on the board, just mark start.p for reserve update new Move({ - appear: [ - new PiPo({ x: cu.x, y: cu.y, c: color, p: p }) - ], - vanish: [ - new PiPo({ x: cu.x, y: cu.y, c: color, p: V.UNDEFINED }) - ], - start: { x: x, y: y } + appear: [], + vanish: [], + start: { x: x, y: y, p: p }, + end: { x: cu.x, y: cu.y } }) - ); + ]; } // or, subTurn == 1 => target any undefined piece that we own. let moves = []; @@ -252,10 +248,24 @@ export class BarioRules extends ChessRules { return super.getPotentialMovesFrom([x, y]); } - getAllValidMoves() { + getAllPotentialMoves() { + const color = this.turn; + if (this.movesCount <= 1) { + // Just put the king on the board + let moves = []; + const firstRank = (color == 'w' ? 7 : 0); + return [...Array(8)].map((x, j) => { + return new Move({ + appear: [ + new PiPo({ x: firstRank, y: j, c: color, p: V.KING }) + ], + vanish: [], + start: { x: -1, y: -1 } + }); + }); + } const getAllReserveMoves = () => { let moves = []; - const color = this.turn; for (let i = 0; i < V.RESERVE_PIECES.length; i++) { moves = moves.concat( this.getReserveMoves([V.size.x + (color == "w" ? 0 : 1), i]) @@ -276,7 +286,21 @@ export class BarioRules extends ChessRules { if (m.vanish.length == 0) return true; const start = { x: m.vanish[0].x, y: m.vanish[0].y }; const end = { x: m.appear[0].x, y: m.appear[0].y }; - if (start.x == end.x && start.y == end.y) return true; //unfinished turn + if (start.x == end.x && start.y == end.y) { + // Unfinished turn: require careful check + this.play(m); + let res = false; + if (this.subTurn == 1) + // Can either play a move, or specialize a piece + res = this.filterValid(this.getAllPotentialMoves()).length > 0; + else { + // subTurn == 2: can only play a specialized piece + res = this.filterValid( + this.getPotentialMovesFrom([m.end.x, m.end.y])).length > 0; + } + this.undo(m); + return res; + } this.play(m); const res = !this.underCheck(color); this.undo(m); @@ -356,6 +380,7 @@ export class BarioRules extends ChessRules { } play(move) { + move.turn = [this.turn, this.subTurn]; //easier undo (TODO?) const toNextPlayer = () => { V.PlayOnBoard(this.board, move); this.turn = V.GetOppCol(this.turn); @@ -365,20 +390,21 @@ export class BarioRules extends ChessRules { this.postPlay(move); }; if (move.vanish.length == 0) { - toNextPlayer(); + if (move.appear.length == 1) toNextPlayer(); + else { + // Removal (subTurn == 0 --> 1) + this.reserve[this.turn][move.start.p]--; + this.subTurn++; + } return; } const start = { x: move.vanish[0].x, y: move.vanish[0].y }; const end = { x: move.appear[0].x, y: move.appear[0].y }; if (start.x == end.x && start.y == end.y) { - // Specialisation (subTurn == 1 before 2), or Removal (subTurn == 0). - // In both cases, turn not over, and a piece removed from reserve + // Specialisation (subTurn == 1 before 2) this.reserve[this.turn][move.appear[0].p]--; - if (move.appear[0].c == move.vanish[0].c) { - // Specialisation: play "move" on board - V.PlayOnBoard(this.board, move); - this.definitions.push(move.end); - } + V.PlayOnBoard(this.board, move); + this.definitions.push(move.end); this.subTurn++; } else { @@ -417,31 +443,55 @@ export class BarioRules extends ChessRules { }) ) { const piecesList = [V.ROOK, V.KNIGHT, V.BISHOP, V.QUEEN]; - let myPieces = {}; + const oppCol = this.turn; + let definedPieces = { w: {}, b: {} }; for (let i=0; i<8; i++) { for (let j=0; j<8; j++) { - if ( - this.board[i][j] != V.EMPTY && - this.getColor(i, j) == color - ) { + if (this.board[i][j] != V.EMPTY) { const p = this.getPiece(i, j); - if (piecesList.includes(p)) - myPieces[p] = (!myPieces[p] ? 1 : myPieces[p] + 1); + const c = this.getColor(i, j); + if (piecesList.includes(p)) { + definedPieces[c][p] = + (!definedPieces[c][p] ? 1 : definedPieces[c][p] + 1); + } } } } - const pk = Object.keys(myPieces); - if (pk.length >= 2) { + const my_pk = Object.keys(definedPieces[color]); + const opp_pk = Object.keys(definedPieces[oppCol]); + const oppRevert = ( + opp_pk.length >= 2 || + ( + // Only one opponent's piece is defined, but + // at least a different piece wait in reserve: + opp_pk.length == 1 && + Object.keys(this.reserve[oppCol]).some(k => { + return (k != opp_pk[0] && this.reserve[oppCol][k] >= 1); + }) + ) + ); + if (my_pk.length >= 2 || oppRevert) { + // NOTE: necessary HACK... because the move is played already. + V.UndoOnBoard(this.board, move); move.position = this.getBaseFen(); - for (let p of pk) this.reserve[color][p] = myPieces[p]; - for (let i=0; i<8; i++) { - for (let j=0; j<8; j++) { - if ( - this.board[i][j] != V.EMPTY && - this.getColor(i, j) == color && - piecesList.includes(this.getPiece(i, j)) - ) { - this.board[i][j] = color + V.UNDEFINED; + move.reserve = JSON.parse(JSON.stringify(this.reserve)); + V.PlayOnBoard(this.board, move); + for ( + let cp of [{ c: color, pk: my_pk }, { c: oppCol, pk: opp_pk }] + ) { + if (cp.pk.length >= 2 || (cp.c == oppCol && oppRevert)) { + for (let p of cp.pk) + this.reserve[cp.c][p] += definedPieces[cp.c][p]; + for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if ( + this.board[i][j] != V.EMPTY && + this.getColor(i, j) == cp.c && + piecesList.includes(this.getPiece(i, j)) + ) { + this.board[i][j] = cp.c + V.UNDEFINED; + } + } } } } @@ -454,23 +504,25 @@ export class BarioRules extends ChessRules { undo(move) { const toPrevPlayer = () => { V.UndoOnBoard(this.board, move); - this.turn = V.GetOppCol(this.turn); + [this.turn, this.subTurn] = move.turn; this.movesCount--; this.postUndo(move); }; if (move.vanish.length == 0) { - toPrevPlayer(); + if (move.appear.length == 1) toPrevPlayer(); + else { + this.reserve[this.turn][move.start.p]++; + this.subTurn = move.turn[1]; + } return; } const start = { x: move.vanish[0].x, y: move.vanish[0].y }; const end = { x: move.appear[0].x, y: move.appear[0].y }; if (start.x == end.x && start.y == end.y) { this.reserve[this.turn][move.appear[0].p]++; - if (move.appear[0].c == move.vanish[0].c) { - V.UndoOnBoard(this.board, move); - this.definitions.pop(); - } - this.subTurn--; + V.UndoOnBoard(this.board, move); + this.definitions.pop(); + this.subTurn = move.turn[1]; } else { this.epSquares.pop(); @@ -492,29 +544,41 @@ export class BarioRules extends ChessRules { else { if (!!move.position) { this.board = V.GetBoard(move.position); - this.reserve[color] = { - [V.ROOK]: 0, - [V.KNIGHT]: 0, - [V.BISHOP]: 0, - [V.QUEEN]: 0 - } + this.reserve = move.reserve; } } } } getComputerMove() { + let initMoves = this.getAllValidMoves(); + if (initMoves.length == 0) return null; + // Loop until valid move is found (no un-specifiable piece...) const color = this.turn; - // Just play at random for now... - let mvArray = []; - while (this.turn == color) { - const moves = this.getAllValidMoves(); - const choice = moves[randInt(moves.length)]; - mvArray.push(choice); - this.play(choice); + while (true) { + let moves = JSON.parse(JSON.stringify(initMoves)); + let mvArray = []; + let mv = null; + // Just play random moves (for now at least. TODO?) + while (moves.length > 0) { + mv = moves[randInt(moves.length)]; + mvArray.push(mv); + this.play(mv); + if (this.turn == color) { + if (this.subTurn == 1) moves = this.getAllValidMoves(); + else { + // subTurn == 2 + moves = this.filterValid( + this.getPotentialMovesFrom([mv.end.x, mv.end.y])); + } + } + else break; + } + const thisIsTheEnd = (this.turn != color); + for (let i = mvArray.length - 1; i >= 0; i--) this.undo(mvArray[i]); + if (thisIsTheEnd) return (mvArray.length > 1 ? mvArray : mvArray[0]); } - for (let i = mvArray.length - 1; i >= 0; i--) this.undo(mvArray[i]); - return (mvArray.length == 1? mvArray[0] : mvArray); + return null; //never reached } static get VALUES() { @@ -524,19 +588,16 @@ export class BarioRules extends ChessRules { // NOTE: evalPosition is wrong, but unused (random mover) getNotation(move) { - const end = { x: move.appear[0].x, y: move.appear[0].y }; + const end = { x: move.end.x, y: move.end.y }; const endSquare = V.CoordsToSquare(end); + if (move.appear.length == 0) + // Removal + return move.start.p.toUpperCase() + endSquare + "X"; if (move.vanish.length == 0) return "K@" + endSquare; const start = { x: move.vanish[0].x, y: move.vanish[0].y }; - if (start.x == end.x && start.y == end.y) { - // Something is specialized, or removed - const symbol = move.appear[0].p.toUpperCase(); - if (move.appear[0].c == move.vanish[0].c) - // Specialisation - return symbol + "@" + endSquare; - // Removal: - return symbol + endSquare + "X"; - } + if (start.x == end.x && start.y == end.y) + // Something is specialized + return move.appear[0].p.toUpperCase() + "@" + endSquare; // Normal move return super.getNotation(move); }