diff --git a/grim.py b/grim.py index 941ca09c9baf829d39a09bf019192cb590987f27..346c9b85ec6929008df48504feff52ba1210958c 100755 --- a/grim.py +++ b/grim.py @@ -110,7 +110,7 @@ def handle_choice_questions(output, script_name, instances): 'author': script.meta['author'], 'title': script.meta['title'], 'maxattempts': '0', - 'shuffle': True, + 'shuffle': script.meta['shuffle'] if 'shuffle' in script.meta else True, 'questions': choice_parser(script.choices, script.meta['points']), 'feedback': markdown(script.feedback), } diff --git a/hallgrim/parser.py b/hallgrim/parser.py index d4b7c1e1c5870a8bf8be4b0383b3286b863bc728..b9c5c55de5aafc0f05bdbaaf1764453ccfa284f9 100644 --- a/hallgrim/parser.py +++ b/hallgrim/parser.py @@ -1,14 +1,17 @@ import re -from hallgrim.messages import * - try: - from mistune import Renderer, InlineLexer, Markdown + from mistune import Renderer, InlineLexer, Markdown, escape + from pygments import highlight + from pygments.lexers import get_lexer_by_name + from pygments.formatters import html, HtmlFormatter except ImportError as err: print("Please install mistune to make use of markdown parsing.") print("\t pip install mistune") +no_copy = "-webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;" + def box(content, color): return '<div style="background-color: #ffedc9; border: 1px solid {}; padding: 10px; font-size: smaller;">{}</div>'.format(color, content) @@ -20,12 +23,24 @@ def yellow_box(content): def blue_box(content): return box(content, '#9999ff') +def markdown(value): + renderer = HighlightRenderer() + markdown = Markdown(renderer=renderer) + return markdown(value) class LaTeXRenderer(Renderer): def latex(self, formula): return '<span class="latex">{}</span>'.format(formula) + def block_code(self, code, lang): + if not lang: + return '\n<pre><code>%s</code></pre>\n' % \ + escape(code) + lexer = get_lexer_by_name(lang, stripall=True) + formatter = HtmlFormatter(noclasses=True, cssstyles=no_copy) + return highlight(code, lexer, formatter) + class LaTeXInlineLexer(InlineLexer): @@ -57,15 +72,20 @@ def get_custom_markdown(): def choice_parser(raw_choices, points): """ Parse the multiple choice answers and form an array that has the following form: (text, isCorrect, points, solution) and store them in an - array of arbitrary size """ - lines = raw_choices.strip().split('\n') - parse = [re.match('\[(X| )\] (.*)', line).groups() for line in lines] - if type(points) is not list: - points = [points for _ in parse] - elif len(parse) != len(points): - abort("Length of point list does not match number of choices.") - final = [(markdown(text), True if mark == 'X' else False, point) - for (mark, text), point in zip(parse, points)] + array of arbitrary size + + TODO : This is too dense. simplyfy! + """ + if type(raw_choices) is str: + lines = raw_choices.strip().split('\n') + elif type(raw_choices) is list: + lines = raw_choices + regex = re.compile('\[(\d|X| )\]\s+([\w\W]+)', re.MULTILINE) + parse = [re.match(regex, line).groups() for line in lines] + final = [( + markdown(text), + True if mark != ' ' else False, + float(mark) if mark not in ' X' else points) for mark, text in parse] return final diff --git a/scripts/feld_umgraben.py b/scripts/feld_umgraben.py new file mode 100644 index 0000000000000000000000000000000000000000..abb0542eebf050ba0c18a95d26e136212120a5d9 --- /dev/null +++ b/scripts/feld_umgraben.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +meta = { + 'author': 'Jan Maximilian Michal', + 'title': 'Feld umgraben (I1-ID: xu71ubs0lyg0)', + 'type': 'single choice', + 'shuffle' : False, + 'points': 1, # per correct choice +} + +task = """Die Reihenfolge der Elemente im Feld `a` der Länge **N** soll umgekehrt werden. Wählen +Sie den Code aus, der diese Aufgabe am besten löst:""" + +choices = [ +"""[4] +``` +for (int i = 0; i < N/2; i++) { + int tmp = a[i]; + a[i] = a[N-i-1]; + a[N-i-1] = tmp; +} +``` +""", + +"""[ ] +``` +int[] b = new int[N]; +for (int i = 0; i < N; i++) + b[i] = a[N-i-1]; +a = b; +``` +""", + +"""[ ] +``` +for (int i = 0; i < N; i++) { + int tmp = a[i]; + a[i] = a[N-i-1]; + a[N-i-1] = tmp; +}``` +""", + +"""[ ] +``` +for (int i = 0; i < N/2; i++) { + int tmp = a[i]; + a[i] = a[N-i]; + a[N-i] = tmp; +}``` +""" + + +] + +feedback = """ +1. löst die Aufgabe, indem alle Elemente "um die Mitte herum rotiert" werden. Das sind maximal n/2 Operationen. +2. löst die Aufgabe NICHT, denn nach n/2 Tauschoperationen wird nochmal zurückgetauscht und alles steht am alten Platz. +3. löst die Aufgabe, verbraucht aber doppelt soviel Speicher wie nötig. +4. löst die Aufgabe NICHT: bei der ersten Iteration wird auf das nicht existente Element a[N] zugegriffen. +""" \ No newline at end of file diff --git a/scripts/feldarbeit.py b/scripts/feldarbeit.py new file mode 100644 index 0000000000000000000000000000000000000000..8e11ad59d47a18ee81990b6d7928a43e323c1e72 --- /dev/null +++ b/scripts/feldarbeit.py @@ -0,0 +1,47 @@ +meta = { + 'author': 'Jan Maximilian Michal', + 'title': 'Feldarbeit (I1-ID: p0kaixs0lyg0)', + 'type': 'single choice', + 'points': 1, # per correct choice +} + +task = """ +Welche Ausgabe erzeugt folgender Code: + +```java +public class Feldarbeit { + public static void main(String[] args) { + int[] a = { 0, 1, 2, 3, 4, 5, 6, 7}; + int N = a.length; + for (int i = 0; i < N; i++) { + a[i] = a[(i+1) % N]; + } + for (int i = 0; i < N; i++) + System.out.print(a[i] + " "); + System.out.println(); + } +} +``` +""" + +choices = """ +[4] `1 2 3 4 5 6 7 1` +[2] `1 2 3 4 5 6 7 0` +[ ] `1 1 1 1 1 1 1 1` +[ ] `7 0 1 2 3 4 5 6` +""" + +feedback = """ +Betrachten Sie die folgenden Zeilen: +```java +for (int i = 0; i < N; i++) { + a[i] = a[(i+1) % N]; +} +``` + +Der Inhalt jeder Zelle des Arrays jeweils durch den linken Nachbarn ersetzt, +wobei an den Rändern zyklisch verfahren wird. Dadurch, dass *in-place* verfahren +wird, also keine Kopie erstellt wird, wird der neue Inhalt der 0. Zelle in die +letzte geschrieben, daher enthält das neue Array keine 0 mehr. """ + + diff --git a/scripts/multi_proto.py b/scripts/multi_proto.py index 38fd6a7397e377cda88cb9d5808f7995ae64e8c3..266816ad7c5dea64f5101f6a81266aff3f35c3aa 100644 --- a/scripts/multi_proto.py +++ b/scripts/multi_proto.py @@ -2,7 +2,7 @@ meta = { 'author': 'Jan Maximilian Michal', 'title': 'Sortieren nach Punkten (I1-ID: nipe84411eh0)', 'type': 'multiple choice', - 'points': [0.5, 5, 4, 4, 2, 1], # per correct choice + 'points': 0.5, # per correct choice } task = """ diff --git a/scripts/single_proto.py b/scripts/single_proto.py index f91a1505e1e2daf52849f2fe540851351408eec6..f96e4de18c1f8aa642f8bcc5bbc96c9ba083a22c 100644 --- a/scripts/single_proto.py +++ b/scripts/single_proto.py @@ -22,9 +22,9 @@ sortiert auszugeben (also erst große, dann kleinere Punktzahlen)? """ choices = """ [ ] `sort --reverse --k 5 --numeric-sort punkte.csv` -[ ] `sort --r --field-separator=, -k 5 --n punkte.csv` +[2] `sort --r --field-separator=, -k 5 --n punkte.csv` [ ] `sort -r -t="," -k 5 --n punkte.csv` -[X] `sort --reverse -t "," -k 5 -n punkte.csv` +[4] `sort --reverse -t "," -k 5 -n punkte.csv` [ ] `sort -r --field-separator "," -k 4 -numeric punkte.csv` [ ] `sort -r --field-separator "," -k 4 punkte.csv` """