rapid-router 5.18.0__py2.py3-none-any.whl → 7.6.8__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- example_project/rapid_router_test_settings.py +19 -7
- example_project/settings.py +21 -8
- example_project/urls.py +5 -6
- game/__init__.py +1 -1
- game/admin.py +7 -2
- game/character.py +8 -0
- game/decor.py +40 -0
- game/end_to_end_tests/base_game_test.py +34 -27
- game/end_to_end_tests/editor_page.py +15 -0
- game/end_to_end_tests/game_page.py +88 -20
- game/end_to_end_tests/selenium_test_case.py +1 -20
- game/end_to_end_tests/test_cow_crashes.py +3 -5
- game/end_to_end_tests/test_level_editor.py +273 -10
- game/end_to_end_tests/test_level_selection.py +25 -3
- game/end_to_end_tests/test_play_through.py +222 -127
- game/end_to_end_tests/test_python_levels.py +41 -7
- game/end_to_end_tests/test_saving_workspace.py +2 -1
- game/forms.py +7 -1
- game/level_management.py +26 -11
- game/messages.py +899 -337
- game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
- game/migrations/0026_levels_pt2.py +13 -2
- game/migrations/0032_cannot_turn_left_level.py +13 -2
- game/migrations/0033_recursion_level.py +13 -2
- game/migrations/0034_joes_level.py +13 -2
- game/migrations/0035_disable_route_score_level_70.py +0 -2
- game/migrations/0036_level_score_73.py +0 -2
- game/migrations/0037_level_score_79.py +0 -2
- game/migrations/0038_level_score_40.py +0 -1
- game/migrations/0042_level_score_73.py +0 -2
- game/migrations/0048_add_cow_field_and_blocks.py +0 -2
- game/migrations/0049_level_score_34.py +0 -2
- game/migrations/0050_level_score_40.py +0 -2
- game/migrations/0051_level_score_49.py +0 -1
- game/migrations/0086_loop_levels.py +13 -2
- game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
- game/migrations/0093_alter_level_character_name.py +18 -0
- game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
- game/migrations/0095_level_commands.py +18 -0
- game/migrations/0096_alter_level_commands.py +18 -0
- game/migrations/0097_add_python_den_levels.py +1515 -0
- game/migrations/0098_add_episode_link_fields.py +44 -0
- game/migrations/0099_python_episodes_links.py +103 -0
- game/migrations/0100_reorder_python_levels.py +179 -0
- game/migrations/0101_rename_episodes.py +45 -0
- game/migrations/0102_reoder_episodes_13_14.py +136 -0
- game/migrations/0103_level_1015_solution.py +26 -0
- game/migrations/0104_remove_level_direct_drive.py +17 -0
- game/migrations/0105_delete_invalid_attempts.py +18 -0
- game/migrations/0106_fields_to_snake_case.py +48 -0
- game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
- game/migrations/0108_episode_indy_worksheet_link.py +18 -0
- game/migrations/0109_create_episodes_23_and_24.py +99 -0
- game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
- game/migrations/0111_create_worksheets.py +149 -0
- game/migrations/0112_worksheet_locked_classes.py +21 -0
- game/migrations/0113_level_needs_approval.py +18 -0
- game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
- game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
- game/migrations/0116_update_worksheet_video_links.py +68 -0
- game/migrations/0117_update_solutions_to_if_else.py +61 -0
- game/models.py +127 -17
- game/permissions.py +51 -19
- game/python_den_urls.py +26 -0
- game/random_road.py +9 -9
- game/serializers.py +12 -17
- game/static/django_reverse_js/js/reverse.js +171 -0
- game/static/game/css/LilitaOne-Regular.ttf +0 -0
- game/static/game/css/backgrounds.css +8 -12
- game/static/game/css/dataTables.custom.css +3 -2
- game/static/game/css/editor.css +47 -0
- game/static/game/css/game.css +37 -43
- game/static/game/css/game_screen.css +16 -0
- game/static/game/css/level_editor.css +5 -0
- game/static/game/css/level_selection.css +17 -2
- game/static/game/image/Python_Den_hero_student.png +0 -0
- game/static/game/image/Python_levels_page.svg +1954 -0
- game/static/game/image/characters/front_view/Electric_van.svg +448 -0
- game/static/game/image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/image/decor/city/solar_panel.svg +1200 -0
- game/static/game/image/decor/farm/solar_panel.svg +86 -0
- game/static/game/image/decor/grass/solar_panel.svg +86 -0
- game/static/game/image/decor/snow/solar_panel.svg +173 -0
- game/static/game/image/electric_van.svg +448 -0
- game/static/game/image/icons/description.svg +1 -0
- game/static/game/image/icons/hint.svg +1 -0
- game/static/game/image/icons/python.svg +1 -1
- game/static/game/image/pigeon.svg +684 -0
- game/static/game/image/python_den_header.svg +19 -0
- game/static/game/js/animation.js +65 -24
- game/static/game/js/blockly/msg/js/bg.js +52 -1
- game/static/game/js/blockly/msg/js/ca.js +52 -1
- game/static/game/js/blockly/msg/js/en-gb.js +2 -0
- game/static/game/js/blockly/msg/js/en.js +2 -0
- game/static/game/js/blockly/msg/js/es.js +52 -1
- game/static/game/js/blockly/msg/js/fr.js +2 -0
- game/static/game/js/blockly/msg/js/hi.js +2 -0
- game/static/game/js/blockly/msg/js/it.js +52 -1
- game/static/game/js/blockly/msg/js/pl.js +52 -1
- game/static/game/js/blockly/msg/js/pt-br.js +52 -1
- game/static/game/js/blockly/msg/js/ru.js +52 -1
- game/static/game/js/blockly/msg/js/ur.js +52 -1
- game/static/game/js/blocklyCustomBlocks.js +93 -52
- game/static/game/js/button.js +12 -0
- game/static/game/js/cow.js +11 -7
- game/static/game/js/drawing.js +68 -29
- game/static/game/js/editor.js +23 -0
- game/static/game/js/game.js +74 -110
- game/static/game/js/level_editor.js +646 -274
- game/static/game/js/level_moderation.js +33 -2
- game/static/game/js/level_selection.js +1 -1
- game/static/game/js/loadLanguages.js +2 -2
- game/static/game/js/model.js +32 -2
- game/static/game/js/pythonControl.js +14 -1
- game/static/game/js/scoreboard.js +0 -37
- game/static/game/js/scoreboardSharedLevels.js +48 -0
- game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
- game/static/game/js/sound.js +52 -5
- game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
- game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
- game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
- game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
- game/static/game/raphael_image/pigeon.svg +685 -0
- game/static/game/sass/game.scss +2 -2
- game/static/game/sound/clown_horn.mp3 +0 -0
- game/static/game/sound/clown_horn.ogg +0 -0
- game/static/game/sound/electric_van_starting.mp3 +0 -0
- game/static/game/sound/electric_van_starting.ogg +0 -0
- game/static/game/sound/pigeon.mp3 +0 -0
- game/static/game/sound/pigeon.ogg +0 -0
- game/static/game/sound/sleigh_bells.mp3 +0 -0
- game/static/game/sound/sleigh_bells.ogg +0 -0
- game/static/game/sound/sleigh_crash.mp3 +0 -0
- game/static/game/sound/sleigh_crash.ogg +0 -0
- game/templates/game/base.html +34 -14
- game/templates/game/basenonav.html +11 -5
- game/templates/game/game.html +142 -38
- game/templates/game/level_editor.html +340 -236
- game/templates/game/level_moderation.html +19 -6
- game/templates/game/level_selection.html +18 -110
- game/templates/game/python_den_level_selection.html +291 -0
- game/templates/game/python_den_worksheet.html +101 -0
- game/templates/game/scoreboard.html +83 -64
- game/tests/test_level_editor.py +94 -26
- game/tests/test_level_selection.py +149 -46
- game/tests/test_python_den_worksheet.py +85 -0
- game/tests/test_scoreboard.py +34 -7
- game/tests/utils/level.py +32 -26
- game/theme.py +5 -5
- game/urls.py +199 -61
- game/views/language_code_conversions.py +86 -86
- game/views/level.py +155 -63
- game/views/level_editor.py +88 -55
- game/views/level_moderation.py +23 -0
- game/views/level_selection.py +116 -47
- game/views/level_solutions.py +491 -106
- game/views/scoreboard.py +76 -51
- game/views/worksheet.py +25 -0
- rapid_router-7.6.8.dist-info/METADATA +174 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
- example_project/manage.py +0 -10
- game/static/game/image/actions/go.svg +0 -18
- game/static/game/js/js-reverse.js +0 -14
- game/static/game/js/pqselect.min.js +0 -9
- game/static/game/js/widget-scroller.js +0 -906
- rapid_router-5.18.0.dist-info/METADATA +0 -17
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
- {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
1
3
|
from .base_game_test import BaseGameTest
|
|
2
4
|
|
|
3
5
|
|
|
@@ -5,13 +7,19 @@ class TestPlayThrough(BaseGameTest):
|
|
|
5
7
|
def setUp(self):
|
|
6
8
|
self.login_once()
|
|
7
9
|
|
|
8
|
-
def _complete_episode(
|
|
10
|
+
def _complete_episode(
|
|
11
|
+
self, episode_number, level_number, from_python_den=False, **kwargs
|
|
12
|
+
):
|
|
9
13
|
page = self.go_to_episode(episode_number)
|
|
10
|
-
self.complete_and_check_level(
|
|
14
|
+
self.complete_and_check_level(
|
|
15
|
+
level_number, page, from_python_den, **kwargs
|
|
16
|
+
)
|
|
11
17
|
|
|
12
|
-
def _complete_level(self, level_number, **kwargs):
|
|
13
|
-
page = self.go_to_level(level_number)
|
|
14
|
-
self.complete_and_check_level(
|
|
18
|
+
def _complete_level(self, level_number, from_python_den=False, **kwargs):
|
|
19
|
+
page = self.go_to_level(level_number, from_python_den)
|
|
20
|
+
self.complete_and_check_level(
|
|
21
|
+
level_number, page, from_python_den, **kwargs
|
|
22
|
+
)
|
|
15
23
|
|
|
16
24
|
def test_episode_01(self):
|
|
17
25
|
self._complete_episode(1, 1, check_algorithm_score=False)
|
|
@@ -275,143 +283,230 @@ class TestPlayThrough(BaseGameTest):
|
|
|
275
283
|
self._complete_level(78, check_route_score=False)
|
|
276
284
|
|
|
277
285
|
def test_level_079(self):
|
|
278
|
-
self._complete_level(79)
|
|
279
|
-
|
|
280
|
-
def test_episode_10(self):
|
|
281
|
-
self._complete_episode(10, 80)
|
|
282
|
-
|
|
283
|
-
def test_level_080(self):
|
|
284
|
-
self._complete_level(80)
|
|
285
|
-
|
|
286
|
-
def test_level_081(self):
|
|
287
|
-
self._complete_level(81)
|
|
288
|
-
|
|
289
|
-
def test_level_082(self):
|
|
290
|
-
self._complete_level(82)
|
|
291
|
-
|
|
292
|
-
def test_level_083(self):
|
|
293
|
-
self._complete_level(83)
|
|
294
|
-
|
|
295
|
-
def test_level_084(self):
|
|
296
|
-
self._complete_level(84)
|
|
297
|
-
|
|
298
|
-
def test_level_085(self):
|
|
299
|
-
self._complete_level(85)
|
|
300
|
-
|
|
301
|
-
def test_level_086(self):
|
|
302
|
-
self._complete_level(86)
|
|
303
|
-
|
|
304
|
-
def test_level_087(self):
|
|
305
|
-
self._complete_level(87)
|
|
306
|
-
|
|
307
|
-
def test_level_088(self):
|
|
308
|
-
self._complete_level(88)
|
|
309
|
-
|
|
310
|
-
def test_level_089(self):
|
|
311
|
-
self._complete_level(89)
|
|
312
|
-
|
|
313
|
-
def test_level_090(self):
|
|
314
|
-
self._complete_level(90)
|
|
315
|
-
|
|
316
|
-
def test_level_091(self):
|
|
317
|
-
self._complete_level(91)
|
|
318
|
-
|
|
319
|
-
def test_episode_11(self):
|
|
320
|
-
self._complete_episode(11, 92, check_algorithm_score=False)
|
|
321
|
-
|
|
322
|
-
def test_level_092(self):
|
|
323
|
-
self._complete_level(92, check_algorithm_score=False)
|
|
286
|
+
self._complete_level(79, final_level=True)
|
|
324
287
|
|
|
325
|
-
def
|
|
326
|
-
self.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
self._complete_level(95, check_algorithm_score=False)
|
|
333
|
-
|
|
334
|
-
def test_level_096(self):
|
|
335
|
-
self._complete_level(96, check_algorithm_score=False)
|
|
336
|
-
|
|
337
|
-
def test_level_097(self):
|
|
338
|
-
self._complete_level(97, check_algorithm_score=False)
|
|
339
|
-
|
|
340
|
-
def test_level_098(self):
|
|
341
|
-
self._complete_level(98, check_algorithm_score=False)
|
|
342
|
-
|
|
343
|
-
def test_level_099(self):
|
|
344
|
-
self._complete_level(99, check_algorithm_score=False)
|
|
345
|
-
|
|
346
|
-
def test_level_100(self):
|
|
347
|
-
self._complete_level(100, check_algorithm_score=False)
|
|
348
|
-
|
|
349
|
-
def test_level_101(self):
|
|
350
|
-
self._complete_level(101, check_algorithm_score=False)
|
|
351
|
-
|
|
352
|
-
def test_level_102(self):
|
|
353
|
-
self._complete_level(102, check_algorithm_score=False)
|
|
354
|
-
|
|
355
|
-
def test_level_103(self):
|
|
356
|
-
self._complete_level(103, check_algorithm_score=False)
|
|
357
|
-
|
|
358
|
-
def test_level_104(self):
|
|
359
|
-
self._complete_level(104, check_algorithm_score=False)
|
|
360
|
-
|
|
361
|
-
def test_level_105(self):
|
|
362
|
-
self._complete_level(105, check_algorithm_score=False)
|
|
363
|
-
|
|
364
|
-
def test_level_106(self):
|
|
365
|
-
self._complete_level(106, check_algorithm_score=False)
|
|
366
|
-
|
|
367
|
-
def test_level_107(self):
|
|
368
|
-
self._complete_level(107, check_algorithm_score=False)
|
|
288
|
+
def test_episode_12(self):
|
|
289
|
+
self._complete_episode(
|
|
290
|
+
12, 1, check_algorithm_score=False, from_python_den=True
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def test_python_level_001(self):
|
|
294
|
+
self._complete_level(1, from_python_den=True)
|
|
369
295
|
|
|
370
|
-
def
|
|
371
|
-
self._complete_level(
|
|
296
|
+
def test_python_level_002(self):
|
|
297
|
+
self._complete_level(2, from_python_den=True)
|
|
372
298
|
|
|
373
|
-
def
|
|
374
|
-
self._complete_level(
|
|
299
|
+
def test_python_level_003(self):
|
|
300
|
+
self._complete_level(3, from_python_den=True)
|
|
375
301
|
|
|
376
|
-
def
|
|
377
|
-
self.
|
|
302
|
+
def test_python_level_004(self):
|
|
303
|
+
self._complete_level(
|
|
304
|
+
4, check_algorithm_score=False, from_python_den=True
|
|
305
|
+
)
|
|
378
306
|
|
|
379
|
-
def
|
|
380
|
-
self._complete_level(
|
|
307
|
+
def test_python_level_005(self):
|
|
308
|
+
self._complete_level(
|
|
309
|
+
5, check_algorithm_score=False, from_python_den=True
|
|
310
|
+
)
|
|
381
311
|
|
|
382
|
-
def
|
|
383
|
-
self._complete_level(
|
|
312
|
+
def test_python_level_006(self):
|
|
313
|
+
self._complete_level(
|
|
314
|
+
6, check_algorithm_score=False, from_python_den=True
|
|
315
|
+
)
|
|
384
316
|
|
|
385
|
-
def
|
|
386
|
-
self._complete_level(
|
|
317
|
+
def test_python_level_007(self):
|
|
318
|
+
self._complete_level(7, from_python_den=True)
|
|
387
319
|
|
|
388
|
-
def
|
|
389
|
-
self._complete_level(
|
|
320
|
+
def test_python_level_008(self):
|
|
321
|
+
self._complete_level(8, from_python_den=True)
|
|
390
322
|
|
|
391
|
-
def
|
|
392
|
-
self._complete_level(
|
|
323
|
+
def test_python_level_009(self):
|
|
324
|
+
self._complete_level(9, from_python_den=True)
|
|
393
325
|
|
|
394
|
-
def
|
|
395
|
-
self._complete_level(
|
|
326
|
+
def test_python_level_010(self):
|
|
327
|
+
self._complete_level(
|
|
328
|
+
10, check_algorithm_score=False, from_python_den=True
|
|
329
|
+
)
|
|
396
330
|
|
|
397
|
-
def
|
|
398
|
-
self._complete_level(
|
|
331
|
+
def test_python_level_011(self):
|
|
332
|
+
self._complete_level(
|
|
333
|
+
11, check_algorithm_score=False, from_python_den=True
|
|
334
|
+
)
|
|
399
335
|
|
|
400
|
-
def
|
|
401
|
-
self._complete_level(
|
|
336
|
+
def test_python_level_012(self):
|
|
337
|
+
self._complete_level(
|
|
338
|
+
12, check_algorithm_score=False, from_python_den=True
|
|
339
|
+
)
|
|
402
340
|
|
|
403
|
-
def
|
|
404
|
-
self._complete_level(
|
|
341
|
+
def test_python_level_013(self):
|
|
342
|
+
self._complete_level(
|
|
343
|
+
13, check_algorithm_score=False, from_python_den=True
|
|
344
|
+
)
|
|
405
345
|
|
|
406
|
-
def
|
|
407
|
-
self.
|
|
346
|
+
def test_episode_13(self):
|
|
347
|
+
self._complete_episode(13, 14, from_python_den=True)
|
|
408
348
|
|
|
409
|
-
def
|
|
410
|
-
self._complete_level(
|
|
349
|
+
def test_python_level_014(self):
|
|
350
|
+
self._complete_level(14, from_python_den=True)
|
|
411
351
|
|
|
412
|
-
def
|
|
413
|
-
self._complete_level(
|
|
352
|
+
def test_python_level_015(self):
|
|
353
|
+
self._complete_level(15, from_python_den=True)
|
|
414
354
|
|
|
415
|
-
def
|
|
416
|
-
self._complete_level(
|
|
355
|
+
def test_python_level_016(self):
|
|
356
|
+
self._complete_level(
|
|
357
|
+
16, check_algorithm_score=False, from_python_den=True
|
|
358
|
+
)
|
|
417
359
|
|
|
360
|
+
def test_python_level_017(self):
|
|
361
|
+
self._complete_level(
|
|
362
|
+
17, check_algorithm_score=False, from_python_den=True
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def test_python_level_018(self):
|
|
366
|
+
self._complete_level(
|
|
367
|
+
18, check_algorithm_score=False, from_python_den=True
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
def test_python_level_019(self):
|
|
371
|
+
self._complete_level(19, from_python_den=True)
|
|
372
|
+
|
|
373
|
+
def test_python_level_020(self):
|
|
374
|
+
self._complete_level(
|
|
375
|
+
20, check_algorithm_score=False, from_python_den=True
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
def test_python_level_021(self):
|
|
379
|
+
self._complete_level(
|
|
380
|
+
21, check_algorithm_score=False, from_python_den=True
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def test_python_level_022(self):
|
|
384
|
+
self._complete_level(22, from_python_den=True)
|
|
385
|
+
|
|
386
|
+
def test_python_level_023(self):
|
|
387
|
+
self._complete_level(23, from_python_den=True)
|
|
388
|
+
|
|
389
|
+
def test_python_level_024(self):
|
|
390
|
+
self._complete_level(
|
|
391
|
+
24, check_algorithm_score=False, from_python_den=True
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
def test_python_level_025(self):
|
|
395
|
+
self._complete_level(
|
|
396
|
+
25, check_algorithm_score=False, from_python_den=True
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
def test_episode_14(self):
|
|
400
|
+
self._complete_episode(14, 26, from_python_den=True)
|
|
401
|
+
|
|
402
|
+
def test_python_level_026(self):
|
|
403
|
+
self._complete_level(26, from_python_den=True)
|
|
404
|
+
|
|
405
|
+
def test_python_level_027(self):
|
|
406
|
+
self._complete_level(27, from_python_den=True)
|
|
407
|
+
|
|
408
|
+
def test_python_level_028(self):
|
|
409
|
+
self._complete_level(28, from_python_den=True)
|
|
410
|
+
|
|
411
|
+
def test_python_level_029(self):
|
|
412
|
+
self._complete_level(29, from_python_den=True)
|
|
413
|
+
|
|
414
|
+
def test_python_level_030(self):
|
|
415
|
+
self._complete_level(
|
|
416
|
+
30, check_algorithm_score=False, from_python_den=True
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
def test_python_level_031(self):
|
|
420
|
+
self._complete_level(31, from_python_den=True)
|
|
421
|
+
|
|
422
|
+
def test_python_level_032(self):
|
|
423
|
+
self._complete_level(32, from_python_den=True)
|
|
424
|
+
|
|
425
|
+
def test_python_level_033(self):
|
|
426
|
+
self._complete_level(
|
|
427
|
+
33, check_algorithm_score=False, from_python_den=True
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
def test_python_level_034(self):
|
|
431
|
+
self._complete_level(
|
|
432
|
+
34, check_algorithm_score=False, from_python_den=True
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
def test_python_level_035(self):
|
|
436
|
+
self._complete_level(35, from_python_den=True)
|
|
437
|
+
|
|
438
|
+
def test_python_level_036(self):
|
|
439
|
+
self._complete_level(36, from_python_den=True)
|
|
440
|
+
|
|
441
|
+
def test_python_level_037(self):
|
|
442
|
+
self._complete_level(
|
|
443
|
+
37, check_algorithm_score=False, from_python_den=True
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
@pytest.mark.skip(reason="this level's solution is currently flawed")
|
|
447
|
+
def test_python_level_038(self):
|
|
448
|
+
self._complete_level(
|
|
449
|
+
38, check_algorithm_score=False, from_python_den=True
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
def test_python_level_039(self):
|
|
453
|
+
self._complete_level(
|
|
454
|
+
39, check_algorithm_score=False, from_python_den=True
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
def test_python_level_040(self):
|
|
458
|
+
self._complete_level(
|
|
459
|
+
40,
|
|
460
|
+
check_algorithm_score=False,
|
|
461
|
+
from_python_den=True,
|
|
462
|
+
redirects=True,
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def test_episode_15(self):
|
|
466
|
+
self._complete_episode(
|
|
467
|
+
15, 41, check_algorithm_score=False, from_python_den=True
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
def test_python_level_041(self):
|
|
471
|
+
self._complete_level(41, from_python_den=True)
|
|
472
|
+
|
|
473
|
+
def test_python_level_042(self):
|
|
474
|
+
self._complete_level(
|
|
475
|
+
42, check_algorithm_score=False, from_python_den=True
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
def test_python_level_043(self):
|
|
479
|
+
self._complete_level(
|
|
480
|
+
43, check_algorithm_score=False, from_python_den=True
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
def test_python_level_044(self):
|
|
484
|
+
self._complete_level(44, from_python_den=True)
|
|
485
|
+
|
|
486
|
+
def test_python_level_045(self):
|
|
487
|
+
self._complete_level(
|
|
488
|
+
45, check_algorithm_score=False, from_python_den=True
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
def test_python_level_046(self):
|
|
492
|
+
self._complete_level(
|
|
493
|
+
46, check_algorithm_score=False, from_python_den=True
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
def test_python_level_047(self):
|
|
497
|
+
self._complete_level(
|
|
498
|
+
47, check_algorithm_score=False, from_python_den=True
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
def test_python_level_048(self):
|
|
502
|
+
self._complete_level(
|
|
503
|
+
48, check_algorithm_score=False, from_python_den=True
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
def test_python_level_049(self):
|
|
507
|
+
self._complete_level(
|
|
508
|
+
49,
|
|
509
|
+
check_algorithm_score=False,
|
|
510
|
+
from_python_den=True,
|
|
511
|
+
final_level=True,
|
|
512
|
+
)
|
|
@@ -2,34 +2,68 @@ from selenium.webdriver.common.by import By
|
|
|
2
2
|
from selenium.webdriver.support import expected_conditions as EC
|
|
3
3
|
from selenium.webdriver.support.ui import WebDriverWait
|
|
4
4
|
|
|
5
|
+
from game.character import get_character
|
|
5
6
|
from game.end_to_end_tests.base_game_test import BaseGameTest
|
|
7
|
+
from game.models import Level
|
|
8
|
+
from game.theme import get_theme
|
|
6
9
|
|
|
7
10
|
DELAY_TIME = 10
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class TestPythonLevels(BaseGameTest):
|
|
11
14
|
def test_can_see_python_commands(self):
|
|
12
|
-
self.
|
|
15
|
+
self.go_to_level(4, from_python_den=True).check_python_commands()
|
|
13
16
|
|
|
14
17
|
def test_clear_console(self):
|
|
15
|
-
self.
|
|
18
|
+
self.go_to_level(4, from_python_den=True).write_to_then_clear_console()
|
|
16
19
|
|
|
17
20
|
def test_console_parse_error(self):
|
|
18
|
-
self.
|
|
21
|
+
self.go_to_level(4, from_python_den=True).run_parse_error_program()
|
|
19
22
|
|
|
20
23
|
def test_console_attribute_error(self):
|
|
21
|
-
self.
|
|
24
|
+
self.go_to_level(4, from_python_den=True).run_attribute_error_program()
|
|
22
25
|
|
|
23
26
|
def test_console_print(self):
|
|
24
|
-
self.
|
|
27
|
+
self.go_to_level(4, from_python_den=True).run_print_program()
|
|
25
28
|
|
|
26
29
|
def test_invalid_import(self):
|
|
27
|
-
self.
|
|
30
|
+
self.go_to_level(5, from_python_den=True).run_invalid_import_program()
|
|
28
31
|
|
|
29
32
|
def test_run_code(self):
|
|
30
|
-
self.go_to_level(
|
|
33
|
+
self.go_to_level(4, from_python_den=True)
|
|
31
34
|
run_code = self.selenium.find_element(By.ID, "run-code-button")
|
|
32
35
|
run_code.click()
|
|
33
36
|
assert WebDriverWait(self.selenium, DELAY_TIME).until(
|
|
34
37
|
EC.presence_of_all_elements_located((By.ID, "myModal-lead"))
|
|
35
38
|
)
|
|
39
|
+
|
|
40
|
+
def test_animal_sound_horn(self):
|
|
41
|
+
grass = get_theme(name="grass")
|
|
42
|
+
|
|
43
|
+
van = get_character("Van")
|
|
44
|
+
|
|
45
|
+
animal_level = Level(
|
|
46
|
+
name="Animal commands",
|
|
47
|
+
anonymous=False,
|
|
48
|
+
blockly_enabled=False,
|
|
49
|
+
character=van,
|
|
50
|
+
cows='[{"minCows":1,"maxCows":1,"potentialCoordinates":[{"x":3,"y":4}],"type":"WHITE"}]',
|
|
51
|
+
default=False,
|
|
52
|
+
destinations="[[4,4]]",
|
|
53
|
+
fuel_gauge=False,
|
|
54
|
+
max_fuel=50,
|
|
55
|
+
model_solution="",
|
|
56
|
+
origin='{"coordinate":[2,4],"direction":"E"}',
|
|
57
|
+
path='[{"coordinate":[2,4],"connectedNodes":[1]},{"coordinate":[3,4],"connectedNodes":[0,2]},{"coordinate":[4,4],"connectedNodes":[1]}]',
|
|
58
|
+
python_enabled=True,
|
|
59
|
+
theme=grass,
|
|
60
|
+
threads=1,
|
|
61
|
+
traffic_lights="[]",
|
|
62
|
+
disable_algorithm_score=True,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
user_profile = self.login_once()
|
|
66
|
+
animal_level.owner = user_profile
|
|
67
|
+
animal_level.save()
|
|
68
|
+
|
|
69
|
+
self.run_animal_sound_horn_test(animal_level).assert_success()
|
|
@@ -12,7 +12,8 @@ class TestSavingWorkspace(BaseGameTest):
|
|
|
12
12
|
self.login_once()
|
|
13
13
|
level = 10
|
|
14
14
|
random_save_entry_name = "".join(
|
|
15
|
-
random.choice(string.ascii_uppercase + string.digits)
|
|
15
|
+
random.choice(string.ascii_uppercase + string.digits)
|
|
16
|
+
for _ in range(10)
|
|
16
17
|
)
|
|
17
18
|
return (
|
|
18
19
|
self.go_to_level(level)
|
game/forms.py
CHANGED
|
@@ -9,18 +9,24 @@ from .models import Episode
|
|
|
9
9
|
class ScoreboardForm(forms.Form):
|
|
10
10
|
def __init__(self, *args, **kwargs):
|
|
11
11
|
classes = kwargs.pop("classes")
|
|
12
|
+
language = kwargs.pop("language")
|
|
12
13
|
super(ScoreboardForm, self).__init__(*args, **kwargs)
|
|
13
14
|
classes_choices = [(c.id, c.name) for c in classes]
|
|
14
15
|
|
|
15
16
|
self.fields["classes"] = forms.MultipleChoiceField(
|
|
16
17
|
choices=classes_choices, widget=forms.CheckboxSelectMultiple()
|
|
17
18
|
)
|
|
19
|
+
|
|
20
|
+
episodes_range = (
|
|
21
|
+
range(1, 10) if language == "blockly" else range(12, 16)
|
|
22
|
+
)
|
|
23
|
+
|
|
18
24
|
# Each tuple in choices has two elements, id and name of each level
|
|
19
25
|
# First element is the actual value set on the model
|
|
20
26
|
# Second element is the string displayed on the dropdown menu
|
|
21
27
|
episodes_choices = (
|
|
22
28
|
(episode.id, episode.name)
|
|
23
|
-
for episode in Episode.objects.filter(
|
|
29
|
+
for episode in Episode.objects.filter(pk__in=episodes_range)
|
|
24
30
|
)
|
|
25
31
|
self.fields["episodes"] = forms.MultipleChoiceField(
|
|
26
32
|
choices=itertools.chain(episodes_choices),
|
game/level_management.py
CHANGED
|
@@ -35,8 +35,12 @@ def levels_shared_with(user):
|
|
|
35
35
|
return []
|
|
36
36
|
|
|
37
37
|
shared_levels = user.shared
|
|
38
|
+
shared_levels = add_related_fields(shared_levels)
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
if hasattr(user.userprofile, "student"):
|
|
41
|
+
shared_levels = shared_levels.filter(needs_approval=False)
|
|
42
|
+
|
|
43
|
+
return shared_levels
|
|
40
44
|
|
|
41
45
|
|
|
42
46
|
def levels_owned_by(user):
|
|
@@ -52,13 +56,13 @@ def get_decor(level):
|
|
|
52
56
|
"""Helper method parsing decor into a dictionary format 'sendable' to javascript."""
|
|
53
57
|
decorData = []
|
|
54
58
|
for ld in LevelDecor.objects.filter(level=level):
|
|
55
|
-
decor = get_decor_element(name=ld.
|
|
59
|
+
decor = get_decor_element(name=ld.decor_name, theme=level.theme)
|
|
56
60
|
decorData.append(
|
|
57
61
|
{
|
|
58
62
|
"x": int(ld.x),
|
|
59
63
|
"y": int(ld.y),
|
|
60
64
|
"z": int(decor.z_index),
|
|
61
|
-
"decorName": str(ld.
|
|
65
|
+
"decorName": str(ld.decor_name),
|
|
62
66
|
"width": int(decor.width),
|
|
63
67
|
"height": int(decor.height),
|
|
64
68
|
"url": str(decor.url),
|
|
@@ -81,7 +85,10 @@ def set_decor_inner(level, decor, LevelDecor):
|
|
|
81
85
|
for data in decor:
|
|
82
86
|
level_decors.append(
|
|
83
87
|
LevelDecor(
|
|
84
|
-
level_id=level.id,
|
|
88
|
+
level_id=level.id,
|
|
89
|
+
x=data["x"],
|
|
90
|
+
y=data["y"],
|
|
91
|
+
decor_name=data["decorName"],
|
|
85
92
|
)
|
|
86
93
|
)
|
|
87
94
|
LevelDecor.objects.bulk_create(level_decors)
|
|
@@ -160,11 +167,19 @@ def save_level(level, data):
|
|
|
160
167
|
level.max_fuel = data["max_fuel"]
|
|
161
168
|
level.traffic_lights = data["traffic_lights"]
|
|
162
169
|
level.cows = data["cows"]
|
|
163
|
-
level.
|
|
164
|
-
level.
|
|
165
|
-
level.
|
|
170
|
+
level.blockly_enabled = data.get("blockly_enabled", True)
|
|
171
|
+
level.python_enabled = data.get("python_enabled", False)
|
|
172
|
+
level.python_view_enabled = data.get("python_view_enabled", False)
|
|
166
173
|
level.theme = get_theme_by_pk(pk=data["theme"])
|
|
167
174
|
level.character = get_character_by_pk(pk=data["character"])
|
|
175
|
+
level.disable_algorithm_score = data.get("disable_algorithm_score", False)
|
|
176
|
+
if data.get("subtitle") != None:
|
|
177
|
+
level.subtitle = data.get("subtitle")
|
|
178
|
+
if data.get("lesson") != None:
|
|
179
|
+
level.lesson = data.get("lesson")
|
|
180
|
+
if data.get("hint") != None:
|
|
181
|
+
level.hint = data.get("hint")
|
|
182
|
+
|
|
168
183
|
level.save()
|
|
169
184
|
|
|
170
185
|
set_decor(level, data["decor"])
|
|
@@ -184,9 +199,9 @@ def unshare_level(level, *users):
|
|
|
184
199
|
|
|
185
200
|
|
|
186
201
|
def email_new_custom_level(
|
|
187
|
-
teacher_email, moderate_url, level_url,
|
|
202
|
+
teacher_email, moderate_url, level_url, student_name, class_name
|
|
188
203
|
):
|
|
189
|
-
# email teacher when a new custom level is created by a pupil, so it can be moderated
|
|
204
|
+
# email teacher when a new custom level is created by a pupil, so it can be moderated
|
|
190
205
|
|
|
191
206
|
send_dotdigital_email(
|
|
192
207
|
campaign_ids["level_creation"],
|
|
@@ -195,6 +210,6 @@ def email_new_custom_level(
|
|
|
195
210
|
"STUDENT_NAME": student_name,
|
|
196
211
|
"CLASS_NAME": class_name,
|
|
197
212
|
"LEVEL_URL": level_url,
|
|
198
|
-
"MODERATE_URL": moderate_url
|
|
199
|
-
}
|
|
213
|
+
"MODERATE_URL": moderate_url,
|
|
214
|
+
},
|
|
200
215
|
)
|