diff options
author | Timotej Lazar <timotej.lazar@fri.uni-lj.si> | 2015-12-14 11:39:15 +0100 |
---|---|---|
committer | Timotej Lazar <timotej.lazar@fri.uni-lj.si> | 2015-12-14 11:39:15 +0100 |
commit | 4918cebf5f135993cd1d2d61bc906559e627f526 (patch) | |
tree | edecbf110f0b54409596bd41f7b0ea8aca469153 | |
parent | 91962ece64d200dcb93ce4a549c98bf4f94a22f7 (diff) |
Start documenting how to define new problems
-rw-r--r-- | readme.md | 221 |
1 files changed, 203 insertions, 18 deletions
@@ -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.") + ''' |