Fehler bei Vergabe von Bonuspunkte korrigiert.

Kommentare für Bonuspunkte werden jetzt als Kommentar beim Spieler hinterlassen, nicht als Kommentar in der Hanchan.
FIXED: 3_in_a_row counter wurde nicht zurückgesetzt wenn Bonuspunkte vergeben wurden.
FIXED: Durchschnittliche Platzierung während eines Events wurde nur als Ganzzahl berechnet. Wird nun als Fießkomma berechnet und gesichert.
This commit is contained in:
Christian Berg
2016-01-09 22:55:26 +01:00
parent 088efe2f39
commit b1586efbab
155 changed files with 2571 additions and 2835 deletions

View File

@@ -1,7 +1,9 @@
# -*- encoding: utf-8 -*-
# TODO: Rankings archiv Flag erstellen, womit sie nicht mehr neuberechnet werden dürfen.
# TODO: Rankings archiv Flag erstellen, womit sie nicht mehr neuberechnet
# werden dürfen.
from __future__ import division
from datetime import date
from django.conf import settings
@@ -9,11 +11,10 @@ from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext as _
from events.models import Event
from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, logger, set_dirty, MIN_HANCHANS_FOR_LADDER
from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, logger, set_dirty
from . import managers
kyu_dan_rankings = set()
@@ -40,7 +41,7 @@ class EventRanking(models.Model):
ordering = ('placement', 'avg_placement', '-avg_score',)
def get_absolute_url(self):
return reverse('event-ranking', args=[self.tourney_id])
return reverse('event-ranking', args=[self.event_id])
def recalculate(self):
"""
@@ -50,23 +51,33 @@ class EventRanking(models.Model):
können zwar sehr leicht errechnet werden, es macht trotzdem Sinn
sie zwischen zu speichern.
"""
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user,
self.event.name) # @IgnorePep8
event_hanchans = Player.objects.confirmed_hanchans(user=self.user_id,
event=self.event_id) # @IgnorePep8
aggregator = event_hanchans.aggregate(
models.Avg('placement'),
models.Avg('game_score'),
models.Count('pk'))
self.avg_placement = aggregator['placement__avg']
self.avg_score = aggregator['score__avg']
self.hanchan_count = aggregator['pk__count']
self.good_hanchans = event_hanchans.filter(placement__lt=3).count()
self.won_hanchans = event_hanchans.filter(placement=1).count()
logger.info(
u'Recalculate EventRanking for Player %s in %s',
self.user, self.event.name
)
sum_placement = 0.0
sum_score = 0.0
event_hanchans = Hanchan.objects.confirmed_hanchans(
user=self.user_id,
event=self.event_id
)
self.hanchan_count = event_hanchans.count()
self.won_hanchans = 0
self.good_hanchans = 0
if self.hanchan_count <= 0:
self.delete()
else:
self.save()
for hanchan in event_hanchans:
hanchan.get_playerdata(user=self.user)
sum_placement += hanchan.placement
sum_score += hanchan.game_score
self.won_hanchans += 1 if hanchan.placement == 1 else 0
self.good_hanchans += 1 if hanchan.placement == 2 else 0
self.avg_placement = sum_placement / self.hanchan_count
self.avg_score = sum_score / self.hanchan_count
self.save(force_update=True)
class Hanchan(models.Model):
@@ -76,52 +87,88 @@ class Hanchan(models.Model):
Außerdem gehört jede Hanchan zu einer Veranstaltung.
"""
event = models.ForeignKey(Event)
start = models.DateTimeField(_('Start'),
help_text=_('This is crucial to get the right Hanchans that scores')
)
start = models.DateTimeField(
_('Start'),
help_text=_('This is crucial to get the right Hanchans that scores')
)
player1 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 1'))
player1 = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
verbose_name=_('Player 1'))
player1_input_score = models.IntegerField(_('Score'))
player1_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
player1_placement = models.PositiveSmallIntegerField(default=0, editable=False)
player1_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player1_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player1_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player1_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
player1_game_score = models.PositiveIntegerField(
_('Score'), default=0, editable=False)
player1_placement = models.PositiveSmallIntegerField(
default=0, editable=False)
player1_kyu_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player1_dan_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player1_bonus_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player1_comment = models.CharField(
_('Comment'), blank=True, max_length=255, editable=False)
player2 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 2'))
player2 = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
verbose_name=_('Player 2'))
player2_input_score = models.IntegerField(_('Score'))
player2_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
player2_placement = models.PositiveSmallIntegerField(default=0, editable=False)
player2_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player2_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player2_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player2_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
player2_game_score = models.PositiveIntegerField(
_('Score'), default=0, editable=False)
player2_placement = models.PositiveSmallIntegerField(
default=0, editable=False)
player2_kyu_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player2_dan_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player2_bonus_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player2_comment = models.CharField(
_('Comment'), blank=True, max_length=255, editable=False)
player3 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 3'))
player3 = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
verbose_name=_('Player 3'))
player3_input_score = models.IntegerField(_('Score'))
player3_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
player3_placement = models.PositiveSmallIntegerField(default=0, editable=False)
player3_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player3_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player3_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player3_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
player3_game_score = models.PositiveIntegerField(
_('Score'), default=0, editable=False)
player3_placement = models.PositiveSmallIntegerField(
default=0, editable=False)
player3_kyu_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player3_dan_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player3_bonus_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player3_comment = models.CharField(
_('Comment'), blank=True, max_length=255, editable=False)
player4 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 4'))
player4 = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
verbose_name=_('Player 4'))
player4_input_score = models.IntegerField(_('Score'))
player4_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
player4_placement = models.PositiveSmallIntegerField(default=0, editable=False)
player4_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player4_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player4_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
player4_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
player4_game_score = models.PositiveIntegerField(
_('Score'), default=0, editable=False)
player4_placement = models.PositiveSmallIntegerField(
default=0, editable=False)
player4_kyu_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player4_dan_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player4_bonus_points = models.SmallIntegerField(
blank=True, null=True, editable=False)
player4_comment = models.CharField(
_('Comment'), blank=True, max_length=255, editable=False)
comment = models.TextField(_('Comment'), blank=True)
confirmed = models.BooleanField(_('Has been Confirmed'), default=True,
help_text=_('Only valid and confirmed Hanchans will be counted in the rating.')
help_text=_(
'Only valid and confirmed Hanchans '
'will be counted in the rating.')
)
player_names = models.CharField(max_length=255, editable=False)
season = models.PositiveSmallIntegerField(_('Season'), editable=False, db_index=True)
season = models.PositiveSmallIntegerField(
_('Season'), editable=False, db_index=True)
objects = managers.HanchanManager()
class Meta(object):
@@ -137,7 +184,8 @@ class Hanchan(models.Model):
def clean(self):
"""
Check if 4 different Players are attending the Game,
if the Game between the opening hours and the Hanchan has a total of 100.000 Points.
if the Game between the opening hours and the Hanchan has a total of
100.000 Points.
"""
errors = {}
score_sum = 0
@@ -155,18 +203,21 @@ class Hanchan(models.Model):
score_sum += input_score
game_score = input_score if input_score > 0 else 0
if player in player_set:
errors['player%d' % i] = _("%s can't attend the same game multiple times") % player
errors['player%d' % i] = _(
"%s can't attend the same game multiple times") % player
else:
player_set.add(player)
setattr(self, 'player%d_game_score' % i, game_score)
# Check if the game was played during the event
if self.start > timezone.now():
errors['start'] = _("Games in the future may not be added, Dr. Brown")
errors['start'] = _(
"Games in the future may not be added, Dr. Brown")
elif not (self.event.start <= self.start <= self.event.end):
errors['start'] = _("Only games during the event are allowed")
elif score_sum < 100000:
errors['player4_input_score'] = _('Gamescore is lower then 100.000 Pt.')
errors['player4_input_score'] = _(
'Gamescore is lower then 100.000 Pt.')
elif score_sum > 100000:
errors['player4_input_score'] = _('Gamescore is over 100.000 Pt.')
@@ -190,12 +241,18 @@ class Hanchan(models.Model):
else:
player['placement'] = placement
setattr(self, "player%d" % player_nr, player['user'])
setattr(self, "player%d_input_score" % player_nr, player['input_score'])
setattr(self, "player%d_game_score" % player_nr, player['game_score'])
setattr(self, "player%d_placement" % player_nr, player['placement'])
setattr(self, "player%d_kyu_points" % player_nr, player['kyu_points'])
setattr(self, "player%d_dan_points" % player_nr, player['dan_points'])
setattr(self, "player%d_bonus_points" % player_nr, player['bonus_points'])
setattr(self, "player%d_input_score" %
player_nr, player['input_score'])
setattr(self, "player%d_game_score" %
player_nr, player['game_score'])
setattr(self, "player%d_placement" %
player_nr, player['placement'])
setattr(self, "player%d_kyu_points" %
player_nr, player['kyu_points'])
setattr(self, "player%d_dan_points" %
player_nr, player['dan_points'])
setattr(self, "player%d_bonus_points" %
player_nr, player['bonus_points'])
setattr(self, "player%d_comment" % player_nr, player['comment'])
other_player_placement = player['placement']
other_player_game_score = player['game_score']
@@ -206,13 +263,13 @@ class Hanchan(models.Model):
def get_absolute_url(self):
return "{url:s}#{id:d}".format(
url=reverse('event-hanchan-list', kwargs={'event':self.event_id}),
id= self.pk
url=reverse('event-hanchan-list', kwargs={'event': self.event_id}),
id=self.pk
)
def get_playerdata(self, user):
"""i small workaround to access score, placement and points of a
specific user prominent from a in the user templates"""
"""small workaround to access score, placement and points of a
specific user prominent in the user templates"""
for player in ('player1', 'player2', 'player3', 'player4'):
if getattr(self, player) == user:
self.user = user
@@ -252,7 +309,8 @@ class Hanchan(models.Model):
'comment': getattr(self, 'player%d_comment' % i),
})
# sort player by Score:
return sorted(player_list, key=lambda player: player['input_score'], reverse=True)
return sorted(player_list, key=lambda player: player['input_score'],
reverse=True)
def save(self, **kwargs):
self.season = self.event.mahjong_season or date.today().year
@@ -276,12 +334,13 @@ class KyuDanRanking(models.Model):
good_hanchans = models.PositiveIntegerField(default=0)
hanchan_count = models.PositiveIntegerField(default=0)
legacy_date = models.DateField(blank=True, null=True)
legacy_hanchan_count = models.PositiveIntegerField(default=0)
legacy_dan_points = models.PositiveIntegerField(default=0)
legacy_kyu_points = models.PositiveIntegerField(default=0)
wins_in_a_row = 0
class Meta(object):
ordering = ('-dan_points', '-kyu_points',)
ordering = ('-dan', '-dan_points', '-kyu_points',)
verbose_name = _(u'Kyū/Dan Ranking')
verbose_name_plural = _(u'Kyū/Dan Rankings')
@@ -316,15 +375,18 @@ class KyuDanRanking(models.Model):
hanchan.dan_points += bonus_points
hanchan.bonus_points += bonus_points
hanchan.player_comment += '3 Siege in Folge: +%d Punkte auf den %d. Dan. ' % (bonus_points, new_dan_rank)
hanchan.player_comment += '3 Siege in Folge: +%d Punkte auf den ' \
'%d. Dan. ' % (
bonus_points, new_dan_rank)
self.dan_points += bonus_points
self.wins_in_a_row = 0
# TODO: Komplett Überabreiten!
def append_tournament_bonuspoints(self, hanchan):
"""
Prüft ob es die letzte Hanchan in einem Turnier war. Wenn ja werden
bei Bedarf Bonuspunkte vergeben, falls der Spieler das Turnier gewonnen
hat.
bei Bedarf Bonuspunkte vergeben, falls der Spieler das Turnier
gewonnen hat.
:param hanchan: Ein Player Objekt
"""
bonus_points = 0
@@ -333,24 +395,27 @@ class KyuDanRanking(models.Model):
).order_by('-start')
last_hanchan_this_event = hanchans_this_event[0]
if hanchan != last_hanchan_this_event:
return # Das braucht nur am Ende eines Turnieres gemacht werden.
event_ranking = EventRanking.objects.get(
user=self.user,
event=hanchan.event)
if event_ranking.placement == 1:
bonus_points += 4
hanchan.comment += '+4 Punkte für den Sieg des Turnieres. '
if event_ranking.avg_placement == 1:
bonus_points += 8
hanchan.comment += '+8 Pkt: alle Spiele des Turnieres gewonnen. '
return False # Das braucht nur am Ende eines Turnieres gemacht werden.
else:
event_ranking = EventRanking.objects.get(
user=self.user,
event=hanchan.event
)
if event_ranking.placement == 1:
bonus_points += 4
hanchan.player_comment += u'+4 Punkte Turnier gewonnen. '
if event_ranking.avg_placement == 1:
bonus_points += 8
hanchan.player_comment += u'+8 Pkt: alle Spiele des Turnieres gewonnen. '
if bonus_points and self.dan:
hanchan.dan_points += bonus_points
self.dan_points += bonus_points
elif bonus_points:
hanchan.kyu_points += bonus_points
self.kyu_points += bonus_points
hanchan.bonus_points += bonus_points
if bonus_points and self.dan:
hanchan.dan_points += bonus_points
self.dan_points += bonus_points
elif bonus_points:
hanchan.kyu_points += bonus_points
self.kyu_points += bonus_points
hanchan.bonus_points += bonus_points
return True
def get_absolute_url(self):
if self.dan or self.dan_points > 0:
@@ -363,32 +428,33 @@ class KyuDanRanking(models.Model):
Fetches all valid Hanchans from this Player and recalculates his
Kyu/Dan Ranking.
"""
self.kyu_points = self.legacy_kyu_points or 0
self.dan_points = self.legacy_dan_points or 0
self.dan = None
self.dan_points = self.legacy_dan_points or 0
self.kyu = None
self.won_hanchans = 0
self.good_hanchans = 0
self.kyu_points = self.legacy_kyu_points or 0
self.hanchan_count = self.legacy_hanchan_count or 0
logger.info("recalculating Kyu/Dan punkte for %s...", self.user)
self.good_hanchans = 0
self.won_hanchans = 0
logger.info("recalculating Kyu/Dan points for %s...", self.user)
self.update_rank()
valid_hanchans = Hanchan.objects.confirmed_hanchans(user=self.user)
valid_hanchans = valid_hanchans.order_by('start')
if self.legacy_date:
valid_hanchans = valid_hanchans.filter(start__gt=self.legacy_date)
self.hanchan_count = valid_hanchans.count()
self.hanchan_count += valid_hanchans.count()
for hanchan in valid_hanchans:
hanchan.get_playerdata(self.user)
hanchan.bonus_points=0
hanchan.player_comment=""
hanchan.bonus_points = 0
hanchan.player_comment = u""
self.update_hanchan_points(hanchan)
if hanchan.event.mahjong_tournament:
self.append_tournament_bonuspoints(hanchan)
self.update_rank()
self.append_3_in_a_row_bonuspoints(hanchan)
self.update_rank()
self.won_hanchans += 1 if hanchan.placement == 1 else 0
self.won_hanchans += 1 if hanchan.placement == 1 else 0
self.good_hanchans += 1 if hanchan.placement == 2 else 0
hanchan.update_playerdata(self.user)
hanchan.save(force_update=True)
@@ -447,7 +513,8 @@ class KyuDanRanking(models.Model):
hanchan.kyu_points -= (self.kyu_points + hanchan.kyu_points)
self.kyu_points += hanchan.kyu_points
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr aussagekräfig ist. Überarbeiten?
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr
# aussagekräfig ist. Überarbeiten?
def update_rank(self):
if self.dan and self.dan_points < 0:
self.dan_points = 0
@@ -493,7 +560,8 @@ class SeasonRanking(models.Model):
return reverse('player-ladder-score', args=[self.user.username])
def recalculate(self):
season_hanchans = Hanchan.objects.season_hanchans(user=self.user, season=self.season)
season_hanchans = Hanchan.objects.season_hanchans(
user=self.user, season=self.season)
sum_placement = 0
sum_score = 0
self.placement = None
@@ -501,7 +569,9 @@ class SeasonRanking(models.Model):
self.good_hanchans = 0
self.won_hanchans = 0
logger.info(u'Recalculate LadderRanking for Player %s in Season %s', self.user, self.season)
logger.info(
u'Recalculate LadderRanking for Player %s in Season %s',
self.user, self.season)
for hanchan in season_hanchans:
sum_placement += hanchan.placement
sum_score += hanchan.game_score
@@ -517,16 +587,21 @@ class SeasonRanking(models.Model):
def update_ranking(sender, instance, **kwargs):
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
logger.debug("Marking %s's kyu/dan for recalculation", user)
for user in (
instance.player1, instance.player2, instance.player3, instance.player4):
logger.debug("marking %s's kyu/dan for recalculation", user)
set_dirty(user=user.id)
logger.debug(
"marking event %s for recalculation.", instance.event)
set_dirty(event=instance.event_id, user=user.id)
if instance.season:
logger.debug("Marking %s's ladder %i season for recalculation.", user, instance.season)
logger.debug(
"marking %s's ladder %i season for recalculation.", user,
instance.season)
set_dirty(user=user.id, season=instance.season)
if instance.event.mahjong_tournament:
logger.debug("Marking tournament %s for recalculation.", instance.event)
set_dirty(event=instance.event_id, user=user.id)
set_dirty(season=instance.season)
models.signals.pre_delete.connect(update_ranking, sender=Hanchan)
models.signals.post_save.connect(update_ranking, sender=Hanchan)