# -*- encoding: utf-8 -*- import logging from django.core.urlresolvers import reverse from django.db import models from django.utils.translation import ugettext as _ from events.models import Event from membership.models import Membership from . import settings, managers class Game(models.Model): """ Ein kompettes Spiel Mai-Star bestehend aus 6 Spielern """ event = models.ForeignKey(Event, related_name='maistargame_set') comment = models.TextField(_('Comment'), blank=True) player1 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 1"), related_name='+' ) player1_score = models.SmallIntegerField(_("Score")) player1_placement = models.PositiveSmallIntegerField(editable=False) player2 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 2"), related_name='+' ) player2_score = models.SmallIntegerField(_("Score")) player2_placement = models.PositiveSmallIntegerField(editable=False) player3 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 3"), related_name='+' ) player3_score = models.SmallIntegerField(_("Score")) player3_placement = models.PositiveSmallIntegerField(editable=False) player4 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 4"), related_name='+' ) player4_score = models.SmallIntegerField(_("Score")) player4_placement = models.PositiveSmallIntegerField(editable=False) player5 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 5"), related_name='+' ) player5_score = models.SmallIntegerField(_("Score")) player5_placement = models.PositiveSmallIntegerField(editable=False) player6 = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Player 6"), related_name='+' ) player6_score = models.SmallIntegerField(_("Score")) player6_placement = models.PositiveSmallIntegerField(editable=False) confirmed = models.BooleanField( _('Has been confirmed'), default=True, help_text=_('the game only counts whe it has been confirmed') ) player_names = models.CharField(max_length=255, editable=False) season = models.PositiveSmallIntegerField(_('Season'), editable=False, db_index=True) objects = managers.GameManager() def __str__(self): return _("Mai-Star Game with {0} from {1:%Y-%m-%d}").format( self.player_names, self.event.start ) def get_absolute_url(self): """ URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde. """ url = reverse('maistar-game-list', kwargs={'event': self.event.pk}) return u'%(url)s#%(pk)d' % {'url': url, 'pk': self.pk} @property def player_list(self): try: return self._player_list except AttributeError: self._player_list = list() for nr in range(1, 7): self._player_list.append({ 'user': getattr(self, 'player%d' % nr), 'membership': Membership.objects.get( user=getattr(self, 'player%d' % nr) ), 'score': getattr(self, 'player%d_score' % nr), 'placement': getattr(self, 'player%d_placement' % nr), }) return self._player_list def save(self, force_insert=False, force_update=False, using=None, update_fields=None): u""" Bestimmt die Platzierung eines jeden Spielers noch vor dem speichern. Außerdem wird eine Kommasperierte Liste der Spiele mitgespeichert. """ logging.debug("Berechne die Platzierungen neu...") game_date = self.event.start.date() player_tuples = [ (self.player1.id, self.player1.username, self.player1_score), (self.player2.id, self.player2.username, self.player2_score), (self.player3.id, self.player3.username, self.player3_score), (self.player4.id, self.player4.username, self.player4_score), (self.player5.id, self.player5.username, self.player5_score), (self.player6.id, self.player6.username, self.player6_score), ] season_start = settings.MAISTAR_SEASON_START.replace( year=game_date.year) # sort player by Score: player_tuples = sorted(player_tuples, key=lambda player: player[2], reverse=True) logging.debug(player_tuples) other_player_ranking = 1 other_player_score = 0 player_names = [] ranking = 1 player_nr = 1 for player_id, player_name, player_score in player_tuples: if player_score == other_player_score: player_ranking = other_player_ranking else: player_ranking = ranking setattr(self, "player%d_id" % player_nr, player_id) setattr(self, "player%d_score" % player_nr, player_score) setattr(self, "player%d_placement" % player_nr, player_ranking) other_player_ranking = player_ranking other_player_score = player_score player_names.append(player_name) player_nr += 1 ranking += 1 self.player_names = ', '.join(player_names) if game_date >= season_start: self.season = season_start.year else: self.season = season_start.year - 1 super(Game, self).save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields) class Ranking(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL) season = models.PositiveSmallIntegerField(_("Season")) placement = models.PositiveIntegerField(blank=True, null=True) avg_placement = models.PositiveSmallIntegerField(blank=True, null=True) avg_score = models.SmallIntegerField(blank=True, null=True) games_count = models.PositiveSmallIntegerField(default=0) games_good = models.PositiveSmallIntegerField(default=0) games_won = models.PositiveSmallIntegerField(default=0) objects = managers.LadderManager() class Meta(object): ordering = ('-season', 'placement', 'avg_placement', '-avg_score',) def __str__(self): return "Mai-Star Ranking: %s, Season: %d" % (self.user, self.season) def get_absolute_url(self): return reverse('maistar-player-games', kwargs={ 'username': self.user.username, 'season': self.season }) def recalculate(self): logging.info( u'Recalculate Mai-Star Ranking for Player %s in Season %s', self.user, self.season ) self.placement = None self.avg_placement = None self.avg_score = None self.games_count = 0 self.games_good = 0 self.games_won = 0 player_score = 0 player_placement = 0 for game in Game.objects.player_games(self.user, self.season): placement = 0 score = 0 for player in ('player1', 'player2', 'player3', 'player4', 'player5', 'player6'): if getattr(game, player) == self.user: placement = getattr(game, "%s_placement" % player) score = getattr(game, "%s_score" % player) player_placement += placement player_score += score self.games_count += 1 self.games_good += 1 if placement <= 3 else 0 self.games_won += 1 if placement == 1 else 0 if self.games_count > 0: self.avg_placement = round(player_placement / self.games_count) self.avg_score = round(player_score / self.games_count) self.save() def update_maistar_ranking(sender, instance, **kwargs): for player in instance.player_list: ranking, created = Ranking.objects.get_or_create( user=player['user'], season=instance.season ) if created: logging.debug('Created ranking for %s in Season %d', player['user'].username, instance.season) else: logging.debug('Updating ranking for %s in Season %d', player['user'].username, instance.season) ranking.recalculate() Ranking.objects.calculate_rankings(instance.season) models.signals.post_delete.connect(update_maistar_ranking, sender=Game) models.signals.post_save.connect(update_maistar_ranking, sender=Game)