diff --git a/frontend/static/js/api/game/tictactoe/TicTacToeGame.js b/frontend/static/js/api/game/tictactoe/TicTacToeGame.js index 73b5a56..49d6d18 100644 --- a/frontend/static/js/api/game/tictactoe/TicTacToeGame.js +++ b/frontend/static/js/api/game/tictactoe/TicTacToeGame.js @@ -18,12 +18,12 @@ class TicTacToe this.canvas = canvas this.context = this.canvas.getContext("2d"); this.sign; + this.currentMorpion = 4; this.turn; } async init() { - console.log(this.game_id); await this.game.join(); this.canvas.addEventListener("mousedown", (event, morpion = this) => this.onClick(event, morpion)); } @@ -37,22 +37,46 @@ class TicTacToe async onReceive(messageData) { console.log(messageData) - if (messageData.detail == "x" || messageData.detail == "o") + switch (messageData.detail) { - this.sign = messageData.detail; - this.turn = messageData.detail == "x"; - } - else if (messageData.detail == "game_start") - this.game.started = true; - else if (messageData.targetMorpion && messageData.targetCase) - { - this.map[messageData.targetMorpion][messageData.targetCase] = (this.sign == "x") ? 1 : 0; - this.printSign(messageData.targetMorpion, messageData.targetCase, (this.sign == "x") ? "o" : "x"); - if (this.checkWin() != -1) - printWin(); + case 'x': + case 'o': + this.sign = messageData.detail; + this.turn = messageData.detail == "x"; + if (this.turn) + this.setOutline(4, false); + break; + + case 'game_start': + this.game.started = true; + this.game.finished = false; + break; + + case 'game_move': + this.map[messageData.targetMorpion][messageData.targetCase] = (this.sign == "x") ? 1 : 0; + this.printSign(messageData.targetMorpion, messageData.targetCase, (this.sign == "x") ? "o" : "x"); + this.setOutline(this.currentMorpion, false); + break; + + case 'game_end': + this.game.finished = true; + this.canvas.removeEventListener("mousedown", (event, morpion = this) => this.onClick(event, morpion)); + this.printWin(messageData.winning_sign); + break; } } + printWin(winning_sign) + { + this.context.beginPath(); + this.context.fillStyle = "white"; + this.context.fillRect(this.width / 2 - 200, this.height - this.gap + 10, 400, 80); + this.context.closePath(); + this.context.beginPath(); + this.context.fillStyle = (winning_sign == "o") ? "red" : "green"; + this.context.fillText((winning_sign == "o") ? "Winner is : O" : "Winner is : X", this.width / 2 - 30, this.height - this.gap / 2, 140); + this.context.closePath(); + } checkWin() { for (let i = 0; i < 9; i++) @@ -85,6 +109,10 @@ class TicTacToe let y = event.offsetY; let targetMorpion, targetCase; + if (this.game.finished) + { + return; + } targetMorpion = morpion.findPlace(x, this) + morpion.findPlace(y, this) * 3; if (morpion.findPlace(x, this) < 0 || morpion.findPlace(y, this) < 0) return -1; @@ -92,8 +120,8 @@ class TicTacToe if (morpion.checkCase(targetMorpion, targetCase)) { + morpion.setOutline(this.currentMorpion, true); morpion.sendCase(targetMorpion, targetCase); - morpion.setOutline(); } else morpion.incorrectCase(); @@ -101,19 +129,20 @@ class TicTacToe checkCase(targetMorpion, targetCase) { - return (this.map[targetMorpion][targetCase] == -1 && this.turn == true); + return (this.map[targetMorpion][targetCase] == -1 && this.turn == true && targetMorpion == this.currentMorpion); } incorrectCase() { - console.log("bozo"); + } sendCase(targetMorpion, targetCase) { this.map[targetMorpion][targetCase] = (this.sign == "x") ? 0 : 1; + this.currentMorpion = targetCase; this.printSign(targetMorpion, targetCase, this.sign); - console.log(this.game.send, targetMorpion, targetCase) + console.log(targetMorpion, targetCase) this.game.send(JSON.stringify({"targetMorpion" : targetMorpion, "targetCase" : targetCase, "sign" : this.sign})); console.log(this.turn); this.turn = !this.turn; @@ -172,21 +201,25 @@ class TicTacToe return -1; } - setOutline() + setOutline(targetMorpion, clear) { - if (this.turn) + let targetX = (this.gap + targetMorpion % 3 * this.rectsize * 3); + let targetY = (this.gap + Math.floor(targetMorpion / 3) * this.rectsize * 3); + if (this.game.finished) + return; + if (!clear) { this.context.beginPath(); this.context.strokeStyle = (this.sign == "x") ? "green" : "red"; - this.context.roundRect(0, 0, this.canvas.width, this.canvas.height, 25); + this.context.rect(targetX, targetY, this.rectsize * 3, this.rectsize * 3) this.context.stroke(); this.context.closePath(); } else { this.context.beginPath(); - this.context.strokeStyle = "#1a1a1d"; - this.context.roundRect(0, 0, this.canvas.width, this.canvas.height, 25); + this.context.strokeStyle = `rgb(230 230 230)`; + this.context.rect(targetX, targetY, this.rectsize * 3, this.rectsize * 3) this.context.stroke(); this.context.closePath(); } @@ -244,34 +277,6 @@ class TicTacToe } this.context.closePath(); } - - selectCase(x, y) - { - case_morpion = Math.floor(x / this.rectsize) + Math.floor((y / this.rectsize)) * 3 - case_square = Math.floor(x / Math.floor(this.rectsize / 3)) % this.rectsize + Math.floor(y / this.rectsize) % this.rectsize - // ask server if case_morpion == playing_case && case_square == empty - - } - - setOutline() - { - if (this.turn) - { - this.context.beginPath(); - this.context.strokeStyle = (this.sign == "x") ? "green" : "red"; - this.context.roundRect(0, 0, this.canvas.width, this.canvas.height, 25); - this.context.stroke(); - this.context.closePath(); - } - else - { - this.context.beginPath(); - this.context.strokeStyle = "#1a1a1d"; - this.context.roundRect(0, 0, this.canvas.width, this.canvas.height, 25); - this.context.stroke(); - this.context.closePath(); - } - } } export { TicTacToe }; \ No newline at end of file diff --git a/frontend/static/js/sound/tictactoe/play-move.mp3 b/frontend/static/js/sound/tictactoe/play-move.mp3 new file mode 100644 index 0000000..1713db0 Binary files /dev/null and b/frontend/static/js/sound/tictactoe/play-move.mp3 differ diff --git a/frontend/static/js/views/TicTacToeOnlineView.js b/frontend/static/js/views/TicTacToeOnlineView.js index 129e6a5..2379cd8 100644 --- a/frontend/static/js/views/TicTacToeOnlineView.js +++ b/frontend/static/js/views/TicTacToeOnlineView.js @@ -19,7 +19,6 @@ export class TicTacToeOnlineView extends AbstractView this.Morpion = new TicTacToe(this.height, this.width, 60, 60, document.getElementById("Morpion"), this.game_id); this.Morpion.DrawSuperMorpion(); await this.Morpion.init(); - this.Morpion.setOutline(); } async leavePage() diff --git a/games/consumers.py b/games/consumers.py index 4fd1094..825ffe5 100644 --- a/games/consumers.py +++ b/games/consumers.py @@ -45,6 +45,8 @@ class TicTacToeWebSocket(WebsocketConsumer): self.member.send(self.member.sign) if (self.game._everbody_is_here() and self.game.model.started == False): + if (self.game.time != -1): + self.game.broadcast("opponent_joined") self.game.broadcast("game_start") self.game.model.start() @@ -54,7 +56,12 @@ class TicTacToeWebSocket(WebsocketConsumer): if (data.get("targetMorpion") is not None and data.get("targetCase") is not None): if (self.game.add(data, self.member) == False): return - self.game.broadcast("", data, [self.member]) + if (data.get("catchup") is not None and self.game.model.finished == False and self.game.model.finished == True): + self.member.send("catchup", {"Morpion": self.game._map, "turn": self.game.turn}) + if (self.game.checkWin() != False): + print(self.game.checkWin()) + self.game.broadcast("game_end", {"winning_sign": self.member.sign}) + self.game.broadcast("game_move", data, [self.member]) pass def disconnect(self, event): diff --git a/games/objects/tictactoe/TicTacToeGame.py b/games/objects/tictactoe/TicTacToeGame.py index fe123e5..7befea5 100644 --- a/games/objects/tictactoe/TicTacToeGame.py +++ b/games/objects/tictactoe/TicTacToeGame.py @@ -18,6 +18,10 @@ class TicTacToeGame(AGame): self.players: list[TicTacToePlayer] = [TicTacToePlayer(player, None, self, ["x", "o"][i]) for i, player in enumerate(players)] + self.time = -1 + + self.turn = 'x' + self._map = [[-1 for _ in range(9)] for _ in range(9)] def _everbody_is_here(self): @@ -44,14 +48,15 @@ class TicTacToeGame(AGame): if (self.checkMove(newmove, player)): self._map[newmove.get("targetMorpion")][newmove.get("targetCase")] = newmove.get("sign") - player.currentMorpion = int(newmove.get("targetMorpion")) + player.currentMorpion = int(newmove.get("targetCase")) + self.turn = newmove.get("sign") return True return False def checkMove(self, newmove, player): print(int(newmove.get("targetMorpion")), player.currentMorpion) - if (int(newmove.get("targetMorpion")) != player.currentMorpion): + if (int(newmove.get("targetMorpion")) != player.currentMorpion or newmove.get("sign") != self.turn): return False if (self._map[newmove.get("targetMorpion")][newmove.get("targetCase")] != -1): @@ -62,16 +67,16 @@ class TicTacToeGame(AGame): def checkWin(self): for tab in self._map: for i in range(3): - if tab[i] == tab[i + 3] == tab[i + 6]: + if tab[i] != -1 and tab[i] == tab[i + 3] and tab[i + 3] == tab[i + 6]: return tab[i] for i in range(0, 9, 3): - if tab[i] == tab[i + 1] == tab[i + 2]: + if tab[i] != -1 and tab[i] == tab[i + 1] and tab[i + 1] == tab[i + 2]: return tab[i] - if tab[0] == tab[4] == tab[8]: + if tab[0] != -1 and tab[0] == tab[4] and tab[4] == tab[8]: return tab[0] - if tab[6] == tab[4] == tab[2]: + if tab[6] != -1 and tab[6] == tab[4] and tab[4] == tab[2]: return tab[6] - return None + return False def _spectator_join(self, user_id: int, socket: WebsocketConsumer):