pio-robo 0.1.0__tar.gz
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.
- pio_robo-0.1.0/LICENSE +21 -0
- pio_robo-0.1.0/PKG-INFO +84 -0
- pio_robo-0.1.0/README.md +63 -0
- pio_robo-0.1.0/pyproject.toml +41 -0
- pio_robo-0.1.0/setup.cfg +4 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/PKG-INFO +84 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/SOURCES.txt +71 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/dependency_links.txt +1 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/entry_points.txt +2 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/requires.txt +8 -0
- pio_robo-0.1.0/src/pio_robo.egg-info/top_level.txt +1 -0
- pio_robo-0.1.0/src/robo/__init__.py +1 -0
- pio_robo-0.1.0/src/robo/__main__.py +4 -0
- pio_robo-0.1.0/src/robo/cli.py +115 -0
- pio_robo-0.1.0/src/robo/commands.py +178 -0
- pio_robo-0.1.0/src/robo/project.py +48 -0
- pio_robo-0.1.0/src/robo/run.py +407 -0
- pio_robo-0.1.0/src/robo/solutions/__init__.py +1 -0
- pio_robo-0.1.0/src/robo/solutions/world1_0.py +13 -0
- pio_robo-0.1.0/src/robo/solutions/world1_1.py +13 -0
- pio_robo-0.1.0/src/robo/solutions/world1_2.py +14 -0
- pio_robo-0.1.0/src/robo/solutions/world1_3.py +14 -0
- pio_robo-0.1.0/src/robo/solutions/world1_4.py +14 -0
- pio_robo-0.1.0/src/robo/solutions/world1_5.py +14 -0
- pio_robo-0.1.0/src/robo/solutions/world1_6.py +13 -0
- pio_robo-0.1.0/src/robo/solutions/world1_7.py +7 -0
- pio_robo-0.1.0/src/robo/solutions/world1_8.py +7 -0
- pio_robo-0.1.0/src/robo/solutions/world1_9.py +7 -0
- pio_robo-0.1.0/src/robo/solutions/world2_0.py +7 -0
- pio_robo-0.1.0/src/robo/solutions/world2_1.py +7 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/__init__.py +1 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_0.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_1.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_2.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_3.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_4.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_5.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_6.py +0 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_7.py +27 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_8.py +21 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world1_9.py +70 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world2_0.py +26 -0
- pio_robo-0.1.0/src/robo/teacher_solutions/world2_1.py +93 -0
- pio_robo-0.1.0/src/robo/templates/__init__.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_0.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_1.py +0 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_2.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_3.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_4.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_5.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_6.py +1 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_7.py +6 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_8.py +4 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world1_9.py +14 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world2_0.py +3 -0
- pio_robo-0.1.0/src/robo/templates/exercises/world2_1.py +12 -0
- pio_robo-0.1.0/src/robo/world_tools.py +666 -0
- pio_robo-0.1.0/src/robo/worlds/__init__.py +1 -0
- pio_robo-0.1.0/src/robo/worlds/world1_0.py +13 -0
- pio_robo-0.1.0/src/robo/worlds/world1_1.py +13 -0
- pio_robo-0.1.0/src/robo/worlds/world1_2.py +14 -0
- pio_robo-0.1.0/src/robo/worlds/world1_3.py +14 -0
- pio_robo-0.1.0/src/robo/worlds/world1_4.py +14 -0
- pio_robo-0.1.0/src/robo/worlds/world1_5.py +0 -0
- pio_robo-0.1.0/src/robo/worlds/world1_6.py +13 -0
- pio_robo-0.1.0/src/robo/worlds/world1_7.py +7 -0
- pio_robo-0.1.0/src/robo/worlds/world1_8.py +7 -0
- pio_robo-0.1.0/src/robo/worlds/world1_9.py +7 -0
- pio_robo-0.1.0/src/robo/worlds/world2_0.py +7 -0
- pio_robo-0.1.0/src/robo/worlds/world2_1.py +7 -0
- pio_robo-0.1.0/tests/test_commands.py +427 -0
- pio_robo-0.1.0/tests/test_display.py +200 -0
- pio_robo-0.1.0/tests/test_runner.py +75 -0
pio_robo-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) [2026] [Edward Withers]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pio_robo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pio-robo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A simple grid-based robot programming environment for teaching Python functions-first.
|
|
5
|
+
Author: Edward Withers
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Intended Audience :: Education
|
|
9
|
+
Classifier: Topic :: Education
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Provides-Extra: student
|
|
15
|
+
Requires-Dist: pytest<10,>=8; extra == "student"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
18
|
+
Requires-Dist: build; extra == "dev"
|
|
19
|
+
Requires-Dist: twine; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# š¤ Robo ā Classroom Programming Environment
|
|
23
|
+
|
|
24
|
+
A simple Python-based learning environment for teaching programming functions-first through grid-based robot challenges.
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
### Install from PyPI
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install robo
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Development install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone <repo>
|
|
38
|
+
cd robo
|
|
39
|
+
pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Run a world
|
|
43
|
+
|
|
44
|
+
From a student project folder:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m robo world1.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Student solution files live in:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
exercises/
|
|
54
|
+
world1_0.py
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Check progress
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m robo summary
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Run tests
|
|
64
|
+
|
|
65
|
+
From the project root:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python -m pytest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Run tests when you:
|
|
72
|
+
|
|
73
|
+
- add new worlds
|
|
74
|
+
- change commands
|
|
75
|
+
- change runner/display behaviour
|
|
76
|
+
|
|
77
|
+
## Contribute
|
|
78
|
+
|
|
79
|
+
1. Create or edit code.
|
|
80
|
+
2. Run the test suite.
|
|
81
|
+
3. Check that student worlds still run.
|
|
82
|
+
4. Open a pull request.
|
|
83
|
+
|
|
84
|
+
See the `docs/` folder for pupil-facing command guides and teacher/developer notes.
|
pio_robo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# š¤ Robo ā Classroom Programming Environment
|
|
2
|
+
|
|
3
|
+
A simple Python-based learning environment for teaching programming functions-first through grid-based robot challenges.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### Install from PyPI
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install robo
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Development install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone <repo>
|
|
17
|
+
cd robo
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Run a world
|
|
22
|
+
|
|
23
|
+
From a student project folder:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
python -m robo world1.0
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Student solution files live in:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
exercises/
|
|
33
|
+
world1_0.py
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Check progress
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python -m robo summary
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Run tests
|
|
43
|
+
|
|
44
|
+
From the project root:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pytest
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Run tests when you:
|
|
51
|
+
|
|
52
|
+
- add new worlds
|
|
53
|
+
- change commands
|
|
54
|
+
- change runner/display behaviour
|
|
55
|
+
|
|
56
|
+
## Contribute
|
|
57
|
+
|
|
58
|
+
1. Create or edit code.
|
|
59
|
+
2. Run the test suite.
|
|
60
|
+
3. Check that student worlds still run.
|
|
61
|
+
4. Open a pull request.
|
|
62
|
+
|
|
63
|
+
See the `docs/` folder for pupil-facing command guides and teacher/developer notes.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pio-robo"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A simple grid-based robot programming environment for teaching Python functions-first."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Edward Withers" }
|
|
13
|
+
]
|
|
14
|
+
license = { text = "MIT" }
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Intended Audience :: Education",
|
|
18
|
+
"Topic :: Education",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
student = [
|
|
25
|
+
"pytest>=8,<10",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
dev = [
|
|
29
|
+
"pytest>=8,<10",
|
|
30
|
+
"build",
|
|
31
|
+
"twine",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
robo = "robo.cli:main"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
where = ["src"]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.package-data]
|
|
41
|
+
"robo.templates" = ["README.md", "exercises/*.py"]
|
pio_robo-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pio-robo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A simple grid-based robot programming environment for teaching Python functions-first.
|
|
5
|
+
Author: Edward Withers
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Intended Audience :: Education
|
|
9
|
+
Classifier: Topic :: Education
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Requires-Python: >=3.9
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Provides-Extra: student
|
|
15
|
+
Requires-Dist: pytest<10,>=8; extra == "student"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
18
|
+
Requires-Dist: build; extra == "dev"
|
|
19
|
+
Requires-Dist: twine; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# š¤ Robo ā Classroom Programming Environment
|
|
23
|
+
|
|
24
|
+
A simple Python-based learning environment for teaching programming functions-first through grid-based robot challenges.
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
### Install from PyPI
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install robo
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Development install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone <repo>
|
|
38
|
+
cd robo
|
|
39
|
+
pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Run a world
|
|
43
|
+
|
|
44
|
+
From a student project folder:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m robo world1.0
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Student solution files live in:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
exercises/
|
|
54
|
+
world1_0.py
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Check progress
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m robo summary
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Run tests
|
|
64
|
+
|
|
65
|
+
From the project root:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python -m pytest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Run tests when you:
|
|
72
|
+
|
|
73
|
+
- add new worlds
|
|
74
|
+
- change commands
|
|
75
|
+
- change runner/display behaviour
|
|
76
|
+
|
|
77
|
+
## Contribute
|
|
78
|
+
|
|
79
|
+
1. Create or edit code.
|
|
80
|
+
2. Run the test suite.
|
|
81
|
+
3. Check that student worlds still run.
|
|
82
|
+
4. Open a pull request.
|
|
83
|
+
|
|
84
|
+
See the `docs/` folder for pupil-facing command guides and teacher/developer notes.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/pio_robo.egg-info/PKG-INFO
|
|
5
|
+
src/pio_robo.egg-info/SOURCES.txt
|
|
6
|
+
src/pio_robo.egg-info/dependency_links.txt
|
|
7
|
+
src/pio_robo.egg-info/entry_points.txt
|
|
8
|
+
src/pio_robo.egg-info/requires.txt
|
|
9
|
+
src/pio_robo.egg-info/top_level.txt
|
|
10
|
+
src/robo/__init__.py
|
|
11
|
+
src/robo/__main__.py
|
|
12
|
+
src/robo/cli.py
|
|
13
|
+
src/robo/commands.py
|
|
14
|
+
src/robo/project.py
|
|
15
|
+
src/robo/run.py
|
|
16
|
+
src/robo/world_tools.py
|
|
17
|
+
src/robo/solutions/__init__.py
|
|
18
|
+
src/robo/solutions/world1_0.py
|
|
19
|
+
src/robo/solutions/world1_1.py
|
|
20
|
+
src/robo/solutions/world1_2.py
|
|
21
|
+
src/robo/solutions/world1_3.py
|
|
22
|
+
src/robo/solutions/world1_4.py
|
|
23
|
+
src/robo/solutions/world1_5.py
|
|
24
|
+
src/robo/solutions/world1_6.py
|
|
25
|
+
src/robo/solutions/world1_7.py
|
|
26
|
+
src/robo/solutions/world1_8.py
|
|
27
|
+
src/robo/solutions/world1_9.py
|
|
28
|
+
src/robo/solutions/world2_0.py
|
|
29
|
+
src/robo/solutions/world2_1.py
|
|
30
|
+
src/robo/teacher_solutions/__init__.py
|
|
31
|
+
src/robo/teacher_solutions/world1_0.py
|
|
32
|
+
src/robo/teacher_solutions/world1_1.py
|
|
33
|
+
src/robo/teacher_solutions/world1_2.py
|
|
34
|
+
src/robo/teacher_solutions/world1_3.py
|
|
35
|
+
src/robo/teacher_solutions/world1_4.py
|
|
36
|
+
src/robo/teacher_solutions/world1_5.py
|
|
37
|
+
src/robo/teacher_solutions/world1_6.py
|
|
38
|
+
src/robo/teacher_solutions/world1_7.py
|
|
39
|
+
src/robo/teacher_solutions/world1_8.py
|
|
40
|
+
src/robo/teacher_solutions/world1_9.py
|
|
41
|
+
src/robo/teacher_solutions/world2_0.py
|
|
42
|
+
src/robo/teacher_solutions/world2_1.py
|
|
43
|
+
src/robo/templates/__init__.py
|
|
44
|
+
src/robo/templates/exercises/world1_0.py
|
|
45
|
+
src/robo/templates/exercises/world1_1.py
|
|
46
|
+
src/robo/templates/exercises/world1_2.py
|
|
47
|
+
src/robo/templates/exercises/world1_3.py
|
|
48
|
+
src/robo/templates/exercises/world1_4.py
|
|
49
|
+
src/robo/templates/exercises/world1_5.py
|
|
50
|
+
src/robo/templates/exercises/world1_6.py
|
|
51
|
+
src/robo/templates/exercises/world1_7.py
|
|
52
|
+
src/robo/templates/exercises/world1_8.py
|
|
53
|
+
src/robo/templates/exercises/world1_9.py
|
|
54
|
+
src/robo/templates/exercises/world2_0.py
|
|
55
|
+
src/robo/templates/exercises/world2_1.py
|
|
56
|
+
src/robo/worlds/__init__.py
|
|
57
|
+
src/robo/worlds/world1_0.py
|
|
58
|
+
src/robo/worlds/world1_1.py
|
|
59
|
+
src/robo/worlds/world1_2.py
|
|
60
|
+
src/robo/worlds/world1_3.py
|
|
61
|
+
src/robo/worlds/world1_4.py
|
|
62
|
+
src/robo/worlds/world1_5.py
|
|
63
|
+
src/robo/worlds/world1_6.py
|
|
64
|
+
src/robo/worlds/world1_7.py
|
|
65
|
+
src/robo/worlds/world1_8.py
|
|
66
|
+
src/robo/worlds/world1_9.py
|
|
67
|
+
src/robo/worlds/world2_0.py
|
|
68
|
+
src/robo/worlds/world2_1.py
|
|
69
|
+
tests/test_commands.py
|
|
70
|
+
tests/test_display.py
|
|
71
|
+
tests/test_runner.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
robo
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Robo package
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from robo.project import create_project
|
|
5
|
+
from robo.run import run_world, show_summary
|
|
6
|
+
from robo.world_tools import (
|
|
7
|
+
create_world_from_template,
|
|
8
|
+
delete_world,
|
|
9
|
+
list_world_files,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_parser():
|
|
14
|
+
parser = argparse.ArgumentParser(
|
|
15
|
+
prog="robo",
|
|
16
|
+
description="Robo: a simple grid-based Python teaching tool."
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
subparsers = parser.add_subparsers(
|
|
20
|
+
dest="command",
|
|
21
|
+
required=True
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
new_parser = subparsers.add_parser(
|
|
25
|
+
"new",
|
|
26
|
+
help="Create a new student project."
|
|
27
|
+
)
|
|
28
|
+
new_parser.add_argument(
|
|
29
|
+
"project_name",
|
|
30
|
+
help="Name of the student project folder to create."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
run_parser = subparsers.add_parser(
|
|
34
|
+
"run",
|
|
35
|
+
help="Run one world from the current student project."
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
run_parser.add_argument(
|
|
39
|
+
"world_name",
|
|
40
|
+
help="World to run, e.g. world1.0"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
subparsers.add_parser(
|
|
44
|
+
"summary",
|
|
45
|
+
help="Show which worlds are completed in the current student project."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
make_world_parser = subparsers.add_parser(
|
|
49
|
+
"make-world",
|
|
50
|
+
help="Create the next world from scripts/new_world.py."
|
|
51
|
+
)
|
|
52
|
+
make_world_parser.add_argument(
|
|
53
|
+
"--name",
|
|
54
|
+
help="Optional world name, e.g. world2.0. If omitted, the next number is used."
|
|
55
|
+
)
|
|
56
|
+
make_world_parser.add_argument(
|
|
57
|
+
"--overwrite",
|
|
58
|
+
action="store_true",
|
|
59
|
+
help="Overwrite files if this world already exists."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
delete_world_parser = subparsers.add_parser(
|
|
63
|
+
"delete-world",
|
|
64
|
+
help="Delete generated files for a world."
|
|
65
|
+
)
|
|
66
|
+
delete_world_parser.add_argument(
|
|
67
|
+
"--name",
|
|
68
|
+
required=True,
|
|
69
|
+
help="World name to delete, e.g. world2.0"
|
|
70
|
+
)
|
|
71
|
+
delete_world_parser.add_argument(
|
|
72
|
+
"--dry-run",
|
|
73
|
+
action="store_true",
|
|
74
|
+
help="Show what would be deleted without deleting files."
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
subparsers.add_parser(
|
|
78
|
+
"list-worlds",
|
|
79
|
+
help="List worlds in the package."
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return parser
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def main():
|
|
86
|
+
parser = build_parser()
|
|
87
|
+
args = parser.parse_args()
|
|
88
|
+
|
|
89
|
+
if args.command == "new":
|
|
90
|
+
create_project(args.project_name)
|
|
91
|
+
|
|
92
|
+
elif args.command == "run":
|
|
93
|
+
run_world(args.world_name, Path.cwd())
|
|
94
|
+
|
|
95
|
+
elif args.command == "summary":
|
|
96
|
+
show_summary(Path.cwd())
|
|
97
|
+
|
|
98
|
+
elif args.command == "make-world":
|
|
99
|
+
create_world_from_template(
|
|
100
|
+
overwrite=args.overwrite,
|
|
101
|
+
world_name=args.name
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
elif args.command == "delete-world":
|
|
105
|
+
delete_world(
|
|
106
|
+
world_name=args.name,
|
|
107
|
+
dry_run=args.dry_run
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
elif args.command == "list-worlds":
|
|
111
|
+
list_world_files()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
main()
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
world = None
|
|
2
|
+
robo = None
|
|
3
|
+
trail = []
|
|
4
|
+
|
|
5
|
+
def load_world(w, r):
|
|
6
|
+
global world, robo, trail
|
|
7
|
+
world = w
|
|
8
|
+
robo = r
|
|
9
|
+
trail = [(robo["x"], robo["y"])]
|
|
10
|
+
|
|
11
|
+
def move():
|
|
12
|
+
x = robo["x"]
|
|
13
|
+
y = robo["y"]
|
|
14
|
+
d = robo["direction"]
|
|
15
|
+
|
|
16
|
+
if d == "N":
|
|
17
|
+
new_x, new_y = x, y + 1
|
|
18
|
+
elif d == "E":
|
|
19
|
+
new_x, new_y = x + 1, y
|
|
20
|
+
elif d == "S":
|
|
21
|
+
new_x, new_y = x, y - 1
|
|
22
|
+
elif d == "W":
|
|
23
|
+
new_x, new_y = x - 1, y
|
|
24
|
+
|
|
25
|
+
if not (0 <= new_x < 5 and 0 <= new_y < 5):
|
|
26
|
+
raise Exception("š§ Can't leave the grid!")
|
|
27
|
+
|
|
28
|
+
if world[new_y][new_x] in ["|", "-"]:
|
|
29
|
+
raise Exception("ā Hit a wall!")
|
|
30
|
+
|
|
31
|
+
robo["x"] = new_x
|
|
32
|
+
robo["y"] = new_y
|
|
33
|
+
trail.append((new_x, new_y))
|
|
34
|
+
print("ā”ļø move")
|
|
35
|
+
|
|
36
|
+
def turn_left():
|
|
37
|
+
directions = ["N", "W", "S", "E"]
|
|
38
|
+
robo["direction"] = directions[(directions.index(robo["direction"]) + 1) % 4]
|
|
39
|
+
print("ā©ļø turn left")
|
|
40
|
+
|
|
41
|
+
def turn_right():
|
|
42
|
+
directions = ["N", "E", "S", "W"]
|
|
43
|
+
robo["direction"] = directions[(directions.index(robo["direction"]) + 1) % 4]
|
|
44
|
+
print("āŖļø turn right")
|
|
45
|
+
|
|
46
|
+
def get_star():
|
|
47
|
+
x, y = robo["x"], robo["y"]
|
|
48
|
+
|
|
49
|
+
if world[y][x] == "ā":
|
|
50
|
+
world[y][x] = "."
|
|
51
|
+
print("ā picked up")
|
|
52
|
+
else:
|
|
53
|
+
raise Exception("ā No star here!")
|
|
54
|
+
|
|
55
|
+
def place_star():
|
|
56
|
+
x, y = robo["x"], robo["y"]
|
|
57
|
+
|
|
58
|
+
if world[y][x] == ".":
|
|
59
|
+
world[y][x] = "ā"
|
|
60
|
+
print("ā placed")
|
|
61
|
+
else:
|
|
62
|
+
raise Exception("ā Can't place star here!")
|
|
63
|
+
|
|
64
|
+
def get_position_in_front():
|
|
65
|
+
x = robo["x"]
|
|
66
|
+
y = robo["y"]
|
|
67
|
+
d = robo["direction"]
|
|
68
|
+
|
|
69
|
+
if d == "N":
|
|
70
|
+
return x, y + 1
|
|
71
|
+
elif d == "E":
|
|
72
|
+
return x + 1, y
|
|
73
|
+
elif d == "S":
|
|
74
|
+
return x, y - 1
|
|
75
|
+
elif d == "W":
|
|
76
|
+
return x - 1, y
|
|
77
|
+
|
|
78
|
+
def is_inside_grid(x, y):
|
|
79
|
+
return 0 <= x < 5 and 0 <= y < 5
|
|
80
|
+
|
|
81
|
+
def wall_ahead():
|
|
82
|
+
x, y = get_position_in_front()
|
|
83
|
+
|
|
84
|
+
if not is_inside_grid(x, y):
|
|
85
|
+
return True
|
|
86
|
+
|
|
87
|
+
return world[y][x] in ["|", "-"]
|
|
88
|
+
|
|
89
|
+
def can_move():
|
|
90
|
+
return not wall_ahead()
|
|
91
|
+
|
|
92
|
+
def star_here():
|
|
93
|
+
x = robo["x"]
|
|
94
|
+
y = robo["y"]
|
|
95
|
+
|
|
96
|
+
return world[y][x] == "ā"
|
|
97
|
+
|
|
98
|
+
def star_ahead():
|
|
99
|
+
x, y = get_position_in_front()
|
|
100
|
+
|
|
101
|
+
if not is_inside_grid(x, y):
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
return world[y][x] == "ā"
|
|
105
|
+
|
|
106
|
+
def facing_north():
|
|
107
|
+
return robo["direction"] == "N"
|
|
108
|
+
|
|
109
|
+
def facing_east():
|
|
110
|
+
return robo["direction"] == "E"
|
|
111
|
+
|
|
112
|
+
def facing_south():
|
|
113
|
+
return robo["direction"] == "S"
|
|
114
|
+
|
|
115
|
+
def facing_west():
|
|
116
|
+
return robo["direction"] == "W"
|
|
117
|
+
|
|
118
|
+
# Pupil-friendly aliases for grid directions
|
|
119
|
+
|
|
120
|
+
def facing_up():
|
|
121
|
+
return facing_north()
|
|
122
|
+
|
|
123
|
+
def facing_right():
|
|
124
|
+
return facing_east()
|
|
125
|
+
|
|
126
|
+
def facing_down():
|
|
127
|
+
return facing_south()
|
|
128
|
+
|
|
129
|
+
def facing_left():
|
|
130
|
+
return facing_west()
|
|
131
|
+
|
|
132
|
+
def show_world():
|
|
133
|
+
print("\nš WORLD")
|
|
134
|
+
|
|
135
|
+
for y in reversed(range(5)):
|
|
136
|
+
row = ""
|
|
137
|
+
for x in range(5):
|
|
138
|
+
|
|
139
|
+
# Determine cell content
|
|
140
|
+
if x == robo["x"] and y == robo["y"]:
|
|
141
|
+
cell = "š¤"
|
|
142
|
+
else:
|
|
143
|
+
cell = world[y][x]
|
|
144
|
+
|
|
145
|
+
# Pad NON-emoji cells
|
|
146
|
+
if cell in [".", "|", "-"]:
|
|
147
|
+
cell = cell + " " # make it width ~2
|
|
148
|
+
# emoji left as-is
|
|
149
|
+
|
|
150
|
+
row += cell + " "
|
|
151
|
+
|
|
152
|
+
print(row)
|
|
153
|
+
|
|
154
|
+
print(f"\nš§ Facing: {robo['direction']}\n")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def show_custom_world(world_data, robo_data):
|
|
159
|
+
print("\nš TARGET")
|
|
160
|
+
|
|
161
|
+
for y in reversed(range(5)):
|
|
162
|
+
row = ""
|
|
163
|
+
for x in range(5):
|
|
164
|
+
if x == robo_data["x"] and y == robo_data["y"]:
|
|
165
|
+
cell = "š¤"
|
|
166
|
+
else:
|
|
167
|
+
cell = world_data[y][x]
|
|
168
|
+
|
|
169
|
+
if cell in [".", "|", "-"]:
|
|
170
|
+
cell = cell + " "
|
|
171
|
+
|
|
172
|
+
row += cell + " "
|
|
173
|
+
|
|
174
|
+
print(row)
|
|
175
|
+
|
|
176
|
+
print(f"\nš§ Facing: {robo_data['direction']}\n")
|
|
177
|
+
|
|
178
|
+
|