From 9bb6a32c70a189ff41313722a99917da583c6e2a Mon Sep 17 00:00:00 2001 From: starnakin Date: Tue, 26 Dec 2023 18:24:23 +0100 Subject: [PATCH] tournament: add: TOURNAMENT CAN START --- .../static/js/api/tournament/tournament.js | 6 +- .../static/js/views/TournamentPageView.js | 18 +++- games/serializers.py | 24 ++++++ tournament/consumers.py | 10 +-- tournament/models.py | 84 +++++++++++++------ tournament/serializers.py | 9 +- 6 files changed, 110 insertions(+), 41 deletions(-) create mode 100644 games/serializers.py diff --git a/frontend/static/js/api/tournament/tournament.js b/frontend/static/js/api/tournament/tournament.js index c0d783e..7e62508 100644 --- a/frontend/static/js/api/tournament/tournament.js +++ b/frontend/static/js/api/tournament/tournament.js @@ -51,6 +51,7 @@ class Tourmanent this.finished = response_data.finished; this.levels = response_data.levels; this.id = response_data.id + this.state = this.get_state(); } leave(event) @@ -66,10 +67,7 @@ class Tourmanent { if (!this.connected) return - console.log(this.isParticipating); - this.isParticipating = !this.isParticipating; - console.log(this.isParticipating); - this._socket.send(JSON.stringify({participate: this.isParticipating})); + this._socket.send(JSON.stringify({participate: ""})); } async join(receive_func, disconnect_func) diff --git a/frontend/static/js/views/TournamentPageView.js b/frontend/static/js/views/TournamentPageView.js index 18ae9c4..0e7d5c3 100644 --- a/frontend/static/js/views/TournamentPageView.js +++ b/frontend/static/js/views/TournamentPageView.js @@ -1,4 +1,4 @@ -import {client} from "../index.js"; +import {client, navigateTo} from "../index.js"; import AbstractAuthentifiedView from "./abstracts/AbstractAuthentifiedView.js"; export default class extends AbstractAuthentifiedView @@ -12,13 +12,24 @@ export default class extends AbstractAuthentifiedView pressButton() { this.tournament.toggle_participation(); - document.getElementById("button").value = this.tournament.isParticipating ? "Leave tournament" : "Join tournament"; } async receive(data) { if (data.detail === "nb_participants" || data.detail === "update_participants") document.getElementById("nb_participants").innerText = `${data.nb_participants} / ${this.tournament.nb_players}` + if (data.detail === "go_to") + navigateTo(data.url); + if (data.detail === "is_participant") + this.updateParticipating(data.is_participant) + if (data.detail === "error") + document.getElementById("display").innerText = data.error_message + } + + async updateParticipating(state) + { + document.getElementById("button").value = state ? `Leave ${this.tournament.name}` : `Join ${this.tournament.name}`; + document.getElementById("display").innerText = state ? "You are a particpant" : "You are not a participant"; } async ondisconnect(event) @@ -81,6 +92,7 @@ export default class extends AbstractAuthentifiedView - ` + + ` } } diff --git a/games/serializers.py b/games/serializers.py new file mode 100644 index 0000000..5bd2fc6 --- /dev/null +++ b/games/serializers.py @@ -0,0 +1,24 @@ +from rest_framework import serializers +from .models import GameModel, GameMembersModel + +class GameSerializer(serializers.ModelSerializer): + + players_id = serializers.SerializerMethodField() + winner_id = serializers.ReadOnlyField() + state = serializers.SerializerMethodField() + started = serializers.ReadOnlyField() + finished = serializers.ReadOnlyField() + + class Meta: + model = GameModel + fields = ["id", "winner_id", "state", "started", "finished", "players_id"] + + def get_state(self, instance: GameModel): + if (instance.finished): + return "finished" + if (instance.started): + return "started" + return "waiting" + + def get_players_id(self, instance: GameModel): + players_id = [player_game.member_id for player_game in GameMembersModel.objects.filter(game_id=instance.pk)] \ No newline at end of file diff --git a/tournament/consumers.py b/tournament/consumers.py index 07aaee6..ea2bb46 100644 --- a/tournament/consumers.py +++ b/tournament/consumers.py @@ -26,18 +26,18 @@ class TournamentWebConsumer(WebsocketConsumer): self.tournament_id = int(self.scope['url_route']['kwargs']['tournament_id']) self.room = tournament_manager.get(self.tournament_id) - self.participant = TournamentMember(self.user.pk, self, self.room) + self.member = TournamentMember(self.user.pk, self, self.room) if (self.room is None): - self.participant.send("Tournament not found") + self.member.send("Tournament not found") self.disconnect(1017) - self.room.append(self.participant) + self.room.append(self.member) def receive(self, text_data: str = None, bytes_data: bytes = None): - self.participant.receive(text_data, bytes_data) + self.member.receive(text_data, bytes_data) def disconnect(self, close_code): member = self.room.get_member_by_socket(self) if (member is not None): - self.room.remove(self.participant, close_code) \ No newline at end of file + self.room.remove(self.member, close_code) \ No newline at end of file diff --git a/tournament/models.py b/tournament/models.py index 117e92d..81ee3dc 100644 --- a/tournament/models.py +++ b/tournament/models.py @@ -20,22 +20,41 @@ class TournamentModel(models.Model): started = models.BooleanField(default=False) finished = models.BooleanField(default=False) - def create_game(self, users_id): - game_id = GameModel.create(users_id=users_id) - TournamentGamesModel(game_id=game_id, tournament_id=self.pk).save() + def create_game(self, level, users_id): + game_id = GameModel().create(users_id=users_id) + TournamentGamesModel(game_id=game_id, tournament_id=self.pk, tournament_level=level).save() return game_id def get_games_id_by_level(self, level): - return list(TournamentGamesModel.objects.filter(tournament_id=self.pk, tournament_level=level)) + tmp = TournamentGamesModel.objects.filter(tournament_id=self.pk, tournament_level=level) + return [instance.game_id for instance in tmp] def get_games_id(self): return list(TournamentGamesModel.objects.filter(tournament_id=self.pk)) def get_players_id(self): - lst: [int] = [] - for game_id in self.get_games_id(): - lst.append(GameMembersModel.objects.filter(game_id=game_id)) - return lst + return [model.participant_id for model in TournamentParticipantsModel.objects.filter(tournament_id=self.pk)] + + def is_a_participant(self, participant_id: int): + return TournamentParticipantsModel.objects.filter(participant_id=participant_id, tournament_id=self.pk).exists() + + def add_participants(self, participants_id: [int]): + for participant_id in participants_id: + TournamentParticipantsModel(tournament_id=self.pk, participant_id=participant_id).save() + + def start(self, participants_id: [int]): + self.started = True + self.add_participants(participants_id) + games_id = [int] + for i in range(0, len(participants_id), self.nb_players_by_game): + game_id = self.create_game(0, participants_id[i : i + self.nb_players_by_game]) + games_id.append(game_id) + self.save() + return games_id + +class TournamentParticipantsModel(models.Model): + tournament_id = models.IntegerField() + participant_id = models.IntegerField() class TournamentGamesModel(models.Model): @@ -45,10 +64,10 @@ class TournamentGamesModel(models.Model): class TournamentMember(AbstractRoomMember): - def __init__(self, user_id: int, socket: WebsocketConsumer, tournament): + def __init__(self, user_id: int, socket: WebsocketConsumer, room): super().__init__(user_id, socket) self.participate = False - self.tournament = tournament + self.room = room def receive(self, text_data: str = None, byte_dates: bytes = None): @@ -57,34 +76,46 @@ class TournamentMember(AbstractRoomMember): data: dict = json.loads(text_data) - self.update_participate(data.get("participate", self.participate)) + if (data.get("participate") is not None): + self.room.update_participants(self) - def update_participate(self, new_participate: bool): + def send_error_message(self, message: str): + self.send("error", {"error_message": message}) - if (self.participate == new_participate): - return - self.participate = new_participate - self.tournament.update_participants() + def go_to(self, url: str): + self.send("go_to", {"url": url}) + + def send_participating(self): + self.send("is_participant", {"is_participant": self.participate}) class TournamentRoom(AbstractRoom): def __init__(self, room_manager, tournament_id: int): super().__init__(room_manager) self.tournament_id = tournament_id - self.definitive_participant_list = [] - self.started = False - self.model = TournamentModel.objects.get(pk=tournament_id) + self.tournament = TournamentModel.objects.get(pk=tournament_id) def start(self): self.broadcast("tournament_start") + games_id = self.tournament.start(self.get_participants_id()) + for i, participant in enumerate(self.get_participants()): + participant: TournamentMember + participant.go_to(f"games/{games_id[i // self.tournament.nb_players_by_game]}") - def update_participants(self): + def update_participants(self, member: TournamentMember): + if (self.tournament.started): + member.send_error_message("Tournament already started") + return + member.participate = not member.participate nb_participants = self.get_nb_participants() self.broadcast("update_participants", {"nb_participants": nb_participants}) - if (nb_participants == self.model.nb_players): + member.send_participating() + if (nb_participants == self.tournament.nb_players): self.start() def get_nb_participants(self): + if (self.tournament.started): + return self.tournament.nb_players nb_participants = 0 for member in self._member_list: member: TournamentMember @@ -93,13 +124,16 @@ class TournamentRoom(AbstractRoom): return nb_participants def get_participants(self): + return [member for member in self._member_list if member.participate] + + def get_participants_id(self): return [member.user_id for member in self._member_list if member.participate] - def start(self): - self.started = True - def append(self, member: TournamentMember): super().append(member) + if self.tournament.started: + member.participate = self.tournament.is_a_participant(member.user_id) + member.send_participating() member.send("nb_participants", {"nb_participants": self.get_nb_participants()}) class TournamentRoomManager(AbstractRoomManager): @@ -110,7 +144,7 @@ class TournamentRoomManager(AbstractRoomManager): if (room.tournament_id == tournament_id): return room - if (TournamentModel.objects.filter(pk = tournament_id).exists()): + if (TournamentModel.objects.filter(pk = tournament_id, finished=False).exists()): room = TournamentRoom(self, tournament_id) self.append(room) return room diff --git a/tournament/serializers.py b/tournament/serializers.py index c17525b..7e06053 100644 --- a/tournament/serializers.py +++ b/tournament/serializers.py @@ -1,5 +1,6 @@ from rest_framework import serializers from .models import TournamentModel +from games.serializers import GameSerializer class TournamentSerializer(serializers.ModelSerializer): @@ -13,13 +14,13 @@ class TournamentSerializer(serializers.ModelSerializer): model = TournamentModel fields = ["name", "nb_players", "nb_players_by_game", "level", "started", "finished", "levels", "id"] - def get_levels(self, instance): + def get_levels(self, instance: TournamentModel): levels: [[int]] = [] for i in range(instance.level): - level: [int] = instance.get_games_id_by_level(i) - if (level == []): + games_id: [int] = instance.get_games_id_by_level(i) + if (games_id == []): break - levels.append(level) + levels.append(games_id) return levels def validate_nb_players(self, value: int):