X-Git-Url: https://git.auder.net/img/rock_paper_scissors_lizard_spock.gif?a=blobdiff_plain;f=client%2Fsrc%2Fcomponents%2FBaseGame.vue;h=572c80ad4e018606c79467e56c8ff48c3c1e9295;hb=af34341d92d47d14f396e7f4adb81f2a7e9d9a61;hp=51d087a34b5ce8834a5de6da53725a56332bc6e4;hpb=616561273f216debfeab7f5fc532d0b0a8bc8e2d;p=vchess.git diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index 51d087a3..572c80ad 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -54,6 +54,7 @@ div#baseGame @showrules="showRules" @analyze="analyzePosition" @goto-move="gotoMove" + @reset-arrows="resetArrows" ) .clearer @@ -110,7 +111,7 @@ export default { : "" ); }, - // TODO: is it OK to pass "computed" as propoerties? + // 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 != "*" @@ -186,6 +187,10 @@ 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(); + }, showRules: function() { //this.$router.push("/variants/" + this.game.vname); window.open("#/variants/" + this.game.vname, "_blank"); //better @@ -200,17 +205,23 @@ export default { this.vr = new V(game.fenStart); const parsedFen = V.ParseFen(game.fenStart); const firstMoveColor = parsedFen.turn; - this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2); + this.firstMoveNumber = Math.floor(parsedFen.movesCount / 2) + 1; let L = this.moves.length; - this.moves.forEach(move => { + this.moves.forEach((move,idx) => { // Strategy working also for multi-moves: if (!Array.isArray(move)) move = [move]; - move.forEach((m,idx) => { + const Lm = move.length; + move.forEach((m,idxM) => { m.notation = this.vr.getNotation(m); m.unambiguous = V.GetUnambiguousNotation(m); this.vr.play(m); - if (idx < L - 1 && this.vr.getCheckSquares(this.vr.turn).length > 0) - m.notation += "+"; + const checkSquares = this.vr.getCheckSquares(); + if (checkSquares.length > 0) m.notation += "+"; + if (idx == L - 1 && idxM == Lm - 1) { + this.incheck = checkSquares; + const score = this.vr.getCurrentScore(); + if (["1-0", "0-1"].includes(score)) m.notation += "#"; + } }); }); if (firstMoveColor == "b") { @@ -224,27 +235,13 @@ export default { }); L++; } - this.positionCursorTo(this.moves.length - 1); - this.incheck = this.vr.getCheckSquares(this.vr.turn); - const score = this.vr.getCurrentScore(); - if (L > 0 && this.moves[L - 1].notation != "...") { - if (["1-0","0-1"].includes(score)) - this.moves[L - 1].notation += "#"; - else if (this.vr.getCheckSquares(this.vr.turn).length > 0) - this.moves[L - 1].notation += "+"; - } + this.positionCursorTo(L - 1); }, positionCursorTo: function(index) { this.cursor = index; - // Caution: last move in moves array might be a multi-move - if (index >= 0) { - if (Array.isArray(this.moves[index])) { - const L = this.moves[index].length; - this.lastMove = this.moves[index][L - 1]; - } else { - this.lastMove = this.moves[index]; - } - } else this.lastMove = null; + // Note: last move in moves array might be a multi-move + if (index >= 0) this.lastMove = this.moves[index]; + else this.lastMove = null; }, analyzePosition: function() { let newUrl = @@ -252,11 +249,8 @@ export default { this.game.vname + "/?fen=" + this.vr.getFen().replace(/ /g, "_"); - if (this.game.mycolor) - newUrl += "&side=" + this.game.mycolor; - // Open in same tab in live games (against cheating) - if (this.game.type == "live") this.$router.push(newUrl); - else window.open("#" + newUrl); + if (!!this.game.mycolor) newUrl += "&side=" + this.game.mycolor; + window.open("#" + newUrl); }, download: function() { const content = this.getPgn(); @@ -271,25 +265,38 @@ export default { let pgn = ""; pgn += '[Site "vchess.club"]\n'; pgn += '[Variant "' + this.game.vname + '"]\n'; - pgn += '[Date "' + getDate(new Date()) + '"]\n'; + const gdt = getDate(new Date(this.game.created || Date.now())); + pgn += '[Date "' + gdt + '"]\n'; pgn += '[White "' + this.game.players[0].name + '"]\n'; pgn += '[Black "' + this.game.players[1].name + '"]\n'; pgn += '[Fen "' + this.game.fenStart + '"]\n'; pgn += '[Result "' + this.game.score + '"]\n'; if (!!this.game.id) - pgn += '[URL "' + params.serverUrl + '/game/' + this.game.id + '"]\n'; + pgn += '[Url "' + params.serverUrl + '/game/' + this.game.id + '"]\n'; + if (!!this.game.cadence) + pgn += '[Cadence "' + this.game.cadence + '"]\n'; pgn += '\n'; for (let i = 0; i < this.moves.length; i += 2) { if (i > 0) pgn += " "; - pgn += (i/2+1) + "." + getFullNotation(this.moves[i]); + // Adjust dots notation for a better display: + let fullNotation = getFullNotation(this.moves[i]); + if (fullNotation == "...") fullNotation = ".."; + pgn += (i / 2 + this.firstMoveNumber) + "." + fullNotation; if (i+1 < this.moves.length) pgn += " " + getFullNotation(this.moves[i+1]); } pgn += "\n\n"; for (let i = 0; i < this.moves.length; i += 2) { - pgn += getFullNotation(this.moves[i], "unambiguous") + "\n"; - if (i+1 < this.moves.length) - pgn += getFullNotation(this.moves[i+1], "unambiguous") + "\n"; + const moveNumber = i / 2 + this.firstMoveNumber; + // Skip "dots move", useless for machine reading: + if (this.moves[i].notation != "...") { + pgn += moveNumber + ".w " + + getFullNotation(this.moves[i], "unambiguous") + "\n"; + } + if (i+1 < this.moves.length) { + pgn += moveNumber + ".b " + + getFullNotation(this.moves[i+1], "unambiguous") + "\n"; + } } return pgn; }, @@ -316,8 +323,14 @@ export default { this.autoplayLoop = null; } else { this.autoplay = true; - infinitePlay(); - this.autoplayLoop = setInterval(infinitePlay, 1500); + setTimeout( + () => { + infinitePlay(); + this.autoplayLoop = setInterval(infinitePlay, 1500); + }, + // Small delay otherwise the first move is played too fast + 500 + ); } }, // Animate an elementary move @@ -359,10 +372,15 @@ export default { // For Analyse mode: emitFenIfAnalyze: function() { if (this.game.mode == "analyze") { - this.$emit( - "fenchange", - !!this.lastMove ? this.lastMove.fen : this.game.fenStart - ); + let fen = this.game.fenStart; + if (!!this.lastMove) { + if (Array.isArray(this.lastMove)) { + const L = this.lastMove.length; + fen = this.lastMove[L-1].fen; + } + else fen = this.lastMove.fen; + } + this.$emit("fenchange", fen); } }, clickSquare: function(square) { @@ -374,6 +392,8 @@ export default { play: function(move, received, light, noemit) { // Freeze while choices are shown: if (this.$refs["board"].choices.length > 0) return; + // The board may show some the possible moves: (TODO: bad solution) + this.$refs["board"].resetCurrentAttempt(); if (!!noemit) { if (this.inPlay) { // Received moves in observed games can arrive too fast: @@ -387,8 +407,17 @@ export default { smove.notation = this.vr.getNotation(smove); smove.unambiguous = V.GetUnambiguousNotation(smove); this.vr.play(smove); - this.lastMove = smove; + if (!!this.lastMove) { + if (!Array.isArray(this.lastMove)) + 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; // Condition is "!navigate" but we mean "!this.autoplay" if (!navigate) { if (this.cursor < this.moves.length - 1) @@ -402,8 +431,7 @@ export default { const L = this.moves.length; if (!Array.isArray(this.moves[L-1])) this.$set(this.moves, L-1, [this.moves[L-1], smove]); - else - this.$set(this.moves, L-1, this.moves.concat([smove])); + else this.moves[L-1].push(smove); } }; const playMove = () => { @@ -417,7 +445,9 @@ export default { const initurn = this.vr.turn; (function executeMove() { const smove = move[moveIdx++]; - if (animate) { + // NOTE: condition "smove.start.x >= 0" required for Dynamo, + // because second move may be empty. + if (animate && smove.start.x >= 0) { self.animateMove(smove, () => { playSubmove(smove); if (moveIdx < move.length) @@ -434,10 +464,13 @@ export default { const computeScore = () => { const score = this.vr.getCurrentScore(); if (!navigate) { - if (["1-0","0-1"].includes(score)) - this.lastMove.notation += "#"; - else if (this.vr.getCheckSquares(this.vr.turn).length > 0) - this.lastMove.notation += "+"; + if (["1-0","0-1"].includes(score)) { + if (Array.isArray(this.lastMove)) { + const L = this.lastMove.length; + this.lastMove[L - 1].notation += "#"; + } + else this.lastMove.notation += "#"; + } } if (score != "*" && this.game.mode == "analyze") { const message = getScoreMessage(score); @@ -452,8 +485,6 @@ export default { if (!smove.fen) // NOTE: only FEN of last sub-move is required (=> setting it here) smove.fen = this.vr.getFen(); - // Is opponent in check? - this.incheck = this.vr.getCheckSquares(this.vr.turn); this.emitFenIfAnalyze(); this.inMultimove = false; this.score = computeScore(); @@ -483,8 +514,8 @@ export default { if (!Array.isArray(move)) move = [move]; for (let i=0; i < move.length; i++) this.vr.play(move[i]); if (!light) { - this.lastMove = move[move.length-1]; - this.incheck = this.vr.getCheckSquares(this.vr.turn); + this.lastMove = move; + this.incheck = this.vr.getCheckSquares(); this.score = computeScore(); this.emitFenIfAnalyze(); } @@ -511,7 +542,7 @@ export default { const L = this.moves.length; let move = this.moves[L-1]; if (!Array.isArray(move)) move = [move]; - for (let i=move.length -1; i >= 0; i--) this.vr.undo(move[i]); + for (let i = move.length - 1; i >= 0; i--) this.vr.undo(move[i]); this.moves.pop(); this.cursor--; this.inMultimove = false; @@ -525,9 +556,10 @@ export default { undo: function(move, light) { // Freeze while choices are shown: if (this.$refs["board"].choices.length > 0) return; + this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) { this.cancelCurrentMultimove(); - this.incheck = this.vr.getCheckSquares(this.vr.turn); + this.incheck = this.vr.getCheckSquares(); } else { if (!move) { const minCursor = @@ -537,17 +569,19 @@ export default { if (this.cursor < minCursor) return; //no more moves move = this.moves[this.cursor]; } + this.$refs["board"].resetCurrentAttempt(); undoMove(move, this.vr); if (light) this.cursor--; else { this.positionCursorTo(this.cursor - 1); - this.incheck = this.vr.getCheckSquares(this.vr.turn); + this.incheck = this.vr.getCheckSquares(); this.emitFenIfAnalyze(); } } }, gotoMove: function(index) { if (this.$refs["board"].choices.length > 0) return; + this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) this.cancelCurrentMultimove(); if (index == this.cursor) return; if (index < this.cursor) { @@ -561,11 +595,12 @@ export default { } // NOTE: next line also re-assign cursor, but it's very light this.positionCursorTo(index); - this.incheck = this.vr.getCheckSquares(this.vr.turn); + this.incheck = this.vr.getCheckSquares(); this.emitFenIfAnalyze(); }, gotoBegin: function() { if (this.$refs["board"].choices.length > 0) return; + this.$refs["board"].resetCurrentAttempt(); if (this.inMultimove) this.cancelCurrentMultimove(); const minCursor = this.moves.length > 0 && this.moves[0].notation == "..." @@ -573,11 +608,12 @@ export default { : 0; while (this.cursor >= minCursor) this.undo(null, null, "light"); this.lastMove = (minCursor == 1 ? this.moves[0] : null); - this.incheck = this.vr.getCheckSquares(this.vr.turn); + this.incheck = this.vr.getCheckSquares(); 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();