changed up a few things regarding scoring, added some usability features

This commit is contained in:
root 2020-06-16 13:31:05 +02:00
parent 00d0df4af7
commit 953f2eeb46
9 changed files with 64 additions and 30 deletions

View File

@ -0,0 +1,22 @@
# Generated by Django 2.2.4 on 2020-06-10 15:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0005_auto_20200117_0023'),
]
operations = [
migrations.RemoveField(
model_name='challenge',
name='average',
),
migrations.AlterField(
model_name='challenge',
name='name',
field=models.CharField(blank=True, db_index=True, max_length=255, verbose_name='Challenge Name'),
),
]

View File

@ -1,6 +1,7 @@
import os import os
import random import random
import uuid import uuid
import math
from django.contrib.postgres.search import SearchVectorField, SearchQuery, SearchVector from django.contrib.postgres.search import SearchVectorField, SearchQuery, SearchVector
from django.conf import settings from django.conf import settings
@ -51,20 +52,14 @@ class User(AbstractUser):
class Challenge(models.Model): class Challenge(models.Model):
name = models.CharField(_('Challenge Name'), max_length=255, blank=False, db_index=True) name = models.CharField(_('Challenge Name'), max_length=255, blank=True, db_index=True)
average = models.PositiveIntegerField(default=0)
user = models.ForeignKey(User, models.PROTECT, user = models.ForeignKey(User, models.PROTECT,
related_name='challenge_user', related_name='challenge_user',
null=False, blank=False) null=False, blank=False)
def update_average_score(self):
average = GameRound.objects.filter(game__challenge=self).aggregate(Avg('result')).get('result__avg', 0)
self.average = average
self.save()
return average
def setup_challenge(self, user): def setup_challenge(self, user):
rounds = Coord.objects.filter(challenge=self) rounds = Coord.objects.filter(challenge=self)
#setup games with max score
game = Game.objects.create( game = Game.objects.create(
challenge=self, challenge=self,
start=timezone.now(), start=timezone.now(),
@ -82,6 +77,18 @@ class Challenge(models.Model):
round_id = round.id round_id = round.id
return game.id, round_id return game.id, round_id
@property
def average(self):
#this should be cached, but with low volumes its fine as is
return int(round(Game.objects.filter(challenge=self).aggregate(Avg('score')).get('score__avg', 0)))
@property
def num_rounds(self):
return Coord.objects.filter(challenge=self).count()
def num_plays(self):
return Game.objects.filter(challenge=self).count()
class Coord(models.Model): class Coord(models.Model):
lng = models.CharField(_('longitude'), max_length=50, null=False, blank=False) lng = models.CharField(_('longitude'), max_length=50, null=False, blank=False)
@ -132,5 +139,13 @@ class GameRound(models.Model):
else: else:
actual_coord = (self.coord.lat, self.coord.lng,) actual_coord = (self.coord.lat, self.coord.lng,)
guess_coord = (self.guess_lat, self.guess_lng,) guess_coord = (self.guess_lat, self.guess_lng,)
self.result = distance.distance(actual_coord, guess_coord).km * 1000 #get distance in meters between actual coord and the guess
dst = distance.distance(actual_coord, guess_coord).km * 1000
#calculate a score of 0 to 100
if dst < 100:
self.result = 100
elif dst > 100000:
self.result = 0
else:
self.result = int(round(14.46 * (11.52 - math.log(dst))))
super().save(*args, **kwargs) super().save(*args, **kwargs)

View File

@ -118,6 +118,7 @@ class EditChallengeView(views.UserPassesTestMixin, TemplateView):
context['challenge'] = challenge context['challenge'] = challenge
context['formset'] = ChallengeCoordFormSet(queryset=Coord.objects.none()) context['formset'] = ChallengeCoordFormSet(queryset=Coord.objects.none())
context['coords'] = Coord.objects.filter(challenge=challenge) context['coords'] = Coord.objects.filter(challenge=challenge)
#add form so users can edit the challenge name
return context return context
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
@ -161,7 +162,7 @@ class ChallengeListView(views.LoginRequiredMixin, ListView):
values('challenge').\ values('challenge').\
distinct() distinct()
return Challenge.objects.filter(id__in=ids).order_by('average') return Challenge.objects.filter(id__in=ids).order_by('id')
class NewGameView(views.LoginRequiredMixin, View): class NewGameView(views.LoginRequiredMixin, View):
@ -241,6 +242,7 @@ class RoundView(views.UserPassesTestMixin, UpdateView):
) )
) )
class RemoveCoordView(View): class RemoveCoordView(View):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
round = get_object_or_404(GameRound, pk=self.kwargs.get('round_pk', 0)) round = get_object_or_404(GameRound, pk=self.kwargs.get('round_pk', 0))
@ -249,7 +251,7 @@ class RemoveCoordView(View):
dodgy_coord.report() dodgy_coord.report()
if game.challenge: if game.challenge:
round.score = 30000 round.score = 100
round.guess_lat = 0 round.guess_lat = 0
round.guess_lng = 0 round.guess_lng = 0
round.save() round.save()
@ -269,7 +271,6 @@ class RemoveCoordView(View):
) )
) )
else: else:
round.game.challenge.update_average_score()
return redirect( return redirect(
reverse_lazy( reverse_lazy(
'game:end-recap-view', 'game:end-recap-view',
@ -320,7 +321,7 @@ class RoundRecapView(views.UserPassesTestMixin, TemplateView):
context['guess_lat'] = round.guess_lat context['guess_lat'] = round.guess_lat
context['guess_lng'] = round.guess_lng context['guess_lng'] = round.guess_lng
context['game_id'] = round.game.id context['game_id'] = round.game.id
context['distance'] = int(round.result) context['result'] = round.result
next_round = GameRound.objects.filter( next_round = GameRound.objects.filter(
game=round.game, game=round.game,
@ -328,11 +329,6 @@ class RoundRecapView(views.UserPassesTestMixin, TemplateView):
).first() ).first()
if not next_round: if not next_round:
#not every game is part of a challenge, so try updated the challenge average
try:
round.game.challenge.update_average_score()
except:
pass
context['last_round'] = True context['last_round'] = True
else: else:
context['next_round_id'] = next_round.id context['next_round_id'] = next_round.id
@ -361,14 +357,10 @@ class GameRecapView(views.UserPassesTestMixin, TemplateView):
) )
context['results'] = coord_results context['results'] = coord_results
context['average_distance'] = int( context['total_score'] = game.score
GameRound.objects.filter(game=game)\
.aggregate(Avg('result'))\
.get('result__avg', 0)
)
# not every game is part of a challenge, so keep this in a try # not every game is part of a challenge, so keep this in a try
try: try:
context['all_average'] = game.challenge.average context['all_average'] = game.challenge.average()
except: except:
pass pass
return context return context

View File

@ -24,7 +24,7 @@ with open(os.path.join(BASE_DIR, "env_secret_key.txt")) as secret_key:
SECRET_KEY = secret_key.read().strip() SECRET_KEY = secret_key.read().strip()
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False DEBUG = True
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']

View File

@ -15,12 +15,16 @@
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Average</th> <th>Average</th>
<th>Rounds</th>
<th>Plays</th>
<th></th> <th></th>
</tr> </tr>
{% for challenge in challenges %} {% for challenge in challenges %}
<tr> <tr>
<td>{{challenge.name}}</td> <td>{{challenge.name}}</td>
<td>{{challenge.average|intcomma}}</td> <td>{{challenge.average}}</td>
<td>{{challenge.num_rounds}}</td>
<td>{{challenge.num_plays}}</td>
<td><a class="btn btn-success btn-block" href="{% url 'game:new-game' %}?challenge={{challenge.id}}" role="button">Play</a></td> <td><a class="btn btn-success btn-block" href="{% url 'game:new-game' %}?challenge={{challenge.id}}" role="button">Play</a></td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -15,7 +15,7 @@
{{ form.non_field_errors }} {{ form.non_field_errors }}
{% csrf_token %} {% csrf_token %}
<div class="form-group form-row"> <div class="form-group form-row">
<label for="staticName" class="col-sm-4 col-form-label">Name</label> <label for="staticName" class="col-sm-4 col-form-label">Challenge Name</label>
<div class="col-sm-8"> <div class="col-sm-8">
{{form.name}} {{form.name}}
</div> </div>

View File

@ -14,7 +14,7 @@
{% endif %} {% endif %}
<div class="alert alert-info"> <div class="alert alert-info">
Your average guess was {{average_distance|intcomma}}m away.{% if all_average %} The average for this challenge is {{all_average|intcomma}}m{%endif%} Your total score was {{total_score}}.{% if all_average %} The average for this challenge is {{all_average}}{%endif%}
</div> </div>
<div id="map" class="guessMap"></div> <div id="map" class="guessMap"></div>

View File

@ -14,7 +14,7 @@
{% endif %} {% endif %}
<div class="alert alert-info"> <div class="alert alert-info">
Your guess was {{distance|intcomma}}m away. You scored {{result}} out of 100.
</div> </div>
<div id="map" class="guessMap"></div> <div id="map" class="guessMap"></div>

View File

@ -6,6 +6,7 @@ django-allauth==0.39.1
django-autocomplete-light==3.4.1 django-autocomplete-light==3.4.1
django-braces==1.13.0 django-braces==1.13.0
django-countries==5.4 django-countries==5.4
django-dynamic-formsets==0.0.8
django-extensions==2.2.1 django-extensions==2.2.1
django-starfield==1.0.post1 django-starfield==1.0.post1
geographiclib==1.49 geographiclib==1.49