Foldit leaderboard w/o tests
This commit is contained in:
@@ -66,6 +66,14 @@ class FolditModule(XModule):
|
||||
PuzzleComplete.completed_puzzles(self.system.anonymous_student_id),
|
||||
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):
|
||||
"""
|
||||
@@ -80,6 +88,7 @@ class FolditModule(XModule):
|
||||
'success': self.is_complete(),
|
||||
'goal_level': goal_level,
|
||||
'completed': self.completed_puzzles(),
|
||||
'top_scores': self.puzzle_leaders(),
|
||||
}
|
||||
|
||||
return self.system.render_template('foldit.html', context)
|
||||
@@ -97,6 +106,7 @@ class FolditModule(XModule):
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
class FolditDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
"""
|
||||
Module for adding open ended response questions to courses
|
||||
|
||||
@@ -26,17 +26,19 @@ class Score(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@staticmethod
|
||||
def display_score(score):
|
||||
def display_score(score, sum_of=1):
|
||||
"""
|
||||
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:
|
||||
score (float), as displayed to the user in the game and in the leaderboard
|
||||
"""
|
||||
# TODO: put in correct formula
|
||||
return -score
|
||||
return (-score) * 10 + 8000 * sum_of
|
||||
|
||||
# TODO: delete this, incorporate it in get_tops_n
|
||||
@staticmethod
|
||||
def get_top_n(puzzle_id, n):
|
||||
"""
|
||||
@@ -52,9 +54,33 @@ class Score(models.Model):
|
||||
score: 8500}, ...]
|
||||
"""
|
||||
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]
|
||||
|
||||
|
||||
class PuzzleComplete(models.Model):
|
||||
"""
|
||||
|
||||
@@ -10,6 +10,8 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from foldit.models import Score, PuzzleComplete
|
||||
from student.models import unique_id_for_user
|
||||
|
||||
import re
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -38,6 +40,13 @@ def foldit_ops(request):
|
||||
"user %s, scores json %r, verify %r",
|
||||
request.user, puzzle_scores_json, pz_verify_json)
|
||||
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)
|
||||
responses.append(save_scores(request.user, puzzle_scores))
|
||||
|
||||
@@ -98,10 +107,22 @@ def save_scores(user, puzzle_scores):
|
||||
# BestScore (energy), CurrentScore (Energy), ScoreVersion (int)
|
||||
|
||||
puzzle_id = score['PuzzleID']
|
||||
best_score = score['BestScore']
|
||||
current_score = score['CurrentScore']
|
||||
score_version = score['ScoreVersion']
|
||||
|
||||
# TODO: save the score
|
||||
|
||||
# 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,
|
||||
'Status': 'Success'})
|
||||
|
||||
|
||||
@@ -25,4 +25,21 @@ You have not yet gotten to level ${goal_level}.
|
||||
% endfor
|
||||
</table>
|
||||
|
||||
</section>
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user