core: tournament

This commit is contained in:
2024-04-16 19:13:18 +02:00
parent 14886c8ac9
commit 630ef709ab
10 changed files with 160 additions and 216 deletions

View File

@ -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()