6d68f6638f
Taken MR comments into account: * `and` is considered a binary operator, thus put at the beginning of the line when splitting a line, * same for `+`, * same for `.` (different reasons).
105 lines
4.1 KiB
Python
105 lines
4.1 KiB
Python
# coding: utf-8
|
|
|
|
from __future__ import division
|
|
|
|
from django.db.models import Max
|
|
|
|
import random
|
|
|
|
|
|
class Algorithm(object):
|
|
|
|
shows = None
|
|
ranks = None
|
|
origranks = None
|
|
double = None
|
|
|
|
def __init__(self, shows, members, choices):
|
|
"""Initialisation :
|
|
- on aggrège toutes les demandes pour chaque spectacle dans
|
|
show.requests
|
|
- on crée des tables de demandes pour chaque personne, afin de
|
|
pouvoir modifier les rankings"""
|
|
self.max_group = \
|
|
2 * choices.aggregate(Max('priority'))['priority__max']
|
|
self.shows = []
|
|
showdict = {}
|
|
for show in shows:
|
|
show.nrequests = 0
|
|
showdict[show] = show
|
|
show.requests = []
|
|
self.shows.append(show)
|
|
self.ranks = {}
|
|
self.origranks = {}
|
|
self.choices = {}
|
|
next_rank = {}
|
|
member_shows = {}
|
|
for member in members:
|
|
self.ranks[member] = {}
|
|
self.choices[member] = {}
|
|
next_rank[member] = 1
|
|
member_shows[member] = {}
|
|
for choice in choices:
|
|
member = choice.participant
|
|
if choice.spectacle in member_shows[member]:
|
|
continue
|
|
else:
|
|
member_shows[member][choice.spectacle] = True
|
|
showdict[choice.spectacle].requests.append(member)
|
|
showdict[choice.spectacle].nrequests += 2 if choice.double else 1
|
|
self.ranks[member][choice.spectacle] = next_rank[member]
|
|
next_rank[member] += 2 if choice.double else 1
|
|
self.choices[member][choice.spectacle] = choice
|
|
for member in members:
|
|
self.origranks[member] = dict(self.ranks[member])
|
|
|
|
def IncrementRanks(self, member, currank, increment=1):
|
|
for show in self.ranks[member]:
|
|
if self.ranks[member][show] > currank:
|
|
self.ranks[member][show] -= increment
|
|
|
|
def appendResult(self, l, member, show):
|
|
l.append((member,
|
|
self.ranks[member][show],
|
|
self.origranks[member][show],
|
|
self.choices[member][show].double))
|
|
|
|
def __call__(self, seed):
|
|
random.seed(seed)
|
|
results = []
|
|
shows = sorted(self.shows, key=lambda x: x.nrequests / x.slots,
|
|
reverse=True)
|
|
for show in shows:
|
|
# On regroupe tous les gens ayant le même rang
|
|
groups = dict([(i, []) for i in range(1, self.max_group + 1)])
|
|
for member in show.requests:
|
|
if self.ranks[member][show] == 0:
|
|
raise RuntimeError(member, show.title)
|
|
groups[self.ranks[member][show]].append(member)
|
|
# On passe à l'attribution
|
|
winners = []
|
|
losers = []
|
|
for i in range(1, self.max_group + 1):
|
|
group = list(groups[i])
|
|
random.shuffle(group)
|
|
for member in group:
|
|
if self.choices[member][show].double: # double
|
|
if len(winners) + 1 < show.slots:
|
|
self.appendResult(winners, member, show)
|
|
self.appendResult(winners, member, show)
|
|
elif not self.choices[member][show].autoquit \
|
|
and len(winners) < show.slots:
|
|
self.appendResult(winners, member, show)
|
|
self.appendResult(losers, member, show)
|
|
else:
|
|
self.appendResult(losers, member, show)
|
|
self.appendResult(losers, member, show)
|
|
self.IncrementRanks(member, i, 2)
|
|
else: # simple
|
|
if len(winners) < show.slots:
|
|
self.appendResult(winners, member, show)
|
|
else:
|
|
self.appendResult(losers, member, show)
|
|
self.IncrementRanks(member, i)
|
|
results.append((show, winners, losers))
|
|
return results
|