summaryrefslogtreecommitdiff
path: root/readme.md
diff options
context:
space:
mode:
authorTimotej Lazar <timotej.lazar@fri.uni-lj.si>2015-12-14 11:39:15 +0100
committerTimotej Lazar <timotej.lazar@fri.uni-lj.si>2015-12-14 11:39:15 +0100
commit4918cebf5f135993cd1d2d61bc906559e627f526 (patch)
treeedecbf110f0b54409596bd41f7b0ea8aca469153 /readme.md
parent91962ece64d200dcb93ce4a549c98bf4f94a22f7 (diff)
Start documenting how to define new problems
Diffstat (limited to 'readme.md')
-rw-r--r--readme.md221
1 files changed, 203 insertions, 18 deletions
diff --git a/readme.md b/readme.md
index ec26acd..420120d 100644
--- a/readme.md
+++ b/readme.md
@@ -1,20 +1,20 @@
+Directory structure
+===================
+
The file hierarchy for problem data is below. Comments indicate the global
variables and functions that can be defined in each file. Only the ID is
-necessary. See existing problems for examples.
-
-<language>
-├── common.py # id, hint_type, hint() [language-specific]
-├── en.py # name, description, hint [language-specific]
-├── sl.py # name, description, hint [language-specific]
-└── problems
-    └── <group>
- ├── common.py # id, number
- ├── en.py # name, description
- ├── sl.py # name, description
-    └── <problem>
-       ├── common.py # id, number, test(), hint_type, hint() [problem-specific]
-       ├── en.py # name, plan, hint [problem-specific]
-       └── sl.py # name, plan, hint [problem-specific]
+required.
+
+ <language>
+ ├── common.py # id, hint_type, hint() [language-specific]
+ ├── en.py # name, description, hint [language-specific]
+ └── problems
+    └── <group>
+ ├── common.py # id, number
+ ├── en.py # name, description
+    └── <problem>
+       ├── common.py # id, number, test(), hint_type, hint() [problem-specific]
+       └── en.py # name, plan, hint [problem-specific]
To add a problem, create the necessary files. Pick an unused problem ID from
the relevant range below:
@@ -23,6 +23,191 @@ the relevant range below:
Python: 20000-29999
Robot: 30000-39999
-Running scripts/build_web_resources.py in the codeq-server repo will generate
-JSON files for all problems, and insert new problems, groups and languages in
-the database.
+Running `scripts/build\_web\_resources.py` in the codeq-server repo
+will generate JSON files for all problems, and insert new problems, groups and
+languages in the database.
+
+
+Hints
+=====
+
+There are two distinct hint types: normal hints and popup hints. Normal hint
+appears in the hints section of the application, and contains a single or
+multipart message. A popup hint highlights a range of user’s code and displays
+a message when the user clicks on or hovers over the highlight. The type of
+each hint is defined in the appropriate `common.py` file, like this:
+
+ # common.py
+ from server.hints import Hint, HintPopup
+ hint_type = {
+ 'normal_1': Hint('normal_1'),
+ 'normal_2': Hint('normal_2'),
+ 'popup': Hint('popup')
+ }
+
+Message for each hint is defined in the `hint` dictionary in the corresponding
+language file (e.g. `en.py`). For the example above:
+
+ # en.py
+ hint = {
+ 'normal_1': '<p>Message for hint "normal_1".</p>',
+ 'normal_2': [
+ '<p>First part.</p>',
+ {'message': '<p>Second part.</p>', 'linkText': 'Details…'},
+ '<p>Final part.</p>'
+ ],
+ 'popup': '<p>There is an error here.</p>'
+ }
+
+For a popup hint, a single string is required and will be displayed when the
+user hovers over (or clicks on) the highlighted range. For a normal hint, a
+single string can be specified which will be displayed in the hints section
+(e.g. `normal\_1`).
+
+Multipart hints
+---------------
+
+Instead of specifying a single string for a normal hint, a list of strings can
+be given; initially, only the first string will be displayed, with a “More…”
+link to show the next string and so on. List elements can also be dictionaries
+with `message` and `linkText` attributes - in this case, “More…” will be
+replaced by the value of `linkText`.
+
+In the above example, on receiving the `normal\_2` hint, application will first
+show
+
+ First part.
+ More…
+
+After clicking “More…”, the message is extended:
+
+ First part.
+ Second part.
+ Details…
+
+After clicking “Details…”, the message is extended again:
+
+ First part.
+ Second part.
+ Final part.
+
+Template arguments
+------------------
+
+A template in the form `[%=arg%]` may appear in any hint string. It
+will be replaced with an actual value returned by the `hint` or
+`test` functions (described in the next section). This is used for
+example when displaying test results, with the hint defined as
+
+ 'test_results': '<p>Your code passed [%=passed%] / [%=total%] tests.</p>'
+
+The actual values for the `passed` and `total` arguments
+are returned by the `test` function.
+
+
+Problem functions
+=================
+
+For each problem, a `test(program)` and `hint(program)` functions must be
+specified in the corresponding `common.py` file. They are called with the
+user’s current program when the Test or Hint button is pressed.
+
+The `hint(program)` function should return a list of hint objects. Each hint
+object is a dictionary containing the hint ID, any arguments for the hint
+message, and (for popup hints) `start` and `end` attributes indicating the
+range of code to highlight.
+
+The `test(program)` function should return a pair of values `(correct, hints)`,
+where `correct` is a Boolean value indicating whether the program is correct,
+and `hints` a list of hint objects as described above.
+
+For example, given an incorrect program the `test` function might return
+
+ (False, [{'id': 'test_results', 'args': {'passed': 2, 'total': 5}}])
+
+saying that the program passed two out of five tests, while the `hint` function
+might return
+
+ [{'id': 'normal_1'},
+ {'id': 'popup', 'start': 14, 'end': 20}]
+
+displaying the message for `normal\_1` hint in the hints window and
+highlighting the code between characters 14 and 20.
+
+
+Example
+=======
+
+In this section we add a new problem “Ballistics” in the “Introduction” section
+for the “Python” course. First, create the required directory structure (note
+the required “problems/” path component):
+
+ mkdir -p "python/problems/introduction/ballistics"
+
+Course, group and problem definitions are given in “common.py” files in the
+respective directories. The “en.py” file in the same directory stores the
+English versions of user messages. Additional language files can be created to
+support more languages.
+
+Course files
+------------
+
+### python/common.py
+
+Minimum content:
+
+ from server.hints import Hint
+
+ id = <course id>
+ hint_type = {
+ 'no_hint': Hint('no_hint'),
+ 'test_results': Hint('test_results'),
+ }
+
+The id attribute stores ID of the corresponding database row and must be
+different from existing courses.
+
+### python/en.py
+
+ name = 'Python'
+ description = 'Introductory Python course'
+
+ hint = {
+ 'no_hint': '<p>No hint available, sorry!</p>',
+ 'test_results': '<p>Your code passed [%=passed%] / [%=total%] tests.</p>',
+ }
+
+Group files
+-----------
+
+### python/problems/introduction/common.py
+
+Minimum content:
+
+ id = <group id>
+ number = 1
+
+The number attributes are used to determine the order of groups in a course (in
+this case, “Introduction” is the first problem group in the “Python” course).
+
+### python/problems/introduction/en.py
+
+ name = 'Introduction'
+ description = 'Expressions, variables, functions, first program.'
+
+Problem files
+-------------
+
+ id = <problem id>
+ number = 3
+ visible = True
+
+ solution = '''\
+ from math import *
+ g = 9.8
+ kot = float(input("Vnesi kot (v stopinjah): "))
+ v = float(input("Vnesi hitrost (v m/s): "))
+ kot_rad = kot * 2 * pi / 360
+ razdalja = v ** 2 * sin(2 * kot_rad) / g
+ print("Kroglo bo odneslo", razdalja, "metrov.")
+ '''