core: tournament
This commit is contained in:
@ -1,155 +1,127 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.db import models
|
||||
|
||||
from channels.generic.websocket import WebsocketConsumer
|
||||
|
||||
from games.models import GameModel
|
||||
|
||||
import json
|
||||
|
||||
from transcendence.abstract.AbstractRoomMember import AbstractRoomMember
|
||||
from transcendence.abstract.AbstractRoom import AbstractRoom
|
||||
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
|
||||
|
||||
from profiles.models import ProfileModel
|
||||
from games.models import GameModel
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import CASCADE
|
||||
from channels.generic.websocket import WebsocketConsumer
|
||||
|
||||
|
||||
# Create your models here.tu
|
||||
class TournamentModel(models.Model):
|
||||
|
||||
name = models.CharField(max_length = 100)
|
||||
nb_players = models.IntegerField()
|
||||
nb_players_by_game = models.IntegerField()
|
||||
level = models.IntegerField()
|
||||
rounds = models.IntegerField()
|
||||
started = models.BooleanField(default = False)
|
||||
finished = models.BooleanField(default = False)
|
||||
gamemode = models.CharField(max_length = 50, default = "pong")
|
||||
winner = models.ForeignKey(ProfileModel, on_delete=CASCADE)
|
||||
|
||||
def create_game(self, level, players_id):
|
||||
game_id = GameModel().create(self.gamemode, players_id = players_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):
|
||||
tmp = TournamentGamesModel.objects.filter(tournament_id = self.pk, tournament_level = level)
|
||||
return [instance.game_id for instance in tmp]
|
||||
def _add_player(self, player: ProfileModel) -> None:
|
||||
TournamentPlayerModel(player=player, tournament=self).save()
|
||||
|
||||
def get_games_id(self):
|
||||
return [tournament_game.game_id for tournament_game in TournamentGamesModel.objects.filter(tournament_id = self.pk)]
|
||||
|
||||
def get_participants_id(self):
|
||||
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 start(self, players: list[ProfileModel]) -> None:
|
||||
|
||||
def add_participants(self, participants_id: [int]):
|
||||
for participant_id in participants_id:
|
||||
TournamentParticipantsModel(tournament_id = self.pk, participant_id = participant_id).save()
|
||||
self.started = False
|
||||
|
||||
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
|
||||
for player in players:
|
||||
self._add_player(player)
|
||||
|
||||
class TournamentParticipantsModel(models.Model):
|
||||
tournament_id = models.IntegerField()
|
||||
participant_id = models.IntegerField()
|
||||
|
||||
class TournamentGamesModel(models.Model):
|
||||
|
||||
tournament_id = models.IntegerField()
|
||||
tournament_level = models.IntegerField()
|
||||
game_id = models.IntegerField()
|
||||
|
||||
class TournamentMember(AbstractRoomMember):
|
||||
|
||||
def __init__(self, user_id: int, socket: WebsocketConsumer, room):
|
||||
super().__init__(user_id, socket)
|
||||
self.participate = False
|
||||
self.room = room
|
||||
|
||||
def receive(self, text_data: str = None, byte_dates: bytes = None):
|
||||
for (player1, player2) in zip(players[0::2], players[1::2]):
|
||||
self.create_game([player1, player2], round=1)
|
||||
|
||||
if (text_data is None):
|
||||
return
|
||||
self.save()
|
||||
|
||||
data: dict = json.loads(text_data)
|
||||
def create_game(self, players: list[ProfileModel], round: int) -> GameModel:
|
||||
|
||||
if (data.get("participate") is not None):
|
||||
self.room.update_participants(self)
|
||||
if (self.started == False):
|
||||
return None
|
||||
|
||||
if (len(players) != 2):
|
||||
return None
|
||||
|
||||
from games.models import GameModel
|
||||
|
||||
def send_error_message(self, message: str):
|
||||
self.send("error", {"error_message": message})
|
||||
game: GameModel = GameModel().create(players=players)
|
||||
|
||||
def go_to(self, url: str):
|
||||
self.send("go_to", {"url": url})
|
||||
TournamentGameModel(tournament=self, game=game, round=round).save()
|
||||
|
||||
return game
|
||||
|
||||
def start(self, players: list[ProfileModel]) -> int:
|
||||
|
||||
if (len(players) != self.nb_players):
|
||||
return 1
|
||||
|
||||
for player in players:
|
||||
TournamentPlayerModel(tournament=self, player=player).save()
|
||||
|
||||
return 0
|
||||
|
||||
def get_games(self) -> list[GameModel]:
|
||||
return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self)]
|
||||
|
||||
def send_participating(self):
|
||||
self.send("is_participant", {"is_participant": self.participate})
|
||||
def get_games_by_round(self, round: int) -> list[GameModel]:
|
||||
return [tournament_game.game for tournament_game in TournamentGameModel.objects.filter(tournament=self, round=round)]
|
||||
|
||||
def get_players_by_round(self, round: int) -> list[ProfileModel]:
|
||||
return [game.get_players() for game in self.get_games_by_round(round)]
|
||||
|
||||
def get_winners_by_round(self, round: int) -> list[ProfileModel]:
|
||||
return [game.winner for game in self.get_games_by_round(round)]
|
||||
|
||||
def get_players(self) -> list[TournamentPlayerModel]:
|
||||
return TournamentPlayerModel.objects.filter(tournament=self.pk)
|
||||
|
||||
def get_state(self) -> str:
|
||||
return ("waiting to start", "in progress", "finish")[self.started + self.finished]
|
||||
|
||||
def is_player(self, profile: ProfileModel) -> bool:
|
||||
return TournamentPlayerModel.objects.filter(player=profile, tournament=self).exists()
|
||||
|
||||
class TournamentPlayerModel(models.Model):
|
||||
player = models.ForeignKey(ProfileModel, on_delete=CASCADE)
|
||||
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE)
|
||||
|
||||
class TournamentGameModel(models.Model):
|
||||
|
||||
tournament = models.ForeignKey(TournamentModel, on_delete=CASCADE, null=True, blank=True)
|
||||
round = models.IntegerField()
|
||||
game = models.ForeignKey(GameModel, on_delete=CASCADE)
|
||||
|
||||
class TournamentSpectator(AbstractRoomMember):
|
||||
pass
|
||||
|
||||
class TournamentPlayer(TournamentSpectator):
|
||||
pass
|
||||
|
||||
class TournamentRoom(AbstractRoom):
|
||||
|
||||
def __init__(self, room_manager, tournament_id: int):
|
||||
|
||||
def __init__(self, room_manager: TournamentRoomManager, tournament_id: int):
|
||||
super().__init__(room_manager)
|
||||
self.tournament_id = tournament_id
|
||||
self.tournament = TournamentModel.objects.get(pk = tournament_id)
|
||||
self.room_manager: TournamentRoomManager
|
||||
self.id: int = id
|
||||
self.model: TournamentModel = 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, 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})
|
||||
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
|
||||
if (member.participate):
|
||||
nb_participants += 1
|
||||
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 append(self, member: TournamentMember):
|
||||
super().append(member)
|
||||
if self.tournament.started:
|
||||
member.participate = self.tournament.is_a_participant(member.user_id)
|
||||
member.send_participating()
|
||||
self.broadcast("update_participants", {"participants": [self.get_participants_id()]})
|
||||
def join(self, profile: ProfileModel, socket: WebsocketConsumer) -> TournamentPlayer | TournamentSpectator:
|
||||
if (self.model.started):
|
||||
if (self.model.is_player(profile)):
|
||||
return TournamentPlayer(profile.pk, socket)
|
||||
else:
|
||||
return TournamentSpectator(profile.pk, socket)
|
||||
else:
|
||||
return TournamentSpectator(profile.pk, socket)
|
||||
|
||||
class TournamentRoomManager(AbstractRoomManager):
|
||||
|
||||
def get(self, tournament_id: int):
|
||||
|
||||
for room in self._room_list:
|
||||
if (room.tournament_id == tournament_id):
|
||||
return room
|
||||
|
||||
if (TournamentModel.objects.filter(pk = tournament_id).exists()):
|
||||
room = TournamentRoom(self, tournament_id)
|
||||
self.append(room)
|
||||
return room
|
||||
|
||||
return None
|
||||
pass
|
||||
|
||||
tournament_manager: TournamentRoomManager = TournamentRoomManager()
|
Reference in New Issue
Block a user