work in progress on supporting science puzzles
This commit is contained in:
@@ -25,6 +25,36 @@ class Score(models.Model):
|
||||
score_version = models.IntegerField()
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@staticmethod
|
||||
def display_score(score):
|
||||
"""
|
||||
Argument:
|
||||
score (float), as stored in the DB
|
||||
|
||||
Returns:
|
||||
score (float), as displayed to the user in the game and in the leaderboard
|
||||
"""
|
||||
# TODO: put in correct formula
|
||||
return -score
|
||||
|
||||
@staticmethod
|
||||
def get_top_n(puzzle_id, n):
|
||||
"""
|
||||
Arguments:
|
||||
puzzle_id (int): id of the puzzle for which to look
|
||||
n (int): number of top scores to return.
|
||||
|
||||
Returns:
|
||||
The top (lowest energy, highest display score) n scores for the puzzle. If
|
||||
there are fewer than n, returns all. Output is a list of dictionaries, sorted
|
||||
by display_score:
|
||||
[ {username: 'a_user',
|
||||
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)}
|
||||
for s in scores]
|
||||
|
||||
|
||||
class PuzzleComplete(models.Model):
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from foldit.views import foldit_ops, verify_code
|
||||
from foldit.models import PuzzleComplete
|
||||
from foldit.models import PuzzleComplete, Score
|
||||
from student.models import UserProfile, unique_id_for_user
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
@@ -37,13 +37,19 @@ class FolditTestCase(TestCase):
|
||||
request.user = self.user
|
||||
return request
|
||||
|
||||
def test_SetPlayerPuzzleScores(self):
|
||||
|
||||
scores = [ {"PuzzleID": 994391,
|
||||
def make_puzzle_score_request(self, puzzle_ids, best_scores):
|
||||
"""
|
||||
Given lists of puzzle_ids and best_scores (must have same length), make a
|
||||
SetPlayerPuzzleScores request and return the response.
|
||||
"""
|
||||
def score_dict(puzzle_id, best_score):
|
||||
return {"PuzzleID": puzzle_id,
|
||||
"ScoreType": "score",
|
||||
"BestScore": 0.078034,
|
||||
"CurrentScore":0.080035,
|
||||
"ScoreVersion":23}]
|
||||
"BestScore": best_score,
|
||||
# current scores don't actually matter
|
||||
"CurrentScore": best_score + 0.01,
|
||||
"ScoreVersion": 23}
|
||||
scores = [score_dict(pid, bs) for pid, bs in zip(puzzle_ids, best_scores)]
|
||||
scores_str = json.dumps(scores)
|
||||
|
||||
verify = {"Verify": verify_code(self.user.email, scores_str),
|
||||
@@ -55,51 +61,76 @@ class FolditTestCase(TestCase):
|
||||
|
||||
response = foldit_ops(request)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
return response
|
||||
|
||||
def test_SetPlayerPuzzleScores(self):
|
||||
|
||||
puzzle_id = 994391
|
||||
best_score = 0.078034
|
||||
response = self.make_puzzle_score_request([puzzle_id], [best_score])
|
||||
|
||||
self.assertEqual(response.content, json.dumps(
|
||||
[{"OperationID": "SetPlayerPuzzleScores",
|
||||
"Value": [{
|
||||
"PuzzleID": 994391,
|
||||
"PuzzleID": puzzle_id,
|
||||
"Status": "Success"}]}]))
|
||||
|
||||
# There should now be a score in the db.
|
||||
top_10 = Score.get_top_n(puzzle_id, 10)
|
||||
self.assertEqual(len(top_10), 1)
|
||||
self.assertEqual(top_10[0]['score'], Score.display_score(best_score))
|
||||
|
||||
|
||||
def test_SetPlayerPuzzleScores_many(self):
|
||||
|
||||
scores = [ {"PuzzleID": 994391,
|
||||
"ScoreType": "score",
|
||||
"BestScore": 0.078034,
|
||||
"CurrentScore":0.080035,
|
||||
"ScoreVersion":23},
|
||||
|
||||
{"PuzzleID": 994392,
|
||||
"ScoreType": "score",
|
||||
"BestScore": 0.078000,
|
||||
"CurrentScore":0.080011,
|
||||
"ScoreVersion":23}]
|
||||
|
||||
scores_str = json.dumps(scores)
|
||||
|
||||
verify = {"Verify": verify_code(self.user.email, scores_str),
|
||||
"VerifyMethod":"FoldItVerify"}
|
||||
data = {'SetPlayerPuzzleScoresVerify': json.dumps(verify),
|
||||
'SetPlayerPuzzleScores': scores_str}
|
||||
|
||||
request = self.make_request(data)
|
||||
|
||||
response = foldit_ops(request)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = self.make_puzzle_score_request([1, 2], [0.078034, 0.080000])
|
||||
|
||||
self.assertEqual(response.content, json.dumps(
|
||||
[{"OperationID": "SetPlayerPuzzleScores",
|
||||
"Value": [{
|
||||
"PuzzleID": 994391,
|
||||
"PuzzleID": 1,
|
||||
"Status": "Success"},
|
||||
|
||||
{"PuzzleID": 994392,
|
||||
{"PuzzleID": 2,
|
||||
"Status": "Success"}]}]))
|
||||
|
||||
|
||||
|
||||
|
||||
def test_SetPlayerPuzzleScores_multiple(self):
|
||||
"""
|
||||
Check that multiple posts with the same id are handled properly
|
||||
(keep latest for each user, have multiple users work properly)
|
||||
"""
|
||||
orig_score = 0.07
|
||||
puzzle_id = 1
|
||||
response = self.make_puzzle_score_request([puzzle_id], [orig_score])
|
||||
|
||||
# There should now be a score in the db.
|
||||
top_10 = Score.get_top_n(puzzle_id, 10)
|
||||
self.assertEqual(len(top_10), 1)
|
||||
self.assertEqual(top_10[0]['score'], Score.display_score(best_score))
|
||||
|
||||
# Reporting a better score should overwrite
|
||||
better_score = 0.06
|
||||
response = self.make_puzzle_score_request([1], [better_score])
|
||||
|
||||
top_10 = Score.get_top_n(puzzle_id, 10)
|
||||
self.assertEqual(len(top_10), 1)
|
||||
self.assertEqual(top_10[0]['score'], Score.display_score(better_score))
|
||||
|
||||
# reporting a worse score shouldn't
|
||||
worse_score = 0.065
|
||||
response = self.make_puzzle_score_request([1], [worse_score])
|
||||
|
||||
top_10 = Score.get_top_n(puzzle_id, 10)
|
||||
self.assertEqual(len(top_10), 1)
|
||||
# should still be the better score
|
||||
self.assertEqual(top_10[0]['score'], Score.display_score(better_score))
|
||||
|
||||
|
||||
|
||||
def test_SetPlayerPuzzleScores_error(self):
|
||||
|
||||
scores = [ {"PuzzleID": 994391,
|
||||
|
||||
Reference in New Issue
Block a user