Question Authors' Forum

Parson's Problems

Parson's Problems

by Richard Lobb -
Number of replies: 9

A user asked a question in an email, that I thought might be of interest to other users, so I'm posting it and my reply here:

I am also interested in making Moodle work with Parsons problems. There is a ready made library to do this under the MIT license (here). I was wondering if it would be easy for a question prototype to eschew the ACE editor and load it up as a parsons problem instead. The running could then be done by grabbing the code from the DOM when the submit button is clicked or perhaps just hiding the ACE editor and updating it each time there is a drag and drop. Does that sound reasonable? I could make a Moodle plugin instead – but that would mean learning lots more than I want to about Moodle question types!

CodeRunner supports several different UI plugins - Ace is just the default. See here. The appropriate one for your needs is the HTML UI. As a quick partial proof of concept I created a new Python3 question, customised it to use the HTML UI, and copied all the Parsons code including library scripts and CSS into the global extra field. The result is a question that looks like this:

Screen shot of parsons problem in coderunner

I attach its xml export

It works in the sense that you can construct a solution, click Get feedback, and be told if it's right or not. But it doesn't work with CodeRunner, i.e. clicking Check doesn't work!

To get it working properly in CodeRunner you'd need to do a fair bit of work, however - see the documentation for what's required. For a start you'd want the elements in the solution area to be given the class coderunner-ui-element and they would need names - perhaps just line0, line1, line2 etc. They would have to be elements that implemented the jquery val method. [You can add JavaScript code to implement that if necessary - see the jquery documentation.] If those conditions are satisfied, the student answer submitted when Check is clicked would be a JSON object with all the solution element names and values. The template code could sort them in order and run the resulting program (with test code added). Or: you could just name all the lines with the same name and the associated value would then be all the values in DOM order.

I think, though, that you might be better off starting again (but still using HTML UI) rather than trying to use the supplied code. The vast majority of the code in the Parsons github repo is irrelevant in a CodeRunner context.

Further down the line you'd want a question prototype where the bulk of the code was in a template parameter - see this discussion.

In reply to Richard Lobb

Re: Parson's Problems

by Jon Witts -

This is really interesting; I use Parson's Problems a lot in my instruction of younger students when learning Python and it would be great to be able to include them in Moodle quizzes. I was looking at the other moodle question types to see if it could be done, but did not find anything satisfactory... 

As I have only been using CodeRunner for a day at this point, I feel a complete rewrite of a question type is somewhat beyond me at the minute!

The javascript library looks great too; but having something like this integrated into Moodle quizzes would be amazing!

In reply to Richard Lobb

Re: Parson's Problems

by Paul Powell -

Hi Richard

I have made this work after a fashion. A DOM observer essentially goes through the drop box after every update and transforms the list elements into raw code. The code is then copied into a textarea which is hidden.

The only current functional issue from the user side is that the Parsons Problem resets after every check (because of the page reload). How is this done with the ACE editor? If I can get a copy of the program when the page loads after a check, then this shouldn't be a problem to code.

On the admin side I need to:

  1. trim out all / most of the unneeded JavaScript. The first step is to externalise JQuery or better, use the Moodle JQuery.
  2. Look at pulling out all the code that test runs the program
  3. Find some place to define the problem - I want to be able to insert the code. the Pre-Load answer box seems like the most sensible place, but can I access this as a template variable?
  4. Currently the correct solution is included in the HTML. I don't need the correct solution as this will be checked by Moodle. Is there some way to remove tabs and mix it up?

Any help with any of these questions is much appreciated.

Thanks

Paul

In reply to Paul Powell

Re: Parson's Problems

by Richard Lobb -

This was a very timely posting, as our stage 1 teaching team has just been discussing whether to use Parson's Problems. So I jumped in over the weekend and tried to get something working, using your code as a starting point. 

It turned out not to be all that easy, but I do have a working system, albeit a rather ugly one from the question-author's perspective (hopefully not from the student's).

I ripped out all the unnecessary JavaScript (which was most of it) but still had to rewrite most of what was left in order to be able to sync CodeRunner with both the LHS and RHS panels. Having got that working I wondered why we even had two panels - it seems to waste a lot of valuable screen real estate. So I collapsed the UI down into a single panel.

I haven't yet got rid of the JQuery (two version). I would have hoped we could just use Moodle's JQuery but it didn't work out of the box and I haven't had time to explore further. I have however stripped out the underscore package which isn't needed.

Constructing a prototype for such a question type proved problematic. I really need to find a decent way to pass parameters to HTML-UI questions. The best I've been able to come up with is to define the global-extra code in the prototype as a Twig macro, which you then invoke as a single line within the Global Extra field. It's a rather ugly non-intuitive approach but it does work easily enough once you know what to do.

I attach the prototype and an example question. But they'll only work in CodeRunner 4.0 or later (which I released around January this year). Do you have that? 

Here's what it looks like when first loaded:

Initial view of Parsons Problem

And when finished:

Solved parsons problem

There is currently no way to handle distractors, but they weren't something I wanted. They could be done in this single-pane approach by adding a 'disable' toggle to each code line. There is also no syntax colouring, but that didn't appear to work with the original js-parsons code, either. 

Let me know if you're able to get it working or not. Please realise it's still a work-in-progress and will undoubtedly change over the next few weeks. I'll move the question to the University of Canterbury github repo of question types soon.

Thanks again for introducing me to js-parsons and generally kicking things into action. And for the idea of using a MutationObserver.

Richard


In reply to Richard Lobb

Re: Parson's Problems

by Paul Powell -

That's great, thank you. I've very much been using the approach of hack it to get it working then tidy up afterwards. My JavaScript is weak and JQuery non-existent - so it certainly helps to get a more experienced eye on these things.

Personally I think the two boxes approach works well - it gives the student more of a feel of constructing a solution rather than reordering it - seeking what to look for first.

With your version, does the toggle stuff still work? (example here)

My current solution of passing the program looks like this:

{
"program": {
"1": "def is_true(boolean_value):",
"2": "    if boolean_value:",
"3": "        return True",
"4": "    return False",
"5": "return true #distractor"
}
}

As in the other thread I started, I converted all parameters to arrays before passing (rather than some objects being stdClass). This means I can output it using something like:

{% set code = "" %}
{% for line in program %}
{% set code = code + line + "\n" %}
{% endfor %}

I can then use {{ code }} to set the variable in the JavaScript. If I add the shuffle extension to TWIG, then I can also randomise the lines as they get passed in.


In reply to Paul Powell

Re: Parson's Problems

by Paul Powell -

Just had a dig into your template and seen you are using Python to set up the question instead of Twig - will have a play with that.

In reply to Paul Powell

Re: Parson's Problems

by Richard Lobb -

Hi Paul

There's quite a lot of stuff there to reply to, so for now just a couple of brief comments:

  1. I take your point that having a repository of unused lines of code gives a slightly different (better?) UI. But I found it difficult to accommodate the question inside a typical Moodle question page - the double panel was just too wide. I guess it depends on screen width, but I was happy to compromise on a single panel for our purposes. It can even be used on a cell phone! But if you want to go back to the double-panel approach I attach an xml export of a mostly working question up to the point where I gave up and went for a single panel.
  2. I'm not sure I get your example iterating over object attributes in Twig. Why not write it in the template parameters as:

    { "code": ["Line1", "Line2", "Line3"]}

    then expand it as:

    {{ code | join('\n') }}
  3. No, my version doesn't do toggles. I'll look into that to see if it's a feature I want. I cut things back to a bare minimum of functionality in order to understand the original code.
But I find it a nuisance even breaking code into separate lines with quotes. Hence my solution of dumping the job onto Python, which can do all the indent stripping and randomisation and even construct the correct answer given just a copy-pasted single string.r

I've uploaded my working Parson's Problem question type onto github here. It has quite a few bug fixes since the version I sent you. In particular the code that does indentation when you drag and drop was seriously broken in the original js-parsons - lines kept springing left and write when I let go with the mouse. I believe I've solved that in the current version. Also, if you're to have multiple Parsons Problems questions on a single page you need to construct unique HTML element IDs using the ___textareaId___ macro.

In reply to Richard Lobb

Re: Parson's Problems

by Paul Powell -

For point 1, perhaps the code lines below the construction area would make sense?

For point 2, it is because I am going 3 sides round the square! Your solution makes perfect sense. If there were some other reason to want to iterate over the JSON structure then passing it to Twig as a nested array rather than StdClass would make it possible - but not needed by me now.

For point 3: OK, good to know.

For the code (and indeed for the gap filler UI) I thought the neatest way would be to put the code in Answer Box Preload. This makes sense to me as it is what we want to preload into the answer box. I am guessing this would mean just exposing the Answer Box Preload as a Twig variable and then putting that in the template.

In reply to Paul Powell

Re: Parson's Problems

by Richard Lobb -
  1. I'll let you investigate how well it works with the code lines above or below the construction area. Certainly it takes more screen real estate but it might indeed feel better from a UI standpoint. I doubt it's a real game changer though.
  2. Another recent poster (see this thread) also wanted to have JSON objects passed in to Twig as associative arrays rather than as objects. I can achieve that simply by changing one line of code - a call to json_decode - passing in a parameter to force associative arrays rather than objects. As I said in that thread: "... I'm sorry, but I'm not prepared to make that change, as I don't know what other consequences there might be. You're the first person who has ever drawn my attention to this and I feel the risks are just too great." But with a second person asking I am prepared to rethink.

    It's possible that I could break existing question types by making that change, for example if someone were using the Twig attribute function to extract attributes from the object. But more fundamentally it seems to me that JSON objects should get converted to Twig object whereas JSON arrays should get converted to Twig arrays. Iterating over the attributes of an object is sometimes convenient but never pretty. If you want to iterate over something, shouldn't it be a list?!
With regard to where to put the answer for Parson's problem: I agree that it seems totally logical to put it in the Answer or Answer preload boxes. But the current architecture for the HTML-UI plugin simply doesn't allow this.

[Ignore this paragraph unless you're wondering why]. For security reasons you can't pass the answer through to the browser for use by the JavaScript, or smart students could simply pull it out and use it, hidden or not. So the stripping and shuffling of the code has to be done on the server before the HTML _UI is loaded. The Twigging of the various question fields takes place when the question is first instantiated and it isn't safe (or defined, or nice, or ...) for one part of the question to try to use other parts of the question, which may or may not yet be finalised. The only exception is the template parameters field which is processed at the very start in order to define the environment for all subsequent Twigging.

I agree it would be nice to have a way to parameterise the HTML-UI data and I'm thinking about it. But yet another layer of code hacking is not the solution. I think most people would agree the architecture is quite complicated enough already. I need to find a way to simplify it, not complicate it further :)
In reply to Richard Lobb

Re: Parson's Problems

by Richard Lobb -

I've figured out how to use Moodle's jquery and jquery-ui, rather than include the source for both within the Parson's problem prototype. This reduces the HTML size from around 300k to 14k! It also removes potential conflicts between the two different versions.

I've also fixed the bug that allowed you to lose lines by dragging them off to the right of the window.

The updated prototype can be downloaded from github: https://github.com/trampgeek/ucquestiontypes.