Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Make algorithm score setting consistent with presence of model solutions #1585

Merged
merged 7 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 176 additions & 163 deletions Pipfile.lock

Large diffs are not rendered by default.

34 changes: 31 additions & 3 deletions game/admin.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,54 @@
from django.contrib import admin

from game.models import Level, Block, Episode, Workspace, LevelDecor
from game.models import Level, Block, Episode, Workspace, LevelDecor, Attempt


class LevelAdmin(admin.ModelAdmin):
search_fields = ["name", "id", "owner__user__username", "owner__user__first_name"]
search_fields = [
"name",
"id",
"owner__user__username",
"owner__user__first_name",
]
raw_id_fields = ["next_level", "locked_for_class"]
readonly_fields = ["owner"]
list_display = ["name", "id", "episode", "owner"]


class EpisodeAdmin(admin.ModelAdmin):
list_display = ["id", "name"]


class WorkspaceAdmin(admin.ModelAdmin):
raw_id_fields = ["owner"]


class AttemptAdmin(admin.ModelAdmin):
search_fields = [
"level",
"student",
"start_time",
"finish_time",
"is_best_attempt",
]
raw_id_fields = ["student"]
list_display = [
"level",
"student",
"start_time",
"finish_time",
"is_best_attempt",
]


class LevelDecorAdmin(admin.ModelAdmin):
search_fields = ["level__name"]
list_display = ["id", "level", "x", "y", "decorName"]


admin.site.register(Level, LevelAdmin)
admin.site.register(Episode, EpisodeAdmin)
admin.site.register(Workspace, WorkspaceAdmin)
admin.site.register(Episode)
admin.site.register(Block)
admin.site.register(Attempt, AttemptAdmin)
admin.site.register(LevelDecor, LevelDecorAdmin)
26 changes: 13 additions & 13 deletions game/end_to_end_tests/test_play_through.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,43 +278,43 @@ def test_level_079(self):
self._complete_level(79)

def test_episode_10(self):
self._complete_episode(10, 80, check_algorithm_score=False)
self._complete_episode(10, 80)

def test_level_080(self):
self._complete_level(80, check_algorithm_score=False)
self._complete_level(80)

def test_level_081(self):
self._complete_level(81, check_algorithm_score=False)
self._complete_level(81)

def test_level_082(self):
self._complete_level(82, check_algorithm_score=False)
self._complete_level(82)

def test_level_083(self):
self._complete_level(83, check_algorithm_score=False)
self._complete_level(83)

def test_level_084(self):
self._complete_level(84, check_algorithm_score=False)
self._complete_level(84)

def test_level_085(self):
self._complete_level(85, check_algorithm_score=False)
self._complete_level(85)

def test_level_086(self):
self._complete_level(86, check_algorithm_score=False)
self._complete_level(86)

def test_level_087(self):
self._complete_level(87, check_algorithm_score=False)
self._complete_level(87)

def test_level_088(self):
self._complete_level(88, check_algorithm_score=False)
self._complete_level(88)

def test_level_089(self):
self._complete_level(89, check_algorithm_score=False)
self._complete_level(89)

def test_level_090(self):
self._complete_level(90, check_algorithm_score=False)
self._complete_level(90)

def test_level_091(self):
self._complete_level(91, check_algorithm_score=False)
self._complete_level(91)

def test_episode_11(self):
self._complete_episode(11, 92, check_algorithm_score=False)
Expand Down
122 changes: 122 additions & 0 deletions game/migrations/0090_add_missing_model_solutions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import re

from django.apps.registry import Apps
from django.db import migrations


def add_missing_model_solutions(apps: Apps, *args):
Level = apps.get_model("game", "Level")

model_solutions = {
"80": "[5]",
"81": "[10]",
"82": "[11]",
"83": "[5]",
"84": "[5]",
"85": "[3]",
"86": "[8]",
"87": "[8]",
"88": "[11]",
"89": "[11]",
"90": "[15]",
"91": "[15]",
}

for level_name, model_solution in model_solutions.items():
count = Level.objects.filter(name=level_name).update(
model_solution=model_solution, disable_algorithm_score=False
)
assert count == 1

Attempt = apps.get_model("game", "Attempt")

attempts = Attempt.objects.filter(
level__name__in=[
"80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"90",
"91",
],
score=10,
).prefetch_related("level")

for attempt in attempts.iterator(chunk_size=500):
workspace = attempt.workspace

Check warning on line 52 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L52

Added line #L52 was not covered by tests

# Get number of blocks from solution - 1 to discount Start block
number_of_blocks = len(re.findall("<block", workspace)) - 1

Check warning on line 55 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L55

Added line #L55 was not covered by tests

model_solution = model_solutions[attempt.level.name]

Check warning on line 57 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L57

Added line #L57 was not covered by tests

ideal_number_of_blocks = int(

Check warning on line 59 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L59

Added line #L59 was not covered by tests
model_solution.replace("[", "").replace("]", "")
)

if number_of_blocks == ideal_number_of_blocks:
attempt.score = 20

Check warning on line 64 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L63-L64

Added lines #L63 - L64 were not covered by tests
else:
difference = abs(number_of_blocks - ideal_number_of_blocks)

Check warning on line 66 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L66

Added line #L66 was not covered by tests

if difference < 10:
attempt.score += 10 - difference

Check warning on line 69 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L68-L69

Added lines #L68 - L69 were not covered by tests

attempt.save()

Check warning on line 71 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L71

Added line #L71 was not covered by tests


def remove_new_model_solutions(apps: Apps, *args):
Level = apps.get_model("game", "Level")

Check warning on line 75 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L75

Added line #L75 was not covered by tests

Level.objects.filter(

Check warning on line 77 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L77

Added line #L77 was not covered by tests
name__in=[
"80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"90",
"91",
]
).update(model_solution="[]", disable_algorithm_score=True)

Attempt = apps.get_model("game", "Attempt")

Check warning on line 94 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L94

Added line #L94 was not covered by tests

Attempt.objects.filter(

Check warning on line 96 in game/migrations/0090_add_missing_model_solutions.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0090_add_missing_model_solutions.py#L96

Added line #L96 was not covered by tests
level__name__in=[
"80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"90",
"91",
],
score__gt=10,
).update(score=10)


class Migration(migrations.Migration):
dependencies = [("game", "0089_episodes_in_development")]
operations = [
migrations.RunPython(
add_missing_model_solutions,
reverse_code=remove_new_model_solutions,
)
]
40 changes: 40 additions & 0 deletions game/migrations/0091_disable_algo_score_if_no_model_solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from django.apps.registry import Apps
from django.db import migrations


def disable_algo_score_for_levels_without_model_solution(apps: Apps, *args):
Level = apps.get_model("game", "Level")

Level.objects.filter(default=True, model_solution="[]").update(
disable_algorithm_score=True
)

Attempt = apps.get_model("game", "Attempt")

Attempt.objects.filter(
level__default=True, level__model_solution="[]", score=20
).update(score=10)


def enable_algo_score_for_levels_without_model_solution(apps: Apps, *args):
Level = apps.get_model("game", "Level")

Check warning on line 20 in game/migrations/0091_disable_algo_score_if_no_model_solution.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0091_disable_algo_score_if_no_model_solution.py#L20

Added line #L20 was not covered by tests

Level.objects.filter(default=True, model_solution="[]").update(

Check warning on line 22 in game/migrations/0091_disable_algo_score_if_no_model_solution.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0091_disable_algo_score_if_no_model_solution.py#L22

Added line #L22 was not covered by tests
disable_algorithm_score=False
)

Attempt = apps.get_model("game", "Attempt")

Check warning on line 26 in game/migrations/0091_disable_algo_score_if_no_model_solution.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0091_disable_algo_score_if_no_model_solution.py#L26

Added line #L26 was not covered by tests

Attempt.objects.filter(

Check warning on line 28 in game/migrations/0091_disable_algo_score_if_no_model_solution.py

View check run for this annotation

Codecov / codecov/patch

game/migrations/0091_disable_algo_score_if_no_model_solution.py#L28

Added line #L28 was not covered by tests
level__default=True, level__model_solution="[]", score=10
).update(score=20)


class Migration(migrations.Migration):
dependencies = [("game", "0090_add_missing_model_solutions")]
operations = [
migrations.RunPython(
disable_algo_score_for_levels_without_model_solution,
reverse_code=enable_algo_score_for_levels_without_model_solution,
)
]
20 changes: 11 additions & 9 deletions game/static/game/js/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ ocargo.Game.prototype.setup = function () {
}
}


// Function being called when there is a change in game level.
ocargo.Game.prototype.onLevelChange = function() {
const currentLevelId = LEVEL_ID;
localStorage.setItem('currentEpisode', EPISODE);
const currentLevelId = LEVEL_ID;
localStorage.setItem('currentEpisode', EPISODE);
}

restoreCmsLogin()
Expand Down Expand Up @@ -123,7 +123,7 @@ ocargo.Game.prototype.onLevelChange = function() {
}

this.drawing.enablePanning()

const showMascot = BLOCKLY_ENABLED && !PYTHON_VIEW_ENABLED && LEVEL_NAME <= 80; // show mascot on Blockly-only levels that are not above 80

ocargo.Drawing.startPopup(
Expand All @@ -146,7 +146,7 @@ document.addEventListener("DOMContentLoaded", function() {
if (currentEpisode) {
localStorage.setItem('currentEpisode', currentEpisode);
}
});
});

ocargo.Game.prototype.clearWorkspaceNameInputInSaveTab = function () {
$('#workspaceNameInput').val('')
Expand Down Expand Up @@ -238,10 +238,12 @@ ocargo.Game.prototype.sendAttempt = function (score) {
return /^(GET|HEAD|OPTIONS|TRACE)$/.test(method)
}

// hack scores so that it works for demo and python TODO implement max scores and remove this!!
if (PYTHON_ENABLED) {
score *= 2
}
// TODO: Remove below - keeping it for now as a reminder that we need to
// implement some kind of algorithm score for Python levels.
// // hack scores so that it works for demo and python TODO implement max scores and remove this!!
// if (PYTHON_ENABLED) {
// score *= 2
// }

// Check that we should actually be sending an attempt - either if only blockly is enabled
// or if python is enabled and we're on the python tab (assumes they don't change tab quickly...)
Expand Down
Loading
Loading