from functools import total_ordering
from oioioi.contests.scores import IntegerScore, ScoreValue
@total_ordering
[docs]class ScoreDistribution(object):
def __init__(self, scores=None):
if scores:
assert isinstance(scores, list)
assert len(scores) == 10
self.scores = scores
else:
self.scores = [0] * 10
[docs] def __add__(self, other):
return ScoreDistribution([a + b for (a, b) in zip(self.scores, other.scores)])
[docs] def __eq__(self, other):
return self.scores == other.scores
[docs] def __lt__(self, other):
return self.scores < other.scores
[docs] def update(self, score):
assert score >= 0 and score <= 10
if score > 0:
self.scores[10 - score] += 1
[docs] def __repr__(self):
return 'ScoreDistribution(%s)' % ', '.join(
['%d: %d' % p for p in zip(reversed(list(range(1, 11))), self.scores)]
)
[docs] def _to_repr(self):
return ':'.join(['%05d' % p for p in self.scores])
@classmethod
[docs] def _from_repr(cls, value):
return cls([int(p) for p in value.split(':')])
@total_ordering
[docs]class PAScore(ScoreValue):
"""PA style score.
It consists of a number of points scored, together with their
distribution.
When two users get the same number of points, then the number of tasks
for which they got 10pts (maximal score) is taken into consideration.
If this still does not break the tie, number of 9 point scores is
considered, then 8 point scores etc.
"""
def __init__(self, points=None, distribution=None):
if points:
assert isinstance(points, IntegerScore)
self.points = points
else:
self.points = IntegerScore(0)
if distribution:
assert isinstance(distribution, ScoreDistribution)
self.distribution = distribution
else:
self.distribution = ScoreDistribution()
self.distribution.update(self.points.value)
[docs] def __add__(self, other):
return PAScore(
self.points + other.points, self.distribution + other.distribution
)
[docs] def __eq__(self, other):
if not isinstance(other, PAScore):
return self.points == other
return (self.points, self.distribution) == (other.points, other.distribution)
[docs] def __lt__(self, other):
if not isinstance(other, PAScore):
return self.points < other
return (self.points, self.distribution) < (other.points, other.distribution)
[docs] def __unicode__(self):
return str(self.points)
[docs] def __repr__(self):
return "PAScore(%r, %r)" % (self.points, self.distribution)
[docs] def __str__(self):
return str(self.points)
@classmethod
[docs] def _from_repr(cls, value):
points, distribution = value.split(';')
return cls(
points=IntegerScore._from_repr(points),
distribution=ScoreDistribution._from_repr(distribution),
)
[docs] def _to_repr(self):
return '%s;%s' % (self.points._to_repr(), self.distribution._to_repr())
[docs] def to_int(self):
return self.points.to_int()