From 8b8d5725552e390a426f58ceee7d4883d561c55e Mon Sep 17 00:00:00 2001 From: Florian Aucomte <33633200+faucomte97@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:02:13 +0000 Subject: [PATCH] feat: Create levels 110-122 (#1509) * Improve RR admin models * Add decor coordinates to list * Update migration to include paths, destinations, origins, level types, blocks and decors * Add level solutions, tests and counting of new blocks towards solution score * Remove logs * Merge branch 'master' into while_loop_levels * Bulk actions * Merge remote-tracking branch 'origin/while_loop_levels' into while_loop_levels * Remove unnecessary code --- Pipfile.lock | 57 ++--- game/admin.py | 10 +- game/end_to_end_tests/test_play_through.py | 45 +++- game/messages.py | 2 +- game/migrations/0086_loop_levels.py | 245 +++++++++++++++++---- game/static/game/js/blocklyControl.js | 9 +- game/urls.py | 2 +- game/views/level.py | 23 +- game/views/level_solutions.py | 109 +++++++++ 9 files changed, 409 insertions(+), 93 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 9796a5d6e..e84a4b4ad 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -26,10 +26,10 @@ }, "asttokens": { "hashes": [ - "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e", - "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69" + "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", + "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" ], - "version": "==2.4.0" + "version": "==2.4.1" }, "backcall": { "hashes": [ @@ -48,10 +48,10 @@ }, "cfl-common": { "hashes": [ - "sha256:089e9fe545fa069fa6198c88d6f58092d65f847a4ef63e91ca700dcf1ccc450a", - "sha256:fa42d51a85191adb98d0ee9aa65deed5ada41166dc7bb0328e27fddc6fa7d69d" + "sha256:5e206380535272c90eae963e1e45290f3de50057a814f79a50ed0c66d41eb0ca", + "sha256:d46ecb04dddce754aa586fa8209dcf33256e47e92f79e76362e9c6970b4d90cc" ], - "version": "==6.37.2" + "version": "==6.37.3" }, "charset-normalizer": { "hashes": [ @@ -266,10 +266,11 @@ }, "executing": { "hashes": [ - "sha256:06df6183df67389625f4e763921c6cf978944721abf3e714000200aab95b0657", - "sha256:0ff053696fdeef426cda5bd18eacd94f82c91f49823a2e9090124212ceea9b08" + "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", + "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc" ], - "version": "==2.0.0" + "markers": "python_version >= '3.5'", + "version": "==2.0.1" }, "idna": { "hashes": [ @@ -496,7 +497,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "pytz": { @@ -586,7 +587,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sqlparse": { @@ -621,11 +622,11 @@ }, "traitlets": { "hashes": [ - "sha256:81539f07f7aebcde2e4b5ab76727f53eabf18ad155c6ed7979a681411602fa47", - "sha256:833273bf645d8ce31dcb613c56999e2e055b1ffe6d09168a164bcd91c36d5d35" + "sha256:9b232b9430c8f57288c1024b34a8f0251ddcc47268927367a0dd3eeaca40deb5", + "sha256:baf991e61542da48fe8aef8b779a9ea0aa38d8a54166ee250d5af5ecf4486619" ], "markers": "python_version >= '3.8'", - "version": "==5.12.0" + "version": "==5.13.0" }, "typing-extensions": { "hashes": [ @@ -653,10 +654,10 @@ }, "wcwidth": { "hashes": [ - "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704", - "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4" + "sha256:9a929bd8380f6cd9571a968a9c8f4353ca58d7cd812a4822bba831f8d685b223", + "sha256:a675d1a4a2d24ef67096a04b85b02deeecd8e226f57b5e3a72dbb9ed99d27da8" ], - "version": "==0.2.8" + "version": "==0.2.9" }, "xlrd": { "hashes": [ @@ -715,10 +716,10 @@ }, "cfl-common": { "hashes": [ - "sha256:089e9fe545fa069fa6198c88d6f58092d65f847a4ef63e91ca700dcf1ccc450a", - "sha256:fa42d51a85191adb98d0ee9aa65deed5ada41166dc7bb0328e27fddc6fa7d69d" + "sha256:5e206380535272c90eae963e1e45290f3de50057a814f79a50ed0c66d41eb0ca", + "sha256:d46ecb04dddce754aa586fa8209dcf33256e47e92f79e76362e9c6970b4d90cc" ], - "version": "==6.37.2" + "version": "==6.37.3" }, "charset-normalizer": { "hashes": [ @@ -818,11 +819,11 @@ }, "codeforlife-portal": { "hashes": [ - "sha256:29552e17ecd265f5578dbbd214eca74940cf71ea0b5adb3d23cb7c62d927ad49", - "sha256:d04182d3a1df9f4c06dbe1702fa27fd9bf44f3352d21366e8c8342870cec9aaa" + "sha256:cb393cf7f8b6f552afeaa6926fac55399a57cb80febed9bfcc923b6d41f2c166", + "sha256:ded940d91a13a0971a146b98dde1d49d5df711dfac30674d5e0391bc26b2efa3" ], "index": "pypi", - "version": "==6.37.2" + "version": "==6.37.3" }, "defusedxml": { "hashes": [ @@ -1220,11 +1221,11 @@ }, "outcome": { "hashes": [ - "sha256:588ef4dc10b64e8df160d8d1310c44e1927129a66d6d2ef86845cef512c5f24c", - "sha256:7b688fd82db72f4b0bc9e883a00359d4d4179cd97d27f09c9644d0c842ba7786" + "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", + "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b" ], "markers": "python_version >= '3.7'", - "version": "==1.3.0" + "version": "==1.3.0.post0" }, "packaging": { "hashes": [ @@ -1432,7 +1433,7 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.8.2" }, "pytz": { @@ -1605,7 +1606,7 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sniffio": { diff --git a/game/admin.py b/game/admin.py index bf3a00d85..0d46a5253 100644 --- a/game/admin.py +++ b/game/admin.py @@ -1,10 +1,10 @@ from django.contrib import admin -from game.models import Level, Block, Episode, Workspace +from game.models import Level, Block, Episode, Workspace, LevelDecor class LevelAdmin(admin.ModelAdmin): - search_fields = ["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"] @@ -14,7 +14,13 @@ class WorkspaceAdmin(admin.ModelAdmin): raw_id_fields = ["owner"] +class LevelDecorAdmin(admin.ModelAdmin): + search_fields = ["level__name"] + list_display = ["id", "level", "x", "y", "decorName"] + + admin.site.register(Level, LevelAdmin) admin.site.register(Workspace, WorkspaceAdmin) admin.site.register(Episode) admin.site.register(Block) +admin.site.register(LevelDecor, LevelDecorAdmin) diff --git a/game/end_to_end_tests/test_play_through.py b/game/end_to_end_tests/test_play_through.py index 3e03d0764..391b55908 100644 --- a/game/end_to_end_tests/test_play_through.py +++ b/game/end_to_end_tests/test_play_through.py @@ -378,4 +378,47 @@ def test_level_108(self): self._complete_level(108, check_algorithm_score=False) def test_level_109(self): - self._complete_level(109, check_algorithm_score=False, final_level=True) + self._complete_level(109, check_algorithm_score=False) + + def test_episode_12(self): + self._complete_episode(12, 110, check_algorithm_score=False) + + def test_level_110(self): + self._complete_level(110, check_algorithm_score=False) + + def test_level_111(self): + self._complete_level(111, check_algorithm_score=False) + + def test_level_112(self): + self._complete_level(112) + + def test_level_113(self): + self._complete_level(113, check_algorithm_score=False) + + def test_level_114(self): + self._complete_level(114, check_algorithm_score=False) + + def test_level_115(self): + self._complete_level(115, check_algorithm_score=False) + + def test_level_116(self): + self._complete_level(116) + + def test_level_117(self): + self._complete_level(117) + + def test_level_118(self): + self._complete_level(118) + + def test_level_119(self): + self._complete_level(119, check_algorithm_score=False) + + def test_level_120(self): + self._complete_level(120, check_algorithm_score=False) + + def test_level_121(self): + self._complete_level(121, check_algorithm_score=False) + + def test_level_122(self): + self._complete_level(122, check_algorithm_score=False, final_level=True) + diff --git a/game/messages.py b/game/messages.py index 29934aafe..2a074c645 100644 --- a/game/messages.py +++ b/game/messages.py @@ -2422,7 +2422,7 @@ def hint_level109(): title_level114(), "This route is just a bit longer. Make sure you type the Python code accurately!", ), - lambda: "The most common errors here are missing the round brackets at the end of the commands or mis-typing the commands, e.g. use my_van.move_fowards() and not my_van.move_foward()", + lambda: "The most common errors here are missing the round brackets at the end of the commands or mistyping the commands, e.g. use my_van.move_fowards() and not my_van.move_foward()", ) ( diff --git a/game/migrations/0086_loop_levels.py b/game/migrations/0086_loop_levels.py index 300c86c54..84f6d546f 100644 --- a/game/migrations/0086_loop_levels.py +++ b/game/migrations/0086_loop_levels.py @@ -1,9 +1,16 @@ +import json + from django.apps.registry import Apps from django.db import migrations +from game.level_management import set_decor_inner, set_blocks_inner + def add_loop_levels(apps: Apps, *args): Level = apps.get_model("game", "Level") + LevelBlock = apps.get_model("game", "LevelBlock") + Block = apps.get_model("game", "Block") + LevelDecor = apps.get_model("game", "LevelDecor") Episode = apps.get_model("game", "Episode") episode_15 = Episode.objects.create( @@ -34,30 +41,25 @@ def add_loop_levels(apps: Apps, *args): level_153 = Level.objects.create( name="153", episode=episode_15, - path="", ) level_152 = Level.objects.create( name="152", episode=episode_15, - path="", next_level=level_153, ) level_151 = Level.objects.create( name="151", episode=episode_15, - path="", next_level=level_152, ) level_150 = Level.objects.create( name="150", episode=episode_15, - path="", next_level=level_151, ) level_149 = Level.objects.create( name="149", episode=episode_15, - path="", next_level=level_150, ) @@ -65,49 +67,41 @@ def add_loop_levels(apps: Apps, *args): level_148 = Level.objects.create( name="148", episode=episode_14, - path="", next_level=level_149, ) level_147 = Level.objects.create( name="147", episode=episode_14, - path="", next_level=level_148, ) level_146 = Level.objects.create( name="146", episode=episode_14, - path="", next_level=level_147, ) level_145 = Level.objects.create( name="145", episode=episode_14, - path="", next_level=level_146, ) level_144 = Level.objects.create( name="144", episode=episode_14, - path="", next_level=level_145, ) level_143 = Level.objects.create( name="143", episode=episode_14, - path="", next_level=level_144, ) level_142 = Level.objects.create( name="142", episode=episode_14, - path="", next_level=level_143, ) level_141 = Level.objects.create( name="141", episode=episode_14, - path="", next_level=level_142, ) @@ -115,109 +109,91 @@ def add_loop_levels(apps: Apps, *args): level_140 = Level.objects.create( name="140", episode=episode_13, - path="", next_level=level_141, ) level_139 = Level.objects.create( name="139", episode=episode_13, - path="", next_level=level_140, ) level_138 = Level.objects.create( name="138", episode=episode_13, - path="", next_level=level_139, ) level_137 = Level.objects.create( name="137", episode=episode_13, - path="", next_level=level_138, ) level_136 = Level.objects.create( name="136", episode=episode_13, - path="", next_level=level_137, ) level_135 = Level.objects.create( name="135", episode=episode_13, - path="", next_level=level_136, ) level_134 = Level.objects.create( name="134", episode=episode_13, - path="", next_level=level_135, ) level_133 = Level.objects.create( name="133", episode=episode_13, - path="", next_level=level_134, ) level_132 = Level.objects.create( name="132", episode=episode_13, - path="", next_level=level_133, ) level_131 = Level.objects.create( name="131", episode=episode_13, - path="", next_level=level_132, ) level_130 = Level.objects.create( name="130", episode=episode_13, - path="", next_level=level_131, ) level_129 = Level.objects.create( name="129", episode=episode_13, - path="", next_level=level_130, ) level_128 = Level.objects.create( name="128", episode=episode_13, - path="", next_level=level_129, ) level_127 = Level.objects.create( name="127", episode=episode_13, - path="", next_level=level_128, ) level_126 = Level.objects.create( name="126", episode=episode_13, - path="", next_level=level_127, ) level_125 = Level.objects.create( name="125", episode=episode_13, - path="", next_level=level_126, ) level_124 = Level.objects.create( name="124", episode=episode_13, - path="", next_level=level_125, ) level_123 = Level.objects.create( name="123", episode=episode_13, - path="", next_level=level_124, ) @@ -225,80 +201,251 @@ def add_loop_levels(apps: Apps, *args): level_122 = Level.objects.create( name="122", episode=episode_12, - path="", # next_level=level_123, TODO: connect them when the next levels are enabled. + path='[{"coordinate":[1,5],"connectedNodes":[1]},{"coordinate":[1,4],"connectedNodes":[0,2]},{"coordinate":[2,4],"connectedNodes":[1,3]},{"coordinate":[2,5],"connectedNodes":[4,2]},{"coordinate":[3,5],"connectedNodes":[3,5]},{"coordinate":[3,4],"connectedNodes":[4,6]},{"coordinate":[4,4],"connectedNodes":[5,7]},{"coordinate":[4,5],"connectedNodes":[8,6]},{"coordinate":[5,5],"connectedNodes":[7,9]},{"coordinate":[5,4],"connectedNodes":[8,10]},{"coordinate":[6,4],"connectedNodes":[9,11]},{"coordinate":[6,5],"connectedNodes":[12,10]},{"coordinate":[7,5],"connectedNodes":[11,13]},{"coordinate":[7,4],"connectedNodes":[12,14]},{"coordinate":[7,3],"connectedNodes":[13,15]},{"coordinate":[7,2],"connectedNodes":[14,16]},{"coordinate":[7,1],"connectedNodes":[17,15]},{"coordinate":[6,1],"connectedNodes":[18,16]},{"coordinate":[6,2],"connectedNodes":[19,17]},{"coordinate":[5,2],"connectedNodes":[18,20]},{"coordinate":[5,1],"connectedNodes":[21,19]},{"coordinate":[4,1],"connectedNodes":[22,20]},{"coordinate":[4,2],"connectedNodes":[23,21]},{"coordinate":[3,2],"connectedNodes":[22,24]},{"coordinate":[3,1],"connectedNodes":[25,23]},{"coordinate":[2,1],"connectedNodes":[26,24]},{"coordinate":[2,2],"connectedNodes":[27,25]},{"coordinate":[1,2],"connectedNodes":[26,28]},{"coordinate":[1,1],"connectedNodes":[27]}]', + origin='{"coordinate":[1,5],"direction":"S"}', + destinations="[[1,1]]", + default=True, + blocklyEnabled=False, + theme_name="grass", + character_name="Van", ) level_121 = Level.objects.create( name="121", episode=episode_12, - path="", next_level=level_122, + path='[{"coordinate":[1,7],"connectedNodes":[1]},{"coordinate":[1,6],"connectedNodes":[0,2,13]},{"coordinate":[2,6],"connectedNodes":[1,25,3]},{"coordinate":[2,5],"connectedNodes":[2,4]},{"coordinate":[3,5],"connectedNodes":[3,5]},{"coordinate":[3,4],"connectedNodes":[4,6]},{"coordinate":[4,4],"connectedNodes":[5,7]},{"coordinate":[4,3],"connectedNodes":[23,6,8]},{"coordinate":[5,3],"connectedNodes":[7,9]},{"coordinate":[5,2],"connectedNodes":[8,10]},{"coordinate":[6,2],"connectedNodes":[9,31,11]},{"coordinate":[6,1],"connectedNodes":[21,10,12]},{"coordinate":[7,1],"connectedNodes":[11,32]},{"coordinate":[1,5],"connectedNodes":[1,14]},{"coordinate":[1,4],"connectedNodes":[13,15]},{"coordinate":[1,3],"connectedNodes":[14,22,16]},{"coordinate":[1,2],"connectedNodes":[15,17]},{"coordinate":[1,1],"connectedNodes":[16,18]},{"coordinate":[2,1],"connectedNodes":[17,19]},{"coordinate":[3,1],"connectedNodes":[18,24,20]},{"coordinate":[4,1],"connectedNodes":[19,21]},{"coordinate":[5,1],"connectedNodes":[20,11]},{"coordinate":[2,3],"connectedNodes":[15,23]},{"coordinate":[3,3],"connectedNodes":[22,7,24]},{"coordinate":[3,2],"connectedNodes":[23,19]},{"coordinate":[3,6],"connectedNodes":[2,26]},{"coordinate":[4,6],"connectedNodes":[25,27]},{"coordinate":[5,6],"connectedNodes":[26,28]},{"coordinate":[6,6],"connectedNodes":[27,29]},{"coordinate":[6,5],"connectedNodes":[28,30]},{"coordinate":[6,4],"connectedNodes":[29,31]},{"coordinate":[6,3],"connectedNodes":[30,10]},{"coordinate":[7,0],"connectedNodes":[12]}]', + origin='{"coordinate":[1,7],"direction":"S"}', + destinations="[[7,0]]", + default=True, + blocklyEnabled=False, + theme_name="farm", + character_name="Van", ) level_120 = Level.objects.create( name="120", episode=episode_12, - path="", next_level=level_121, + path='[{"coordinate":[9,5],"connectedNodes":[1]},{"coordinate":[8,5],"connectedNodes":[2,0]},{"coordinate":[7,5],"connectedNodes":[1,3]},{"coordinate":[7,4],"connectedNodes":[4,2,20]},{"coordinate":[6,4],"connectedNodes":[5,3]},{"coordinate":[5,4],"connectedNodes":[13,4,6]},{"coordinate":[5,3],"connectedNodes":[7,5]},{"coordinate":[4,3],"connectedNodes":[8,6]},{"coordinate":[3,3],"connectedNodes":[7,9]},{"coordinate":[3,2],"connectedNodes":[10,8,24]},{"coordinate":[2,2],"connectedNodes":[11,9]},{"coordinate":[1,2],"connectedNodes":[19,10,12]},{"coordinate":[1,1],"connectedNodes":[25,11]},{"coordinate":[5,5],"connectedNodes":[14,5]},{"coordinate":[4,5],"connectedNodes":[15,13]},{"coordinate":[3,5],"connectedNodes":[16,14]},{"coordinate":[2,5],"connectedNodes":[17,15]},{"coordinate":[1,5],"connectedNodes":[16,18]},{"coordinate":[1,4],"connectedNodes":[17,19]},{"coordinate":[1,3],"connectedNodes":[18,11]},{"coordinate":[7,3],"connectedNodes":[3,21]},{"coordinate":[7,2],"connectedNodes":[22,20]},{"coordinate":[6,2],"connectedNodes":[23,21]},{"coordinate":[5,2],"connectedNodes":[24,22]},{"coordinate":[4,2],"connectedNodes":[9,23]},{"coordinate":[0,1],"connectedNodes":[12]}]', + origin='{"coordinate":[9,5],"direction":"W"}', + destinations="[[0,1]]", + default=True, + blocklyEnabled=False, + theme_name="grass", + character_name="Van", ) level_119 = Level.objects.create( name="119", episode=episode_12, - path="", next_level=level_120, + path='[{"coordinate":[2,3],"connectedNodes":[1]},{"coordinate":[2,2],"connectedNodes":[0,2]},{"coordinate":[3,2],"connectedNodes":[1,3]},{"coordinate":[3,1],"connectedNodes":[2,4]},{"coordinate":[4,1],"connectedNodes":[3,5]},{"coordinate":[5,1],"connectedNodes":[4,6]},{"coordinate":[5,2],"connectedNodes":[7,5]},{"coordinate":[6,2],"connectedNodes":[6,8]},{"coordinate":[6,3],"connectedNodes":[9,7]},{"coordinate":[6,4],"connectedNodes":[10,8]},{"coordinate":[5,4],"connectedNodes":[11,9]},{"coordinate":[5,5],"connectedNodes":[12,10]},{"coordinate":[4,5],"connectedNodes":[13,11]},{"coordinate":[3,5],"connectedNodes":[12]}]', + origin='{"coordinate":[2,3],"direction":"S"}', + destinations="[[3,5]]", + default=True, + blocklyEnabled=False, + theme_name="grass", + character_name="Van", ) level_118 = Level.objects.create( name="118", episode=episode_12, - path="", next_level=level_119, + path='[{"coordinate":[1,3],"connectedNodes":[1]},{"coordinate":[2,3],"connectedNodes":[0,2]},{"coordinate":[3,3],"connectedNodes":[1,3]},{"coordinate":[3,4],"connectedNodes":[4,2]},{"coordinate":[4,4],"connectedNodes":[3,5]},{"coordinate":[4,5],"connectedNodes":[6,4]},{"coordinate":[5,5],"connectedNodes":[5,7]},{"coordinate":[5,6],"connectedNodes":[8,6]},{"coordinate":[6,6],"connectedNodes":[7,9]},{"coordinate":[7,6],"connectedNodes":[8,10]},{"coordinate":[8,6],"connectedNodes":[9]}]', + origin='{"coordinate":[1,3],"direction":"E"}', + destinations="[[8,6]]", + default=True, + pythonEnabled=False, + pythonViewEnabled=True, + theme_name="snow", + character_name="Van", + model_solution="[11]", ) level_117 = Level.objects.create( name="117", episode=episode_12, - path="", next_level=level_118, + path='[{"coordinate":[2,2],"connectedNodes":[1]},{"coordinate":[3,2],"connectedNodes":[0,2]},{"coordinate":[3,3],"connectedNodes":[3,1]},{"coordinate":[4,3],"connectedNodes":[2,4]},{"coordinate":[4,4],"connectedNodes":[5,3]},{"coordinate":[5,4],"connectedNodes":[4,6]},{"coordinate":[5,5],"connectedNodes":[7,5]},{"coordinate":[6,5],"connectedNodes":[6,8]},{"coordinate":[6,6],"connectedNodes":[9,7]},{"coordinate":[7,6],"connectedNodes":[8]}]', + origin='{"coordinate":[2,2],"direction":"E"}', + destinations="[[7,6]]", + default=True, + pythonEnabled=False, + pythonViewEnabled=True, + theme_name="snow", + character_name="Van", + model_solution="[8]", ) level_116 = Level.objects.create( name="116", episode=episode_12, - path="", next_level=level_117, + path='[{"coordinate":[1,4],"connectedNodes":[1]},{"coordinate":[2,4],"connectedNodes":[0,2]},{"coordinate":[3,4],"connectedNodes":[1,3]},{"coordinate":[4,4],"connectedNodes":[2,4]},{"coordinate":[5,4],"connectedNodes":[3,5]},{"coordinate":[6,4],"connectedNodes":[4]}]', + origin='{"coordinate":[1,4],"direction":"E"}', + destinations="[[6,4]]", + default=True, + pythonEnabled=False, + theme_name="grass", + character_name="Van", + model_solution="[7]", ) level_115 = Level.objects.create( name="115", episode=episode_12, - path="", next_level=level_116, + path='[{"coordinate":[9,2],"connectedNodes":[1]},{"coordinate":[8,2],"connectedNodes":[26,0,2]},{"coordinate":[8,1],"connectedNodes":[3,1]},{"coordinate":[7,1],"connectedNodes":[4,2]},{"coordinate":[6,1],"connectedNodes":[5,20,3]},{"coordinate":[5,1],"connectedNodes":[6,4]},{"coordinate":[4,1],"connectedNodes":[7,5]},{"coordinate":[3,1],"connectedNodes":[8,6]},{"coordinate":[3,2],"connectedNodes":[9,7]},{"coordinate":[4,2],"connectedNodes":[8,10]},{"coordinate":[4,3],"connectedNodes":[11,9]},{"coordinate":[3,3],"connectedNodes":[12,10]},{"coordinate":[3,4],"connectedNodes":[13,11]},{"coordinate":[3,5],"connectedNodes":[14,12]},{"coordinate":[4,5],"connectedNodes":[13,15]},{"coordinate":[5,5],"connectedNodes":[14,16,17]},{"coordinate":[5,6],"connectedNodes":[21,15]},{"coordinate":[5,4],"connectedNodes":[15,18]},{"coordinate":[6,4],"connectedNodes":[17,19]},{"coordinate":[6,3],"connectedNodes":[18,27,20]},{"coordinate":[6,2],"connectedNodes":[19,4]},{"coordinate":[6,6],"connectedNodes":[16,22]},{"coordinate":[7,6],"connectedNodes":[21,23]},{"coordinate":[8,6],"connectedNodes":[22,24]},{"coordinate":[8,5],"connectedNodes":[23,25]},{"coordinate":[8,4],"connectedNodes":[24,26]},{"coordinate":[8,3],"connectedNodes":[27,25,1]},{"coordinate":[7,3],"connectedNodes":[19,26]}]', + origin='{"coordinate":[9,2],"direction":"W"}', + destinations="[[4,5]]", + default=True, + blocklyEnabled=False, + theme_name="grass", + character_name="Van", ) level_114 = Level.objects.create( name="114", episode=episode_12, - path="", next_level=level_115, + path='[{"coordinate":[0,2],"connectedNodes":[1]},{"coordinate":[1,2],"connectedNodes":[0,2]},{"coordinate":[1,3],"connectedNodes":[3,1]},{"coordinate":[1,4],"connectedNodes":[4,2]},{"coordinate":[1,5],"connectedNodes":[5,3]},{"coordinate":[2,5],"connectedNodes":[4,6]},{"coordinate":[2,4],"connectedNodes":[5,7]},{"coordinate":[3,4],"connectedNodes":[6,8]},{"coordinate":[3,3],"connectedNodes":[7,9]},{"coordinate":[3,2],"connectedNodes":[8,10]},{"coordinate":[3,1],"connectedNodes":[9,11]},{"coordinate":[4,1],"connectedNodes":[10,12]},{"coordinate":[4,2],"connectedNodes":[13,11]},{"coordinate":[5,2],"connectedNodes":[12]}]', + origin='{"coordinate":[0,2],"direction":"E"}', + destinations="[[5,2]]", + default=True, + blocklyEnabled=False, + theme_name="grass", + character_name="Van", ) level_113 = Level.objects.create( name="113", episode=episode_12, - path="", next_level=level_114, + path='[{"coordinate":[4,7],"connectedNodes":[1]},{"coordinate":[4,6],"connectedNodes":[0,2]},{"coordinate":[4,5],"connectedNodes":[3,1]},{"coordinate":[3,5],"connectedNodes":[2,4]},{"coordinate":[3,4],"connectedNodes":[3,5]},{"coordinate":[3,3],"connectedNodes":[4]}]', + origin='{"coordinate":[4,7],"direction":"S"}', + destinations="[[3,3]]", + default=True, + blocklyEnabled=False, + theme_name="farm", + character_name="Van", ) level_112 = Level.objects.create( name="112", episode=episode_12, - path="", next_level=level_113, + path='[{"coordinate":[2,7],"connectedNodes":[1]},{"coordinate":[2,6],"connectedNodes":[0,2]},{"coordinate":[3,6],"connectedNodes":[1,3,17]},{"coordinate":[4,6],"connectedNodes":[2,4]},{"coordinate":[5,6],"connectedNodes":[3,5]},{"coordinate":[6,6],"connectedNodes":[4,6]},{"coordinate":[6,5],"connectedNodes":[5,7]},{"coordinate":[6,4],"connectedNodes":[20,6,8]},{"coordinate":[6,3],"connectedNodes":[7,9]},{"coordinate":[6,2],"connectedNodes":[8,10]},{"coordinate":[6,1],"connectedNodes":[11,9]},{"coordinate":[5,1],"connectedNodes":[12,10]},{"coordinate":[4,1],"connectedNodes":[13,22,11]},{"coordinate":[3,1],"connectedNodes":[14,12]},{"coordinate":[2,1],"connectedNodes":[15,13]},{"coordinate":[1,1],"connectedNodes":[16,14]},{"coordinate":[0,1],"connectedNodes":[15]},{"coordinate":[3,5],"connectedNodes":[2,18]},{"coordinate":[3,4],"connectedNodes":[17,19]},{"coordinate":[4,4],"connectedNodes":[18,20,21]},{"coordinate":[5,4],"connectedNodes":[19,7]},{"coordinate":[4,3],"connectedNodes":[19,22]},{"coordinate":[4,2],"connectedNodes":[21,12]}]', + origin='{"coordinate":[2,7],"direction":"S"}', + destinations="[[0,1]]", + default=True, + pythonEnabled=False, + pythonViewEnabled=True, + theme_name="grass", + character_name="Van", + model_solution="[11]", ) level_111 = Level.objects.create( name="111", episode=episode_12, - path="", next_level=level_112, + path='[{"coordinate":[0,5],"connectedNodes":[1]},{"coordinate":[1,5],"connectedNodes":[0,2]},{"coordinate":[2,5],"connectedNodes":[1,3]},{"coordinate":[3,5],"connectedNodes":[2,4]},{"coordinate":[3,6],"connectedNodes":[5,3]},{"coordinate":[4,6],"connectedNodes":[4,6]},{"coordinate":[5,6],"connectedNodes":[5,7]},{"coordinate":[5,5],"connectedNodes":[6,8]},{"coordinate":[5,4],"connectedNodes":[7,9]},{"coordinate":[5,3],"connectedNodes":[8,10]},{"coordinate":[5,2],"connectedNodes":[9,11]},{"coordinate":[6,2],"connectedNodes":[10]}]', + origin='{"coordinate":[0,5],"direction":"E"}', + destinations="[[6,2]]", + default=True, + pythonEnabled=False, + pythonViewEnabled=True, + theme_name="grass", + character_name="Van", ) level_110 = Level.objects.create( name="110", episode=episode_12, - path="", next_level=level_111, + path='[{"coordinate":[0,2],"connectedNodes":[2]},{"coordinate":[2,2],"connectedNodes":[2,3]},{"coordinate":[1,2],"connectedNodes":[0,1]},{"coordinate":[2,3],"connectedNodes":[4,1]},{"coordinate":[2,4],"connectedNodes":[5,3]},{"coordinate":[3,4],"connectedNodes":[4,6]},{"coordinate":[4,4],"connectedNodes":[5]}]', + origin='{"coordinate":[0,2],"direction":"E"}', + destinations="[[4,4]]", + default=True, + pythonEnabled=False, + pythonViewEnabled=True, + theme_name="farm", + character_name="Van", + ) + + def set_decor(level, decor): + set_decor_inner(level, decor, LevelDecor) + + set_decor( + level_110, + json.loads('[{"x":503,"y":409,"decorName":"tree2"},{"x":384,"y":503,"decorName":"bush"},{"x":355,"y":549,"decorName":"bush"},{"x":320,"y":503,"decorName":"bush"},{"x":399,"y":200,"decorName":"pond"},{"x":400,"y":299,"decorName":"pond"}]') + ) + set_decor( + level_111, + json.loads('[{"x":611,"y":568,"decorName":"tree2"},{"x":595,"y":648,"decorName":"tree1"},{"x":714,"y":454,"decorName":"tree2"},{"x":652,"y":328,"decorName":"tree2"},{"x":600,"y":447,"decorName":"tree2"},{"x":651,"y":498,"decorName":"tree1"},{"x":366,"y":286,"decorName":"tree2"},{"x":285,"y":257,"decorName":"tree2"},{"x":206,"y":283,"decorName":"tree1"},{"x":82,"y":385,"decorName":"tree1"},{"x":46,"y":324,"decorName":"tree1"},{"x":233,"y":355,"decorName":"tree1"},{"x":637,"y":400,"decorName":"tree1"},{"x":87,"y":258,"decorName":"tree2"},{"x":291,"y":321,"decorName":"tree1"},{"x":164,"y":388,"decorName":"tree2"},{"x":129,"y":334,"decorName":"tree1"},{"x":128,"y":593,"decorName":"tree2"},{"x":235,"y":685,"decorName":"tree2"},{"x":103,"y":688,"decorName":"tree2"},{"x":181,"y":635,"decorName":"tree1"},{"x":70,"y":625,"decorName":"tree1"}]') + ) + set_decor( + level_112, + json.loads('[{"x":50,"y":625,"decorName":"tree1"},{"x":50,"y":207,"decorName":"tree1"},{"x":50,"y":321,"decorName":"tree1"},{"x":50,"y":426,"decorName":"tree1"},{"x":50,"y":529,"decorName":"tree1"},{"x":398,"y":485,"decorName":"tree2"},{"x":500,"y":513,"decorName":"tree2"},{"x":500,"y":198,"decorName":"bush"},{"x":500,"y":274,"decorName":"bush"},{"x":500,"y":352,"decorName":"bush"}]') + ) + set_decor( + level_113, + json.loads('[{"x":404,"y":415,"decorName":"tree2"},{"x":251,"y":420,"decorName":"bush"},{"x":187,"y":420,"decorName":"bush"},{"x":128,"y":420,"decorName":"bush"},{"x":221,"y":460,"decorName":"bush"},{"x":153,"y":460,"decorName":"bush"},{"x":183,"y":500,"decorName":"bush"},{"x":203,"y":596,"decorName":"pond"},{"x":203,"y":696,"decorName":"pond"}]') + ) + set_decor( + level_114, + json.loads('[{"x":2,"y":438,"decorName":"tree1"},{"x":2,"y":543,"decorName":"tree1"},{"x":2,"y":329,"decorName":"tree1"},{"x":548,"y":556,"decorName":"tree1"},{"x":563,"y":469,"decorName":"tree1"},{"x":475,"y":549,"decorName":"tree2"},{"x":419,"y":514,"decorName":"tree1"},{"x":488,"y":434,"decorName":"tree2"}]') + ) + set_decor( + level_115, + json.loads('[{"x":885,"y":343,"decorName":"tree1"},{"x":885,"y":440,"decorName":"tree1"},{"x":406,"y":383,"decorName":"tree2"},{"x":498,"y":306,"decorName":"tree2"},{"x":484,"y":190,"decorName":"tree2"}]') + ) + set_decor( + level_116, + json.loads('[{"x":220,"y":305,"decorName":"pond"},{"x":539,"y":569,"decorName":"tree2"},{"x":569,"y":516,"decorName":"tree1"},{"x":498,"y":497,"decorName":"tree2"},{"x":182,"y":165,"decorName":"tree2"},{"x":225,"y":228,"decorName":"tree1"},{"x":159,"y":245,"decorName":"tree1"},{"x":312,"y":254,"decorName":"tree2"}]') + ) + set_decor( + level_117, + json.loads('[{"x":443,"y":578,"decorName":"pond"},{"x":412,"y":648,"decorName":"tree1"},{"x":516,"y":651,"decorName":"tree2"},{"x":694,"y":341,"decorName":"tree1"},{"x":647,"y":292,"decorName":"tree2"},{"x":623,"y":362,"decorName":"tree1"},{"x":640,"y":434,"decorName":"tree2"}]') + ) + set_decor( + level_118, + json.loads('[{"x":711,"y":507,"decorName":"tree2"},{"x":605,"y":508,"decorName":"tree2"},{"x":193,"y":396,"decorName":"bush"},{"x":250,"y":398,"decorName":"bush"}]') + ) + set_decor( + level_119, + json.loads('[{"x":250,"y":391,"decorName":"tree2"},{"x":367,"y":237,"decorName":"tree1"},{"x":463,"y":317,"decorName":"tree2"},{"x":364,"y":395,"decorName":"tree1"}]') + ) + set_decor( + level_120, + json.loads('[{"x":189,"y":337,"decorName":"pond"},{"x":793,"y":368,"decorName":"tree1"},{"x":814,"y":285,"decorName":"tree2"},{"x":869,"y":389,"decorName":"tree2"},{"x":334,"y":413,"decorName":"tree1"},{"x":403,"y":402,"decorName":"tree2"},{"x":192,"y":410,"decorName":"tree1"}]') + ) + set_decor( + level_121, + json.loads('[{"x":383,"y":500,"decorName":"pond"},{"x":700,"y":500,"decorName":"pond"},{"x":700,"y":400,"decorName":"pond"},{"x":700,"y":300,"decorName":"pond"},{"x":550,"y":433,"decorName":"bush"},{"x":549,"y":467,"decorName":"bush"},{"x":550,"y":395,"decorName":"bush"},{"x":186,"y":431,"decorName":"tree1"},{"x":196,"y":387,"decorName":"tree1"},{"x":541,"y":501,"decorName":"tree2"}]') + ) + set_decor( + level_122, + json.loads('[{"x":150,"y":320,"decorName":"bush"},{"x":350,"y":320,"decorName":"bush"},{"x":550,"y":320,"decorName":"bush"}]') + ) + + def set_blocks(level, blocks): + set_blocks_inner(level, blocks, LevelBlock, Block) + + set_blocks( + level_110, + json.loads('[{"type":"move_forwards"},{"type":"turn_left"},{"type":"turn_right"}]'), + ) + set_blocks( + level_111, + json.loads('[{"type":"move_forwards"},{"type":"turn_left"},{"type":"turn_right"}]'), + ) + set_blocks( + level_112, + json.loads('[{"type":"move_forwards"},{"type":"turn_left"},{"type":"turn_right"}]'), + ) + set_blocks( + level_116, + json.loads('[{"type":"move_forwards"},{"type":"controls_repeat_while"},{"type":"variables_numeric_set"},{"type":"variables_increment"},{"type":"variables_get"},{"type":"math_number"},{"type":"logic_compare"}]'), + ) + set_blocks( + level_117, + json.loads('[{"type":"turn_left"},{"type":"turn_right"},{"type":"controls_repeat_while"},{"type":"variables_numeric_set"},{"type":"variables_increment"},{"type":"variables_get"},{"type":"math_number"},{"type":"logic_compare"}]'), + ) + set_blocks( + level_118, + json.loads('[{"type":"move_forwards"},{"type":"turn_left"},{"type":"turn_right"},{"type":"controls_repeat_while"},{"type":"variables_numeric_set"},{"type":"variables_increment"},{"type":"variables_get"},{"type":"math_number"},{"type":"logic_compare"}]'), ) level_109 = Level.objects.get(name="109") @@ -306,11 +453,19 @@ def add_loop_levels(apps: Apps, *args): level_109.save() +def delete_loop_levels(apps: Apps, *args): + Level = apps.get_model("game", "Level") + Episode = apps.get_model("game", "Episode") + + Level.objects.filter(episode__pk__in=range(12, 16)).delete() + Episode.objects.filter(pk__in=range(12, 16)).delete() + + class Migration(migrations.Migration): dependencies = [("game", "0085_add_new_blocks")] operations = [ migrations.RunPython( add_loop_levels, - reverse_code=migrations.RunPython.noop, + reverse_code=delete_loop_levels, ) ] diff --git a/game/static/game/js/blocklyControl.js b/game/static/game/js/blocklyControl.js index 01688593b..4e3cc28a7 100644 --- a/game/static/game/js/blocklyControl.js +++ b/game/static/game/js/blocklyControl.js @@ -314,15 +314,18 @@ ocargo.BlocklyControl.prototype.activeBlocksCount = function () { block.type === "turn_right" || block.type === "turn_around" || block.type === "wait" || - block.type === "deliver" + block.type === "deliver" || + block.type === "variables_numeric_set" || + block.type === "variables_increment" ) { var nextBlock = block.nextConnection.targetBlock(); n += count(nextBlock); - } else if (block.type === "logic_negate") { + } else if (block.type === "logic_negate" || block.type === "logic_compare") { var conditionBlock = block.inputList[0].connection.targetBlock(); n += count(conditionBlock); + } else if (block.type === "variables_get" || block.type === "math_number") { + n++ } - // TODO: prob need to add new blocks here return n; } diff --git a/game/urls.py b/game/urls.py index 68f857e61..82eb5e8b9 100644 --- a/game/urls.py +++ b/game/urls.py @@ -71,7 +71,7 @@ url(r"^save/$", save_workspace, name="save_workspace"), url(r"^save/(?P[0-9]+)/$", save_workspace, name="save_workspace"), url(r"^delete/(?P[0-9]+)/$", delete_workspace, name="delete_workspace"), - url(r"^solution/(?P[0-9]+)/$", load_workspace_solution, name="load_workspace_solution"), + url(r"^solution/(?P[0-9]+)/$", load_workspace_solution, name="load_workspace_solution"), ] ), ), diff --git a/game/views/level.py b/game/views/level.py index 43a47b032..f5bbd9eef 100644 --- a/game/views/level.py +++ b/game/views/level.py @@ -1,9 +1,7 @@ -from __future__ import absolute_import -from __future__ import division +from __future__ import absolute_import, division import json -from builtins import object -from builtins import str +from builtins import object, str from django.http import Http404, HttpResponse from django.shortcuts import render, get_object_or_404 @@ -372,21 +370,22 @@ def save_workspace(request, workspaceID=None): return load_list_of_workspaces(request) -def load_workspace_solution(request, levelName): - - if levelName in solutions: +def load_workspace_solution(request, level_name): + if level_name in solutions: workspace = Workspace(owner=request.user.userprofile) - workspace.id = levelName - workspace.name = levelName + workspace.id = level_name + workspace.name = level_name workspace.contents = solutions["blockly_default"] workspace.python_contents = solutions["python_default"] - if int(levelName) <= 91: - workspace.contents = solutions[levelName] + level = Level.objects.get(name=level_name, default=True) + + if level.blocklyEnabled: + workspace.contents = solutions[level_name] workspace.blockly_enabled = True workspace.python_enabled = False else: - workspace.python_contents = solutions[levelName] + workspace.python_contents = solutions[level_name] workspace.blockly_enabled = False workspace.python_enabled = True diff --git a/game/views/level_solutions.py b/game/views/level_solutions.py index 03ba0356f..3560af7b2 100644 --- a/game/views/level_solutions.py +++ b/game/views/level_solutions.py @@ -291,6 +291,102 @@ def big(): my_van.turn_left() n = n / 2""" +lvl_113 = """from van import Van + +my_van = Van() + +my_van.move_forwards() +my_van.turn_right() +my_van.turn_left() +my_van.move_forwards()""" + +lvl_114 = """from van import Van + +my_van = Van() + +my_van.turn_left() +my_van.move_forwards() +my_van.move_forwards() +my_van.turn_right() +my_van.turn_right() +my_van.turn_left() +my_van.turn_right() +my_van.move_forwards() +my_van.move_forwards() +my_van.turn_left() +my_van.turn_left() +my_van.turn_right()""" + +lvl_115 = """from van import Van + +my_van = Van() + +my_van.turn_right() +my_van.turn_left() +my_van.move_forwards() +my_van.turn_right() +my_van.turn_left() +my_van.turn_right() +my_van.turn_left()""" + +lvl_119 = """from van import Van + +my_van = Van() + +count = 0 +while count < 3: + my_van.turn_left() + my_van.turn_right() + my_van.turn_left() + my_van.move_forwards() + count = count + 1""" + +lvl_120 = """from van import Van + +my_van = Van() + +count = 0 +while count < 4: + my_van.move_forwards() + my_van.turn_left() + my_van.turn_right() + count = count + 1""" + +lvl_121 = """from van import Van + +my_van = Van() + +count = 0 +while count < 6: + my_van.turn_left() + my_van.turn_right() + count = count + 1""" + +lvl_122 = """from van import Van + +my_van = Van() + +count = 0 +while count < 3: + my_van.turn_left() + my_van.turn_left() + my_van.turn_right() + my_van.turn_right() + count = count + 1 + +count = 0 +while count < 3: + my_van.move_forwards() + count = count + 1 + +count = 0 +while count < 3: + my_van.turn_right() + my_van.turn_right() + my_van.turn_left() + my_van.turn_left() + count = count + 1""" + solutions = { "python_default": python_default, "blockly_default": blockly_default, @@ -403,4 +499,17 @@ def big(): "107": lvl_107, "108": lvl_108, "109": lvl_109, + "110": '', + "111": '', + "112": '', + "113": lvl_113, + "114": lvl_114, + "115": lvl_115, + "116": 'count0LTcount4count1', + "117": 'count0LTcount4count1', + "118": 'count0LTcount3count1', + "119": lvl_119, + "120": lvl_120, + "121": lvl_121, + "122": lvl_122, }