Commit e5294591 by Julian Arni

Foldit leaderboard w/o tests

parent e4312d67
...@@ -66,6 +66,14 @@ class FolditModule(XModule): ...@@ -66,6 +66,14 @@ class FolditModule(XModule):
PuzzleComplete.completed_puzzles(self.system.anonymous_student_id), PuzzleComplete.completed_puzzles(self.system.anonymous_student_id),
key=lambda d: (d['set'], d['subset'])) key=lambda d: (d['set'], d['subset']))
def puzzle_leaders(self, n=10):
"""
Returns a list of n pairs (user, score) corresponding to the top
scores; the pairs are in descending order of score.
"""
from foldit.models import Score
return [(e['username'], e['total_score']) for e in Score.get_tops_n(10)]
def get_html(self): def get_html(self):
""" """
...@@ -80,6 +88,7 @@ class FolditModule(XModule): ...@@ -80,6 +88,7 @@ class FolditModule(XModule):
'success': self.is_complete(), 'success': self.is_complete(),
'goal_level': goal_level, 'goal_level': goal_level,
'completed': self.completed_puzzles(), 'completed': self.completed_puzzles(),
'top_scores': self.puzzle_leaders(),
} }
return self.system.render_template('foldit.html', context) return self.system.render_template('foldit.html', context)
...@@ -97,6 +106,7 @@ class FolditModule(XModule): ...@@ -97,6 +106,7 @@ class FolditModule(XModule):
return 1 return 1
class FolditDescriptor(XmlDescriptor, EditingDescriptor): class FolditDescriptor(XmlDescriptor, EditingDescriptor):
""" """
Module for adding open ended response questions to courses Module for adding open ended response questions to courses
......
...@@ -26,17 +26,19 @@ class Score(models.Model): ...@@ -26,17 +26,19 @@ class Score(models.Model):
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
@staticmethod @staticmethod
def display_score(score): def display_score(score, sum_of=1):
""" """
Argument: Argument:
score (float), as stored in the DB score (float), as stored in the DB (i.e., "rosetta score")
sum_of (int): if this score is the sum of scores of individual
problems, how many elements are in that sum
Returns: Returns:
score (float), as displayed to the user in the game and in the leaderboard score (float), as displayed to the user in the game and in the leaderboard
""" """
# TODO: put in correct formula return (-score) * 10 + 8000 * sum_of
return -score
# TODO: delete this, incorporate it in get_tops_n
@staticmethod @staticmethod
def get_top_n(puzzle_id, n): def get_top_n(puzzle_id, n):
""" """
...@@ -52,7 +54,31 @@ class Score(models.Model): ...@@ -52,7 +54,31 @@ class Score(models.Model):
score: 8500}, ...] score: 8500}, ...]
""" """
scores = Score.objects.filter(puzzle_id=puzzle_id).order_by('-best_score')[:n] scores = Score.objects.filter(puzzle_id=puzzle_id).order_by('-best_score')[:n]
return [{'username': s.user.username, 'score': display_score(s.best_score)} return [{'username': s.user.username, 'score': Score.display_score(s.best_score)}
for s in scores]
@staticmethod
def get_tops_n(n, puzzles=['994559']):
"""
Arguments:
puzzles: a list of puzzle ids that we will use. If not specified,
defaults to puzzle used in 7012x.
n (int): number of top scores to return
Returns:
The top n sum of scores for puzzles in <puzzles>. Output is a list
of disctionaries, sorted by display_score:
[ {username: 'a_user',
score: 12000} ...]
"""
scores = Score.objects.filter(puzzle_id__in=puzzles).annotate(
total_score=models.Sum('best_score')).order_by(
'-total_score')[:n]
num = len(puzzles)
return [{'username': s.user.username,
'total_score': Score.display_score(s.total_score, num)}
for s in scores] for s in scores]
......
...@@ -10,6 +10,8 @@ from django.views.decorators.csrf import csrf_exempt ...@@ -10,6 +10,8 @@ from django.views.decorators.csrf import csrf_exempt
from foldit.models import Score, PuzzleComplete from foldit.models import Score, PuzzleComplete
from student.models import unique_id_for_user from student.models import unique_id_for_user
import re
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -38,6 +40,13 @@ def foldit_ops(request): ...@@ -38,6 +40,13 @@ def foldit_ops(request):
"user %s, scores json %r, verify %r", "user %s, scores json %r, verify %r",
request.user, puzzle_scores_json, pz_verify_json) request.user, puzzle_scores_json, pz_verify_json)
else: else:
# This is needed because we are not getting valid json - the
# value of ScoreType is an unquoted string. Right now regexes are
# quoting the string, but ideally the json itself would be fixed.
# To allow for fixes without breaking this, the regex should only
# match unquoted strings,
a = re.compile(r':([a-zA-Z]*),')
puzzle_scores_json = re.sub(a, ':"\g<1>",', puzzle_scores_json)
puzzle_scores = json.loads(puzzle_scores_json) puzzle_scores = json.loads(puzzle_scores_json)
responses.append(save_scores(request.user, puzzle_scores)) responses.append(save_scores(request.user, puzzle_scores))
...@@ -98,10 +107,22 @@ def save_scores(user, puzzle_scores): ...@@ -98,10 +107,22 @@ def save_scores(user, puzzle_scores):
# BestScore (energy), CurrentScore (Energy), ScoreVersion (int) # BestScore (energy), CurrentScore (Energy), ScoreVersion (int)
puzzle_id = score['PuzzleID'] puzzle_id = score['PuzzleID']
best_score = score['BestScore']
current_score = score['CurrentScore']
score_version = score['ScoreVersion']
# TODO: save the score # TODO: save the score
# SetPlayerPuzzleScoreResponse object # SetPlayerPuzzleScoreResponse object
Score.objects.get_or_create(
user=user,
unique_user_id=unique_id_for_user(user),
puzzle_id=puzzle_id,
best_score=best_score,
current_score=current_score,
score_version=score_version)
# TODO: get info from db instead?
score_responses.append({'PuzzleID': puzzle_id, score_responses.append({'PuzzleID': puzzle_id,
'Status': 'Success'}) 'Status': 'Success'})
......
...@@ -25,4 +25,21 @@ You have not yet gotten to level ${goal_level}. ...@@ -25,4 +25,21 @@ You have not yet gotten to level ${goal_level}.
% endfor % endfor
</table> </table>
</br>
<h3>Puzzle Leaderboard</h3>
<table>
<tr>
<th>User</th>
<th>Score</th>
</tr>
% for pair in top_scores:
<tr>
<td>${pair[0]}</td>
<td>${pair[1]}</td>
</tr>
% endfor
</table>
</section> </section>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment