tournament: game: finish event
This commit is contained in:
parent
02bbaa6d9f
commit
dbb8e07d7d
@ -21,7 +21,6 @@ if TYPE_CHECKING:
|
|||||||
from .objects.pong.PongGame import PongGame
|
from .objects.pong.PongGame import PongGame
|
||||||
|
|
||||||
from .objects.tictactoe.TicTacToeGame import TicTacToeGame
|
from .objects.tictactoe.TicTacToeGame import TicTacToeGame
|
||||||
from .objects.tictactoe.TicTacToeSpectator import TicTacToeSpectator
|
|
||||||
|
|
||||||
game_manager: GameManager = GameManager()
|
game_manager: GameManager = GameManager()
|
||||||
|
|
||||||
|
@ -21,43 +21,28 @@ class GameModel(models.Model):
|
|||||||
stop_timestamp = models.BigIntegerField(null = True, blank = True)
|
stop_timestamp = models.BigIntegerField(null = True, blank = True)
|
||||||
game_type = models.CharField(max_length = 60, default = "pong")
|
game_type = models.CharField(max_length = 60, default = "pong")
|
||||||
|
|
||||||
def create(self, players: list[User]):
|
def create(self, players: set[User]) -> GameModel:
|
||||||
self.save()
|
self.save()
|
||||||
for player in players:
|
for player in players:
|
||||||
GameMembersModel(game = self, player=player).save()
|
GameMembersModel(game = self, player=player).save()
|
||||||
return self.pk
|
return self
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.start_timestamp = round(time.time() * 1000, 1)
|
self.start_timestamp = round(time.time() * 1000, 1)
|
||||||
self.started = True
|
self.started = True
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_tournament(self) -> None | TournamentGameModel:
|
|
||||||
|
|
||||||
from tournament.models import TournamentGameModel
|
|
||||||
|
|
||||||
query = TournamentGameModel.objects.filter(game=self)
|
|
||||||
if (not query.exists()):
|
|
||||||
return None
|
|
||||||
return query[0]
|
|
||||||
|
|
||||||
def finish(self, winner_id):
|
def finish(self, winner: User):
|
||||||
self.winner_id = winner_id
|
self.winner = winner
|
||||||
self.finished = True
|
self.finished = True
|
||||||
self.stop_timestamp = round(time.time() * 1000, 1)
|
self.stop_timestamp = round(time.time() * 1000, 1)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
tournament = self.get_tournament()
|
def get_players(self) -> set[User]:
|
||||||
if tournament is not None:
|
return {game_player.player for game_player in GameMembersModel.objects.filter(game = self)}
|
||||||
from tournament.consumers import tournament_manager
|
|
||||||
room = tournament_manager.get(tournament)
|
|
||||||
room.set_game_as_finished(self)
|
|
||||||
|
|
||||||
def get_players(self) -> list[User]:
|
|
||||||
return [game_player.player for game_player in GameMembersModel.objects.filter(game = self)]
|
|
||||||
|
|
||||||
def get_players_profiles(self) -> list[User]:
|
def get_players_profiles(self) -> set[User]:
|
||||||
return [game_player.player.profilemodel for game_player in GameMembersModel.objects.filter(game = self)]
|
return {game_player.player.profilemodel for game_player in GameMembersModel.objects.filter(game = self)}
|
||||||
|
|
||||||
def get_score_by_player_id(self, player_id: int) -> list[int]:
|
def get_score_by_player_id(self, player_id: int) -> list[int]:
|
||||||
query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id)
|
query: QuerySet = GameGoalModel.objects.filter(game_id = self.pk, player_id = player_id)
|
||||||
|
@ -6,6 +6,8 @@ from .ASpectator import ASpectator
|
|||||||
|
|
||||||
from ..models import GameModel
|
from ..models import GameModel
|
||||||
|
|
||||||
|
from tournament.models import TournamentGameModel
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
class AGame(AbstractRoom):
|
class AGame(AbstractRoom):
|
||||||
@ -16,7 +18,11 @@ class AGame(AbstractRoom):
|
|||||||
|
|
||||||
self.game_manager = game_manager
|
self.game_manager = game_manager
|
||||||
|
|
||||||
self.model: GameModel = GameModel.objects.get(pk = game_id, game_type = game_type)
|
query = TournamentGameModel.objects.filter(pk = game_id, game_type = game_type)
|
||||||
|
if (query.exists()):
|
||||||
|
self.model: TournamentGameModel | GameModel = query[0]
|
||||||
|
else:
|
||||||
|
self.model: TournamentGameModel | GameModel = GameModel.objects.get(pk = game_id, game_type = game_type)
|
||||||
|
|
||||||
players: list[User] = self.model.get_players()
|
players: list[User] = self.model.get_players()
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ from ..models import GameModel
|
|||||||
from .pong.PongGame import PongGame
|
from .pong.PongGame import PongGame
|
||||||
from .tictactoe.TicTacToeGame import TicTacToeGame
|
from .tictactoe.TicTacToeGame import TicTacToeGame
|
||||||
|
|
||||||
|
from tournament.models import TournamentGameModel
|
||||||
|
|
||||||
class GameManager():
|
class GameManager():
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
@ -14,7 +16,7 @@ class GameManager():
|
|||||||
self._game_list.remove(game)
|
self._game_list.remove(game)
|
||||||
|
|
||||||
def get(self, game_id: int, game_type: str) -> TicTacToeGame | PongGame:
|
def get(self, game_id: int, game_type: str) -> TicTacToeGame | PongGame:
|
||||||
|
|
||||||
if (not GameModel.objects.filter(pk=game_id, finished=False, game_type=game_type).exists()):
|
if (not GameModel.objects.filter(pk=game_id, finished=False, game_type=game_type).exists()):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -15,11 +15,11 @@ class GameSerializer(serializers.ModelSerializer):
|
|||||||
finished = serializers.ReadOnlyField()
|
finished = serializers.ReadOnlyField()
|
||||||
start_timestamp = serializers.ReadOnlyField()
|
start_timestamp = serializers.ReadOnlyField()
|
||||||
stop_timestamp = serializers.ReadOnlyField()
|
stop_timestamp = serializers.ReadOnlyField()
|
||||||
gamemode = serializers.ReadOnlyField()
|
game_type = serializers.ReadOnlyField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = GameModel
|
model = GameModel
|
||||||
fields = ["id", "winner_id", "state", "started", "finished", "players", "start_timestamp", "stop_timestamp", "gamemode"]
|
fields = ["id", "winner_id", "state", "started", "finished", "players", "start_timestamp", "stop_timestamp", "game_type"]
|
||||||
|
|
||||||
def get_state(self, instance: GameModel):
|
def get_state(self, instance: GameModel):
|
||||||
if (instance.finished):
|
if (instance.finished):
|
||||||
|
@ -42,8 +42,8 @@ class MatchMaking(WebsocketConsumer):
|
|||||||
|
|
||||||
self.waiting_room.broadcast(f"{len(self.waiting_room)} / {self.waiting_room.mode}")
|
self.waiting_room.broadcast(f"{len(self.waiting_room)} / {self.waiting_room.mode}")
|
||||||
if (len(self.waiting_room) == self.waiting_room.mode):
|
if (len(self.waiting_room) == self.waiting_room.mode):
|
||||||
game_id: int = GameModel(game_type=self.game_type).create(self.waiting_room.get_members())
|
game: GameModel = GameModel(game_type=self.game_type).create(self.waiting_room.get_members())
|
||||||
self.waiting_room.broadcast("game_found", {"game_id": game_id, "game_type": self.game_type})
|
self.waiting_room.broadcast("game_found", {"game_id": game.pk, "game_type": self.game_type})
|
||||||
|
|
||||||
def disconnect(self, close_code):
|
def disconnect(self, close_code):
|
||||||
super().disconnect(close_code)
|
super().disconnect(close_code)
|
||||||
|
@ -7,6 +7,7 @@ from django.db.models import QuerySet
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from games.models import GameModel
|
from games.models import GameModel
|
||||||
|
from games.serializers import GameSerializer
|
||||||
from profiles.models import ProfileModel
|
from profiles.models import ProfileModel
|
||||||
from profiles.serializers.ProfileSerializer import ProfileSerializer
|
from profiles.serializers.ProfileSerializer import ProfileSerializer
|
||||||
from .models import TournamentModel
|
from .models import TournamentModel
|
||||||
@ -83,6 +84,8 @@ class TournamentRoom:
|
|||||||
self._room_manager: TournamentRoomManager = room_manager
|
self._room_manager: TournamentRoomManager = room_manager
|
||||||
self._member_list: set[TournamentMember] = set()
|
self._member_list: set[TournamentMember] = set()
|
||||||
self._model: TournamentModel = tournament
|
self._model: TournamentModel = tournament
|
||||||
|
self._game_in_progress_list: set[GameModel] = set()
|
||||||
|
self._current_round = 0
|
||||||
|
|
||||||
def join(self, socket: TournamentWebConsumer) -> TournamentMember:
|
def join(self, socket: TournamentWebConsumer) -> TournamentMember:
|
||||||
|
|
||||||
@ -92,21 +95,52 @@ class TournamentRoom:
|
|||||||
return member
|
return member
|
||||||
|
|
||||||
def set_game_as_finished(self, game: GameModel):
|
def set_game_as_finished(self, game: GameModel):
|
||||||
raise NotImplemented()
|
self._game_in_progress_list.remove(game)
|
||||||
|
|
||||||
|
data: dict = GameSerializer(game).data
|
||||||
|
|
||||||
|
data.update({"round": self._current_round})
|
||||||
|
|
||||||
|
self.broadcast("game_update", data)
|
||||||
|
|
||||||
|
if len(self._game_in_progress_list) == 0:
|
||||||
|
self._round_finished()
|
||||||
|
|
||||||
|
def _finish(self, winner: User):
|
||||||
|
self._model.finish(winner)
|
||||||
|
|
||||||
|
def _round_finished(self):
|
||||||
|
|
||||||
|
if self._current_round == self._model.round:
|
||||||
|
last_game: GameModel = self._model.get_games_by_round(self._current_round)[0]
|
||||||
|
self._finish(last_game.winner)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._start_round()
|
||||||
|
|
||||||
|
def _start_round(self):
|
||||||
|
|
||||||
|
self._current_round += 1
|
||||||
|
|
||||||
|
participant_list: set[User] = self._model.get_participants_by_round(self._current_round)
|
||||||
|
|
||||||
|
self._game_in_progress_list = self._model.create_round(participant_list, self._current_round)
|
||||||
|
|
||||||
|
for game in self._game_in_progress_list:
|
||||||
|
for player in game.get_players():
|
||||||
|
participant: TournamentMember = self.get_participant_by_profile(player)
|
||||||
|
participant.send_goto(game)
|
||||||
|
|
||||||
def get_participants_profiles(self) -> list[ProfileModel]:
|
def get_participants_profiles(self) -> list[ProfileModel]:
|
||||||
return [participant._socket.user.profilemodel for participant in self.get_participants()]
|
return [participant._socket.user.profilemodel for participant in self.get_participants()]
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
|
|
||||||
games: list[GameModel] = self._model.start()
|
self._model.start()
|
||||||
|
|
||||||
self.broadcast("start")
|
self.broadcast("start")
|
||||||
|
|
||||||
for game in games:
|
self._start_round()
|
||||||
for player in game.get_players():
|
|
||||||
participant: TournamentMember = self.get_participant_by_profile(player)
|
|
||||||
participant.send_goto(game)
|
|
||||||
|
|
||||||
def get_participant_by_profile(self, profile: ProfileModel):
|
def get_participant_by_profile(self, profile: ProfileModel):
|
||||||
for participant in self.get_participants():
|
for participant in self.get_participants():
|
||||||
|
@ -19,24 +19,35 @@ class TournamentModel(models.Model):
|
|||||||
def _register_participant(self, participant: User) -> None:
|
def _register_participant(self, participant: User) -> None:
|
||||||
TournamentParticipantModel(participant=participant, tournament=self).save()
|
TournamentParticipantModel(participant=participant, tournament=self).save()
|
||||||
|
|
||||||
def start(self, participants: list[User]) -> None:
|
def create_round(self, participants: set[User], round: int) -> set[GameModel]:
|
||||||
|
|
||||||
games: list[GameModel] = []
|
game_list: set[GameModel] = set()
|
||||||
|
|
||||||
|
for i, (participant1, participant2) in enumerate(zip(participants[0::2], participants[1::2])):
|
||||||
|
game: GameModel = self.create_game([participant1, participant2], round, i)
|
||||||
|
game_list.add(game)
|
||||||
|
|
||||||
|
return game_list
|
||||||
|
|
||||||
|
def start(self, participant_list: set[User]) -> None:
|
||||||
|
|
||||||
self.started = True
|
self.started = True
|
||||||
|
self.round = 1
|
||||||
|
|
||||||
for player in participants:
|
for participant in participant_list:
|
||||||
self._register_participant(player)
|
self._register_participant(participant)
|
||||||
|
|
||||||
for (participant1, participant2) in zip(participants[0::2], participants[1::2]):
|
|
||||||
game: GameModel = self.create_game([participant1, participant2], round=1)
|
|
||||||
games.append(game)
|
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
return games
|
def finish(self, winner: User):
|
||||||
|
|
||||||
|
self.finished = True
|
||||||
|
|
||||||
def create_game(self, participants: list[User], round: int) -> GameModel:
|
self.winner = winner
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def create_game(self, participants: set[User], round: int, pos: int) -> GameModel:
|
||||||
|
|
||||||
if (self.started == False):
|
if (self.started == False):
|
||||||
return None
|
return None
|
||||||
@ -48,37 +59,47 @@ class TournamentModel(models.Model):
|
|||||||
|
|
||||||
game: GameModel = GameModel().create(participants)
|
game: GameModel = GameModel().create(participants)
|
||||||
|
|
||||||
TournamentGameModel(tournament=self, game=game, round=round).save()
|
TournamentGameModel(tournament=self, game=game, round=round, pos=pos).save()
|
||||||
|
|
||||||
return game
|
return game
|
||||||
|
|
||||||
def get_games(self) -> list[GameModel]:
|
def get_games(self) -> set[GameModel]:
|
||||||
return [games for games in self.get_games_by_round(i for i in range(1, self.round))]
|
return {games for games in self.get_games_by_round(i for i in range(1, self.round))}
|
||||||
|
|
||||||
def get_games_by_round(self, round: int) -> list[GameModel]:
|
def get_games_by_round(self, round: int) -> set[GameModel]:
|
||||||
return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self, round=round)]
|
return {tournament_game for tournament_game in TournamentGameModel.objects.filter(tournament=self, round=round)}
|
||||||
|
|
||||||
def get_players_by_round(self, round: int) -> list[User]:
|
def get_participants_by_round(self, round: int) -> set[User]:
|
||||||
return [game.get_players() for game in self.get_games_by_round(round)]
|
if round == 1:
|
||||||
|
return self.get_participants()
|
||||||
|
return {game.winner for game in self.get_games_by_round(round - 1)}
|
||||||
|
|
||||||
def get_winners_by_round(self, round: int) -> list[User]:
|
def get_winners_by_round(self, round: int) -> set[User]:
|
||||||
return [game.winner for game in self.get_games_by_round(round)]
|
return {game.winner for game in self.get_games_by_round(round)}
|
||||||
|
|
||||||
def get_participants(self) -> list[TournamentParticipantModel]:
|
def get_participants(self) -> set[User]:
|
||||||
return TournamentParticipantModel.objects.filter(tournament=self.pk)
|
return {tournament_participant.participant for tournament_participant in TournamentParticipantModel.objects.filter(tournament=self.pk)}
|
||||||
|
|
||||||
def get_state(self) -> str:
|
def get_state(self) -> str:
|
||||||
return ("waiting to start", "in progress", "finish")[self.started + self.finished]
|
return ("waiting to start", "in progress", "finish")[self.started + self.finished]
|
||||||
|
|
||||||
def is_participanting(self, profile: User) -> bool:
|
def is_participating(self, profile: User) -> bool:
|
||||||
return TournamentParticipantModel.objects.filter(participant=profile, tournament=self).exists()
|
return TournamentParticipantModel.objects.filter(participant=profile, tournament=self).exists()
|
||||||
|
|
||||||
class TournamentParticipantModel(models.Model):
|
class TournamentParticipantModel(models.Model):
|
||||||
participant = models.ForeignKey(User, on_delete=CASCADE)
|
participant = models.ForeignKey(User, on_delete=CASCADE)
|
||||||
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE)
|
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE)
|
||||||
|
|
||||||
class TournamentGameModel(models.Model):
|
class TournamentGameModel(GameModel):
|
||||||
|
|
||||||
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True)
|
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True)
|
||||||
round = models.IntegerField()
|
round = models.IntegerField()
|
||||||
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
pos = models.IntegerField()
|
||||||
|
|
||||||
|
def finish(self, winner_id):
|
||||||
|
super().finish(winner_id)
|
||||||
|
|
||||||
|
from .consumers import tournament_manager
|
||||||
|
|
||||||
|
room = tournament_manager.get(self.tournament)
|
||||||
|
room.set_game_as_finished(self)
|
@ -1,8 +1,7 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from .models import TournamentModel
|
from .models import TournamentModel, TournamentGameModel
|
||||||
|
|
||||||
from profiles.models import ProfileModel
|
|
||||||
from profiles.serializers.ProfileSerializer import ProfileSerializer
|
from profiles.serializers.ProfileSerializer import ProfileSerializer
|
||||||
from games.serializers import GameSerializer
|
from games.serializers import GameSerializer
|
||||||
|
|
||||||
@ -34,4 +33,29 @@ class TournamentSerializer(serializers.ModelSerializer):
|
|||||||
def validate_nb_participants(self, value: int):
|
def validate_nb_participants(self, value: int):
|
||||||
if (value not in nb_participants):
|
if (value not in nb_participants):
|
||||||
raise serializers.ValidationError(f"The numbers of participants must be {str(nb_participants)}.")
|
raise serializers.ValidationError(f"The numbers of participants must be {str(nb_participants)}.")
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
class TournamentGameSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
players = serializers.SerializerMethodField()
|
||||||
|
winner_id = serializers.ReadOnlyField()
|
||||||
|
state = serializers.SerializerMethodField()
|
||||||
|
started = serializers.ReadOnlyField()
|
||||||
|
finished = serializers.ReadOnlyField()
|
||||||
|
start_timestamp = serializers.ReadOnlyField()
|
||||||
|
stop_timestamp = serializers.ReadOnlyField()
|
||||||
|
gamemode = serializers.ReadOnlyField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TournamentGameModel
|
||||||
|
fields = ["id", "winner_id", "state", "started", "finished", "players", "start_timestamp", "stop_timestamp", "game_type"]
|
||||||
|
|
||||||
|
def get_state(self, instance: TournamentGameModel):
|
||||||
|
if (instance.finished):
|
||||||
|
return "finished"
|
||||||
|
if (instance.started):
|
||||||
|
return "started"
|
||||||
|
return "waiting"
|
||||||
|
|
||||||
|
def get_players(self, instance: TournamentGameModel):
|
||||||
|
return ProfileSerializer(instance.get_players_profiles(), many=True).data
|
Loading…
Reference in New Issue
Block a user