X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fcomponents%2FBaseGame.vue;h=61c67dece3d7555b76d4c1ddb1cfdb7e5e630ac2;hb=1b56b73614509d1dca8c4353f18fb78349940cf8;hp=228d9c4be4ab17923a40080d974d09470c23a7d9;hpb=130cca8b28bbba4fe586f4ddad22808d2aa9a537;p=vchess.git diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index 228d9c4b..61c67dec 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -40,7 +40,7 @@ div#baseGame img.inline(src="/images/icons/play.svg") button(@click="gotoEnd()") img.inline(src="/images/icons/fast-forward.svg") - p(v-show="showFen") {{ (!!vr ? vr.getFen() : "") }} + p#fenAnalyze(v-show="showFen") {{ (!!vr ? vr.getFen() : "") }} #movesList MoveList( :show="showMoves" @@ -51,11 +51,12 @@ div#baseGame :firstNum="firstMoveNumber" :moves="moves" :cursor="cursor" + :vname="game.vname" @download="download" @showrules="showRules" @analyze="toggleAnalyze" @goto-move="gotoMove" - @reset-arrows="resetArrows" + @redraw-board="redrawBoard" ) .clearer @@ -86,6 +87,7 @@ export default { endgameMessage: "", orientation: "w", mode: "", + gameMode: "", score: "*", //'*' means 'unfinished' moves: [], cursor: -1, //index of the move just played @@ -94,7 +96,6 @@ export default { incheck: [], //for Board inMultimove: false, autoplay: false, - autoplayLoop: null, inPlay: false, stackToPlay: [] }; @@ -106,7 +107,7 @@ export default { return this.st.tr[ (this.vr.turn == 'w' ? "White" : "Black") + " to move"]; } - // Cannot flip: racing king or circular chess + // Cannot flip (racing king or circular chess), or Monochrome return ( this.vr.movesCount == 0 && this.game.mycolor == "w" ? this.st.tr["It's your turn!"] @@ -122,19 +123,26 @@ export default { // TODO: is it OK to pass "computed" as properties? // Also, some are seemingly not recomputed when vr is initialized. showMoves: function() { - return this.game.score != "*" - ? "all" - : (!!this.vr ? this.vr.showMoves : "none"); + return ( + !!this.game.score && this.game.score != "*" + ? "all" + : (!!this.vr ? this.vr.showMoves : "none") + ); }, showTurn: function() { return ( - this.game.score == '*' && - !!this.vr && (this.vr.showMoves != "all" || !this.vr.canFlip) + !!this.game.score && this.game.score == '*' && + !!this.vr && + ( + this.vr.showMoves != "all" || + !this.vr.canFlip || + this.vr.showFirstTurn + ) ); }, canAnalyze: function() { return ( - this.game.mode != "analyze" && + (!this.game.mode || this.game.mode != "analyze") && !!this.vr && this.vr.canAnalyze ); }, @@ -143,8 +151,8 @@ export default { }, allowDownloadPGN: function() { return ( - this.game.score != "*" || - (!!this.vr && this.vr.showMoves == "all") + (!!this.game.score && this.game.score != "*") || + (!!this.vr && !this.vr.someHiddenMoves) ); } }, @@ -164,7 +172,8 @@ export default { .addEventListener("click", processModalClick); }, beforeDestroy: function() { - if (!!this.autoplayLoop) clearInterval(this.autoplayLoop); + // TODO: probably not required + this.autoplay = false; }, methods: { focusBg: function() { @@ -195,9 +204,8 @@ export default { if (e.deltaY < 0) this.undo(); else if (e.deltaY > 0) this.play(); }, - resetArrows: function() { - // TODO: make arrows scale with board, and remove this - this.$refs["board"].cancelResetArrows(); + redrawBoard: function() { + this.$refs["board"].re_setDrawings(); }, showRules: function() { // The button is here only on Game page: @@ -212,6 +220,12 @@ export default { this.moves = JSON.parse(JSON.stringify(game.moves || [])); // Post-processing: decorate each move with notation and FEN this.vr = new V(game.fenStart); + this.inMultimove = false; //in case of + if (!!this.$refs["board"]) + // Also in case of: + this.$refs["board"].resetCurrentAttempt(); + let analyseBtn = document.getElementById("analyzeBtn"); + if (!!analyseBtn) analyseBtn.classList.remove("active"); const parsedFen = V.ParseFen(game.fenStart); const firstMoveColor = parsedFen.turn; this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2) + 1; @@ -219,21 +233,32 @@ export default { this.moves.forEach((move,idx) => { // Strategy working also for multi-moves: if (!Array.isArray(move)) move = [move]; - const Lm = move.length; - move.forEach((m,idxM) => { + move.forEach(m => { m.notation = this.vr.getNotation(m); m.unambiguous = V.GetUnambiguousNotation(m); this.vr.play(m); - const checkSquares = this.vr.getCheckSquares(); - if (checkSquares.length > 0) m.notation += "+"; - if (idxM == Lm - 1) m.fen = this.vr.getFen(); - if (idx == L - 1 && idxM == Lm - 1) { - this.incheck = checkSquares; - const score = this.vr.getCurrentScore(); - if (["1-0", "0-1"].includes(score)) m.notation += "#"; - } }); + const Lm = move.length; + move[Lm - 1].fen = this.vr.getFen(); + if (idx < L - 1 && this.vr.getCheckSquares().length > 0) + move[Lm - 1].notation += "+"; }); + this.incheck = this.vr.getCheckSquares(); + this.score = this.vr.getCurrentScore(); + if (L >= 1) { + const move = + !Array.isArray(this.moves[L - 1]) + ? [this.moves[L - 1]] + : this.moves[L - 1]; + const Lm = move.length; + if (["1-0", "0-1"].includes(this.score)) move[Lm - 1].notation += "#"; + else if (this.incheck.length > 0) move[Lm - 1].notation += "+"; + } + if (this.score != '*') { + // Show score on screen + const message = getScoreMessage(this.score); + this.showEndgameMsg(this.score + " . " + this.st.tr[message]); + } if (firstMoveColor == "b") { // 'start' & 'end' is required for Board component this.moves.unshift({ @@ -254,17 +279,26 @@ export default { else this.lastMove = null; }, toggleAnalyze: function() { + // Freeze while choices are shown (and autoplay has priority) + if ( + this.inPlay || + this.$refs["board"].choices.length > 0 || + this.autoplay + ) { + return; + } if (this.mode != "analyze") { // Enter analyze mode: this.gameMode = this.mode; //was not 'analyze' this.mode = "analyze"; + if (this.inMultimove) this.cancelCurrentMultimove(); this.gameCursor = this.cursor; this.gameMoves = JSON.parse(JSON.stringify(this.moves)); document.getElementById("analyzeBtn").classList.add("active"); } else { // Exit analyze mode: - this.mode = this.gameMode ; + this.mode = this.gameMode; this.cursor = this.gameCursor; this.moves = this.gameMoves; let fen = this.game.fenStart; @@ -274,7 +308,11 @@ export default { fen = mv[mv.length-1].fen; } this.vr = new V(fen); + this.inMultimove = false; //in case of + this.$refs["board"].resetCurrentAttempt(); //also in case of this.incheck = this.vr.getCheckSquares(); + if (this.cursor >= 0) this.lastMove = this.moves[this.cursor]; + else this.lastMove = null; document.getElementById("analyzeBtn").classList.remove("active"); } }, @@ -331,32 +369,15 @@ export default { document.getElementById("modalEog").checked = true; }, runAutoplay: function() { - const infinitePlay = () => { - if (this.cursor == this.moves.length - 1) { - clearInterval(this.autoplayLoop); - this.autoplayLoop = null; - this.autoplay = false; - return; - } - if (this.inPlay || this.inMultimove) - // Wait next tick - return; - this.play(); - }; if (this.autoplay) { this.autoplay = false; - clearInterval(this.autoplayLoop); - this.autoplayLoop = null; - } else { + if (this.stackToPlay.length > 0) + // Move(s) arrived in-between + this.play(this.stackToPlay.pop(), "received"); + } + else if (this.cursor < this.moves.length - 1) { this.autoplay = true; - setTimeout( - () => { - infinitePlay(); - this.autoplayLoop = setInterval(infinitePlay, 1500); - }, - // Small delay otherwise the first move is played too fast - 500 - ); + this.play(null, null, null, "autoplay"); } }, // Animate an elementary move @@ -411,14 +432,24 @@ export default { }, clickSquare: function(square) { // Some variants make use of a single click at specific times: - const move = this.vr.doClick(square); - if (!!move) this.play(move); + const move_s = this.vr.doClick(square); + if (!!move_s) { + if (!Array.isArray(move_s)) this.play(move_s); + else this.$refs["board"].choices = move_s; + } }, // "light": if gotoMove() or gotoEnd() - play: function(move, received, light, noemit) { + play: function(move, received, light, autoplay) { // Freeze while choices are shown: - if (this.$refs["board"].choices.length > 0) return; + if ( + !!this.$refs["board"].selectedPiece || + this.$refs["board"].choices.length > 0 + ) { + return; + } const navigate = !move; + // Forbid navigation during autoplay: + if (navigate && this.autoplay && !autoplay) return; // Forbid playing outside analyze mode, except if move is received. // Sufficient condition because Board already knows which turn it is. if ( @@ -430,24 +461,19 @@ export default { return; } if (!!received) { - - if (this.mode == "analyze") { console.log("received move"); - console.log(move); } - + if (this.autoplay || this.inPlay) { + // Received moves while autoplaying are stacked, + // and in observed games they could arrive too fast: + this.stackToPlay.unshift(move); + return; + } if (this.mode == "analyze") this.toggleAnalyze(); if (this.cursor < this.moves.length - 1) // To play a received move, cursor must be at the end of the game: this.gotoEnd(); - } - if (!!noemit) { - if (this.inPlay) { - // Received moves in observed games can arrive too fast: - this.stackToPlay.unshift(move); - return; - } this.inPlay = true; } - // The board may show some the possible moves: (TODO: bad solution) + // The board may show some possible moves: (TODO: bad solution) this.$refs["board"].resetCurrentAttempt(); const playSubmove = (smove) => { smove.notation = this.vr.getNotation(smove); @@ -458,9 +484,6 @@ export default { this.lastMove = [this.lastMove, smove]; else this.lastMove.push(smove); } - // Is opponent (or me) in check? - this.incheck = this.vr.getCheckSquares(); - if (this.incheck.length > 0) smove.notation += "+"; if (!this.inMultimove) { // First sub-move: this.lastMove = smove; @@ -492,15 +515,12 @@ export default { (function executeMove() { const smove = move[moveIdx++]; // NOTE: condition "smove.start.x >= 0" required for Dynamo, - // because second move may be empty. - if (animate && smove.start.x >= 0) { + // because second move may be empty. noHighlight condition + // is used at least for Chakart. + if (animate && smove.start.x >= 0 && !smove.end.noHighlight) { self.animateMove(smove, () => { playSubmove(smove); - -console.log(moveIdx + " " + move.length); - - if (moveIdx < move.length) - setTimeout(executeMove, 500); + if (moveIdx < move.length) setTimeout(executeMove, 500); else afterMove(smove, initurn); }); } else { @@ -513,7 +533,7 @@ console.log(moveIdx + " " + move.length); const computeScore = () => { const score = this.vr.getCurrentScore(); if (!navigate) { - if (["1-0","0-1"].includes(score)) { + if (["1-0", "0-1"].includes(score)) { if (Array.isArray(this.lastMove)) { const L = this.lastMove.length; this.lastMove[L - 1].notation += "#"; @@ -521,37 +541,45 @@ console.log(moveIdx + " " + move.length); else this.lastMove.notation += "#"; } } - if (score != "*" && this.mode == "analyze") { + if (score != "*" && ["analyze", "versus"].includes(this.mode)) { const message = getScoreMessage(score); - // Just show score on screen (allow undo) + // Show score on screen this.showEndgameMsg(score + " . " + this.st.tr[message]); } return score; }; const afterMove = (smove, initurn) => { if (this.vr.turn != initurn) { - -console.log(smove); - // Turn has changed: move is complete if (!smove.fen) // NOTE: only FEN of last sub-move is required (=> setting it here) smove.fen = this.vr.getFen(); this.emitFenIfAnalyze(); this.inMultimove = false; + this.incheck = this.vr.getCheckSquares(); + if (this.incheck.length > 0) smove.notation += "+"; this.score = computeScore(); + if (this.autoplay) { + if (this.cursor < this.moves.length - 1) + setTimeout(() => this.play(null, null, null, "autoplay"), 1000); + else { + this.autoplay = false; + if (this.stackToPlay.length > 0) + // Move(s) arrived in-between + this.play(this.stackToPlay.pop(), "received"); + } + } if (this.mode != "analyze" && !navigate) { - if (!noemit && this.mode != "analyze") { + if (!received) { // Post-processing (e.g. computer play). const L = this.moves.length; - // NOTE: always emit the score, even in unfinished, - // to tell Game::processMove() that it's not a received move. + // NOTE: always emit the score, even in unfinished this.$emit("newmove", this.moves[L-1], { score: this.score }); } else { this.inPlay = false; if (this.stackToPlay.length > 0) // Move(s) arrived in-between - this.play(this.stackToPlay.pop(), received, light, noemit); + this.play(this.stackToPlay.pop(), "received"); } } } @@ -593,12 +621,19 @@ console.log(smove); }, // "light": if gotoMove() or gotoBegin() undo: function(move, light) { - // Freeze while choices are shown: - if (this.$refs["board"].choices.length > 0) return; + if ( + this.autoplay || + !!this.$refs["board"].selectedPiece || + this.$refs["board"].choices.length > 0 + ) { + return; + } this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) { this.cancelCurrentMultimove(); this.incheck = this.vr.getCheckSquares(); + if (this.cursor >= 0) this.lastMove = this.moves[this.cursor]; + else this.lastMove = null; } else { if (!move) { const minCursor = @@ -619,7 +654,13 @@ console.log(smove); } }, gotoMove: function(index) { - if (this.$refs["board"].choices.length > 0) return; + if ( + this.autoplay || + !!this.$refs["board"].selectedPiece || + this.$refs["board"].choices.length > 0 + ) { + return; + } this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) this.cancelCurrentMultimove(); if (index == this.cursor) return; @@ -638,7 +679,13 @@ console.log(smove); this.emitFenIfAnalyze(); }, gotoBegin: function() { - if (this.$refs["board"].choices.length > 0) return; + if ( + this.autoplay || + !!this.$refs["board"].selectedPiece || + this.$refs["board"].choices.length > 0 + ) { + return; + } this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) this.cancelCurrentMultimove(); const minCursor = @@ -651,11 +698,8 @@ console.log(smove); this.emitFenIfAnalyze(); }, gotoEnd: function() { - if (this.$refs["board"].choices.length > 0) return; - this.$refs["board"].resetCurrentAttempt(); if (this.cursor == this.moves.length - 1) return; this.gotoMove(this.moves.length - 1); - this.emitFenIfAnalyze(); }, flip: function() { if (this.$refs["board"].choices.length > 0) return; @@ -668,6 +712,7 @@ console.log(smove);