X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fvariants%2FSynchrone2.js;h=00d68ad7597f7e7a32177e3bf81eb57db7a22a09;hb=aa32568ef0c9fff28d17d19588b53ee049f0e1dc;hp=7f623982d0f5ca7283e27b7ab430b57e12ea3ba6;hpb=67d5ce20f36e7a85636dd357e099dde82cc94dbd;p=vchess.git diff --git a/client/src/variants/Synchrone2.js b/client/src/variants/Synchrone2.js index 7f623982..00d68ad7 100644 --- a/client/src/variants/Synchrone2.js +++ b/client/src/variants/Synchrone2.js @@ -1,4 +1,4 @@ -import { ChessRules } from "@/base_rules"; +import { ChessRules, Move } from "@/base_rules"; import { Synchrone1Rules } from "@/variants/Synchrone1"; import { randInt } from "@/utils/alea"; @@ -16,7 +16,7 @@ export class Synchrone2Rules extends Synchrone1Rules { if (!Synchrone1Rules.IsGoodFen(fen)) return false; const fenParsed = V.ParseFen(fen); // 5) Check initFen (not really... TODO?) - if (!fenParsed.initFen || fenParsed.initFen == "-") return false; + if (!fenParsed.initFen) return false; return true; } @@ -32,18 +32,16 @@ export class Synchrone2Rules extends Synchrone1Rules { } getInitfenFen() { - if (!this.whiteMove) return "-"; - return JSON.stringify({ - start: this.whiteMove.start, - end: this.whiteMove.end, - appear: this.whiteMove.appear, - vanish: this.whiteMove.vanish - }); + const L = this.initfenStack.length; + return L > 0 ? this.initfenStack[L-1] : "-"; } getFen() { return ( - super.getFen() + " " + + super.getBaseFen() + " " + + super.getTurnFen() + " " + + this.movesCount + " " + + super.getFlagsFen() + " " + this.getInitfenFen() + " " + this.getWhitemoveFen() ); @@ -52,7 +50,7 @@ export class Synchrone2Rules extends Synchrone1Rules { static GenRandInitFen(randomness) { const res = ChessRules.GenRandInitFen(randomness); // Add initFen field: - return res.slice(0, -1) + " " + res.split(' ')[1] + " -"; + return res.slice(0, -1) + res.split(' ')[0] + " -"; } setOtherVariables(fen) { @@ -64,25 +62,133 @@ export class Synchrone2Rules extends Synchrone1Rules { parsedFen.whiteMove != "-" ? JSON.parse(parsedFen.whiteMove) : null; - // And initFen (not empty) - this.initFen = parsedFen.initFen; + // And initFen (could be empty) + this.initfenStack = []; + if (parsedFen.initFen != "-") this.initfenStack.push(parsedFen.initFen); } getPotentialMovesFrom([x, y]) { if (this.movesCount % 4 <= 1) return super.getPotentialMovesFrom([x, y]); - // TODO: either add a "blackMove' field in FEN (bof...), - // or write an helper function to detect from diff positions, - // which piece moved (if not disappeared!), which moves are valid. - // + do not forget pass move (king 2 king): always possible at stage 2. - return []; + // Diff current and old board to know which pieces have moved, + // and to deduce possible moves at stage 2. + const L = this.initfenStack.length; + let initBoard = V.GetBoard(this.initfenStack[L-1]); + let appeared = []; + const c = this.turn; + const oppCol = V.GetOppCol(c); + for (let i=0; i<8; i++) { + for (let j=0; j<8; j++) { + if (this.board[i][j] != initBoard[i][j]) { + if (this.board[i][j] != V.EMPTY) { + const color = this.board[i][j].charAt(0); + appeared.push({ c: color, x: i, y: j }); + // Pawns capture in diagonal => the following fix. + // (Other way would be to redefine getPotentialPawnMoves()...) + if (color == oppCol) initBoard[i][j] = this.board[i][j]; + } + } + } + } + const saveBoard = this.board; + this.board = initBoard; + const movesInit = super.getPotentialMovesFrom([x, y]); + this.board = saveBoard; + const target = appeared.find(a => a.c == oppCol); + let movesNow = super.getPotentialMovesFrom([x, y]).filter(m => { + return ( + m.end.x == target.x && + m.end.y == target.y && + movesInit.some(mi => mi.end.x == m.end.x && mi.end.y == m.end.y) + ); + }); + const passTarget = + (x != this.kingPos[c][0] || y != this.kingPos[c][1]) ? c : oppCol; + movesNow.push( + new Move({ + start: { x: x, y: y }, + end: { + x: this.kingPos[passTarget][0], + y: this.kingPos[passTarget][1] + }, + appear: [], + vanish: [] + }) + ); + return movesNow; + } + + filterValid(moves) { + if (moves.length == 0) return []; + if (moves.length == 1 && moves[0].vanish.length == 0) return moves; + // filterValid can be called when it's "not our turn": + const color = moves.find(m => m.vanish.length > 0).vanish[0].c; + return moves.filter(m => { + if (m.vanish.length == 0) return true; + const piece = m.vanish[0].p; + if (piece == V.KING) { + this.kingPos[color][0] = m.appear[0].x; + this.kingPos[color][1] = m.appear[0].y; + } + V.PlayOnBoard(this.board, m); + let res = !this.underCheck(color); + V.UndoOnBoard(this.board, m); + if (piece == V.KING) this.kingPos[color] = [m.start.x, m.start.y]; + return res; + }); + } + + getPossibleMovesFrom([x, y]) { + return this.filterValid(this.getPotentialMovesFrom([x, y])); } play(move) { + if (this.movesCount % 4 == 0) this.initfenStack.push(this.getBaseFen()); move.flags = JSON.stringify(this.aggregateFlags()); // Do not play on board (would reveal the move...) this.turn = V.GetOppCol(this.turn); this.movesCount++; - this.postPlay(move); + if ([0, 3].includes(this.movesCount % 4)) this.postPlay(move); + else super.postPlay(move); //resolve synchrone move + } + + postPlay(move) { + if (this.turn == 'b') { + // NOTE: whiteMove is used read-only, so no need to copy + this.whiteMove = move; + return; + } + + // A full "deterministic" turn just ended: no need to resolve + const smove = { + appear: this.whiteMove.appear.concat(move.appear), + vanish: this.whiteMove.vanish.concat(move.vanish) + }; + V.PlayOnBoard(this.board, smove); + move.whiteMove = this.whiteMove; //for undo + this.whiteMove = null; + + // Update king position + flags + let kingAppear = { 'w': false, 'b': false }; + for (let i=0; i < smove.appear.length; i++) { + if (smove.appear[i].p == V.KING) { + const c = smove.appear[i].c; + kingAppear[c] = true; + this.kingPos[c][0] = smove.appear[i].x; + this.kingPos[c][1] = smove.appear[i].y; + } + } + for (let i = 0; i < smove.vanish.length; i++) { + if (smove.vanish[i].p == V.KING) { + const c = smove.vanish[i].c; + if (!kingAppear[c]) { + this.kingPos[c][0] = -1; + this.kingPos[c][1] = -1; + } + break; + } + } + super.updateCastleFlags(smove); + move.smove = smove; } undo(move) { @@ -92,12 +198,13 @@ export class Synchrone2Rules extends Synchrone1Rules { V.UndoOnBoard(this.board, move.smove); this.turn = V.GetOppCol(this.turn); this.movesCount--; - this.postUndo(move); + if (this.movesCount % 4 == 0) this.initfenStack.pop(); + if (move.vanish.length > 0) super.postUndo(move); } getCurrentScore() { if (this.movesCount % 4 != 0) - // Turn (2 x white + black) not over yet + // Turn (2 x [white + black]) not over yet return "*"; // Was a king captured? if (this.kingPos['w'][0] < 0) return "0-1"; @@ -119,4 +226,9 @@ export class Synchrone2Rules extends Synchrone1Rules { return (whiteCanMove ? "1-0" : "0-1"); } + getNotation(move) { + if (move.vanish.length == 0) return "pass"; + return super.getNotation(move); + } + };