X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fcomponents%2FBaseGame.vue;h=b5a82dfbfda16cbcc9fb462f560fb233ce6807ea;hb=21baf44462799a80c4b1cd772de8c3c4fa0b3d37;hp=ceadcd3a6762c06df1510f2957d77ae090bdedfa;hpb=a6088c906bbe6fae95707dc7028e45023fe39981;p=vchess.git diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index ceadcd3a..b5a82dfb 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -6,11 +6,13 @@ .card.smallpad.small-modal.text-center label.modal-close(for="modalEog") h3#eogMessage.section {{ endgameMessage }} - Board(:vr="vr" :last-move="lastMove" :analyze="analyze" :user-color="mycolor" - :orientation="orientation" :vname="variant.name" @play-move="play") + // TODO: or "BoardHex" if this.game.vname in "Hexagonal..." + Board(:vr="vr" :last-move="lastMove" :analyze="analyze" + :user-color="game.mycolor" :orientation="orientation" + :vname="game.vname" @play-move="play") .button-group - button(@click="play") Play - button(@click="undo") Undo + button(@click="() => play()") Play + button(@click="() => undo()") Undo button(@click="flip") Flip button(@click="gotoBegin") GotoBegin button(@click="gotoEnd") GotoEnd @@ -20,7 +22,8 @@ a#download(href="#") .button-group button#downloadBtn(@click="download") {{ st.tr["Download PGN"] }} - button Import game + // TODO: Import game button copy game locally in IndexedDB + //button Import game //MoveList(v-if="showMoves" :moves="moves" :cursor="cursor" @goto-move="gotoMove") @@ -30,6 +33,7 @@ import Board from "@/components/Board.vue"; //import MoveList from "@/components/MoveList.vue"; import { store } from "@/store"; import { getSquareId } from "@/utils/squareId"; +import { getDate } from "@/utils/datetime"; export default { name: 'my-base-game', @@ -37,50 +41,62 @@ export default { Board, //MoveList, }, - props: ["variant","analyze","players"], + // "vr": VariantRules object, describing the game state + rules + props: ["vr","game"], data: function() { return { st: store.state, - vr: null, //VariantRules object, describing the game state + rules + // NOTE: all following variables must be reset at the beginning of a game endgameMessage: "", orientation: "w", score: "*", //'*' means 'unfinished' - // userColor: given by gameId, or fen in problems mode (if no game Id)... - mycolor: "w", - fenStart: "", - moves: [], //all moves played in current game + moves: [], cursor: -1, //index of the move just played lastMove: null, }; }, + watch: { + // game initial FEN changes when a new game starts + "game.fenStart": function() { + this.re_setVariables(); + }, + }, computed: { showMoves: function() { return true; //return window.innerWidth >= 768; }, showFen: function() { - return this.variant.name != "Dark" || this.score != "*"; + return this.game.vname != "Dark" || this.score != "*"; + }, + analyze: function() { + return this.game.mode == "analyze" || this.game.score != "*"; }, }, + created: function() { + if (!!this.game.fenStart) + this.re_setVariables(); + }, methods: { - setEndgameMessage: function(score) { - let eogMessage = "Undefined"; - switch (score) - { - case "1-0": - eogMessage = translations["White win"]; - break; - case "0-1": - eogMessage = translations["Black win"]; - break; - case "1/2": - eogMessage = translations["Draw"]; - break; - case "?": - eogMessage = "Unfinished"; - break; - } - this.endgameMessage = eogMessage; + re_setVariables: function() { + this.endgameMessage = ""; + this.orientation = this.game.mycolor || "w"; //default orientation for observed games + this.score = this.game.score || "*"; //mutable (if initially "*") + this.moves = JSON.parse(JSON.stringify(this.game.moves || [])); + // Post-processing: decorate each move with color + current FEN: + // (to be able to jump to any position quickly) + let vr_tmp = new V(this.game.fenStart); //vr is already at end of game + this.moves.forEach(move => { + // NOTE: this is doing manually what play() function below achieve, + // but in a lighter "fast-forward" way + move.color = vr_tmp.turn; + move.notation = vr_tmp.getNotation(move); + vr_tmp.play(move); + move.fen = vr_tmp.getFen(); + }); + const L = this.moves.length; + this.cursor = L-1; + this.lastMove = (L > 0 ? this.moves[L-1] : null); }, download: function() { const content = this.getPgn(); @@ -93,11 +109,11 @@ export default { getPgn: function() { let pgn = ""; pgn += '[Site "vchess.club"]\n'; - pgn += '[Variant "' + this.variant.name + '"]\n'; + pgn += '[Variant "' + this.game.vname + '"]\n'; pgn += '[Date "' + getDate(new Date()) + '"]\n'; - pgn += '[White "' + this.players[0] + '"]\n'; - pgn += '[Black "' + this.players[1] + '"]\n'; - pgn += '[Fen "' + this.fenStart + '"]\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.score + '"]\n\n'; let counter = 1; let i = 0; @@ -108,23 +124,44 @@ export default { { let move = ""; while (i < this.moves.length && this.moves[i].color == color) - move += this.moves[i++].notation[0] + ","; + move += this.moves[i++].notation + ","; move = move.slice(0,-1); //remove last comma - pgn += move + (i < this.moves.length-1 ? " " : ""); + pgn += move + (i < this.moves.length ? " " : ""); } } return pgn + "\n"; }, - showScoreMsg: function(score) { - this.setEndgameMessage(score); - let modalBox = document.getElementById("modal-eog"); + getScoreMessage: function(score) { + let eogMessage = "Undefined"; + switch (score) + { + case "1-0": + eogMessage = this.st.tr["White win"]; + break; + case "0-1": + eogMessage = this.st.tr["Black win"]; + break; + case "1/2": + eogMessage = this.st.tr["Draw"]; + break; + case "?": + eogMessage = this.st.tr["Unfinished"]; + break; + } + return eogMessage; + }, + showEndgameMsg: function(message) { + this.endgameMessage = message; + let modalBox = document.getElementById("modalEog"); modalBox.checked = true; setTimeout(() => { modalBox.checked = false; }, 2000); }, - endGame: function(score) { + endGame: function(score, message) { this.score = score; - this.showScoreMsg(score); - this.$emit("game-over"); + if (!message) + message = this.getScoreMessage(score); + this.showEndgameMsg(score + " . " + message); + this.$emit("gameover", score); }, animateMove: function(move) { let startSquare = document.getElementById(getSquareId(move.start)); @@ -154,11 +191,11 @@ export default { this.play(move); }, 250); }, - play: function(move, programmatic) { - let navigate = !move; + play: function(move, receive, noanimate) { + const navigate = !move; // Forbid playing outside analyze mode when cursor isn't at moves.length-1 // (except if we receive opponent's move, human or computer) - if (!navigate && !this.analyze && !programmatic + if (!navigate && !this.analyze && !receive && this.cursor < this.moves.length-1) { return; @@ -169,56 +206,55 @@ export default { return; //no more moves move = this.moves[this.cursor+1]; } - if (!!programmatic) //computer or (remote) human opponent + if (!!receive && !noanimate) //opponent move, variant != "Dark" { if (this.cursor < this.moves.length-1) this.gotoEnd(); //required to play the move return this.animateMove(move); } - // Not programmatic, or animation is over - if (!move.notation) - move.notation = this.vr.getNotation(move); - if (!move.color) + if (!navigate) + { move.color = this.vr.turn; + move.notation = this.vr.getNotation(move); + } + // Not programmatic, or animation is over this.vr.play(move); this.cursor++; this.lastMove = move; - if (!move.fen) - move.fen = this.vr.getFen(); if (this.st.settings.sound == 2) new Audio("/sounds/move.mp3").play().catch(err => {}); - // Send the move to web worker (including his own moves) - this.compWorker.postMessage(["newmove",move]); - if (!navigate && (this.score == "*" || this.analyze)) + if (!navigate) { - // Stack move on movesList at current cursor - if (this.cursor == this.moves.length) - this.moves.push(move); - else - this.moves = this.moves.slice(0,this.cursor).concat([move]); + move.fen = this.vr.getFen(); + if (this.score == "*" || this.analyze) + { + // Stack move on movesList at current cursor + if (this.cursor == this.moves.length) + this.moves.push(move); + else + this.moves = this.moves.slice(0,this.cursor).concat([move]); + } } - // Is opponent in check? + // Is opponent in check? (TODO: generalize, find all check squares) this.incheck = this.vr.getCheckSquares(this.vr.turn); const score = this.vr.getCurrentScore(); - if (score != "*") + if (score != "*") //TODO: generalize score for 3 or 4 players { if (!this.analyze) this.endGame(score); - else //just show score on screen (allow undo) - this.showScoreMsg(score); + else + { + // Just show score on screen (allow undo) + const message = this.getScoreMessage(score); + this.showEndgameMsg(score + " . " + message); + } } - // subTurn condition for Marseille (and Avalanche) rules - else if ((this.mode == "computer" && (!this.vr.subTurn || this.vr.subTurn <= 1)) - && (this.subMode == "auto" || this.vr.turn != this.mycolor)) - { - this.playComputerMove(); + if (!this.analyze) { console.log("EMIT NEWMOVE"); + this.$emit("newmove", move); //post-processing (e.g. computer play) } - // https://vuejs.org/v2/guide/list.html#Caveats (also for undo) - //if (navigate) - // this.$children[0].$forceUpdate(); //TODO!? }, undo: function(move) { - let navigate = !move; + const navigate = !move; if (navigate) { if (this.cursor < 0) @@ -231,18 +267,16 @@ export default { if (this.st.settings.sound == 2) new Audio("/sounds/undo.mp3").play().catch(err => {}); this.incheck = this.vr.getCheckSquares(this.vr.turn); - if (navigate) - this.$children[0].$forceUpdate(); //TODO!? - else if (this.analyze) //TODO: can this happen? + if (!navigate) this.moves.pop(); }, gotoMove: function(index) { - this.vr = new V(this.moves[index].fen); + this.vr.re_init(this.moves[index].fen); this.cursor = index; this.lastMove = this.moves[index]; }, gotoBegin: function() { - this.vr = new V(this.fenStart); + this.vr.re_init(this.game.fenStart); this.cursor = -1; this.lastMove = null; },