The following is a detailed explanation of an extended example stack called NameQuiz to demonstrate various aspects of MoStacks' scripting capabilities. With the help of a number of scripts, NameQuiz is a MoStack that nearly has the look and feel of a full application instead of being only a merely passive data store.
The stack implements an interactive quiz: A question, chosen at random from a pool of questions, together with four possible answers is offered. You choose one answer. You are told whether it is right or wrong, and it is counted as such. After a given number of questions the quiz is over, and you are told your score.
General stack structure
The stack needs 3 backgrounds, because there is the need for 3 different types of cards:
There are nearly 80 cards for a pool of 80 questions, all of the same background of course, called Question. Each card has a number of text fields, 1 for the question, and 4 for the answers. The right answer is always in the first of the 4 answer fields so that there is no need to mark the right answer somehow. (But on the other hand, this makes some kind of answer shuffling necessary for the quiz to be non-trivial.)
There is an additional boolean field that allows to mark questions as "asked". This prevents questions from being asked twice or even more often during the same quiz. (From this follows the need for a way to "reset" the stack at the beginning of each new quiz round.)
The very first card of the stack is the one where all interaction takes place, the one that more or less "is" the quiz, if seen as an application instead of a simple stack. Because this front card called Ask has a different structure from the quiz cards, a different, second background (also called Ask) is needed.
Below 5 text fields, 1 for the question, and 4 for the 4 (shuffled) questions, there a number of buttons used for "operating" the quiz. For details see below.
Some questions and answers are rather long, so the background Ask is designed to offer a maximum of usable area for text, by using several MoStacks features:
- The fields inherit a small font of 10 points from the stack font.
- The background has the Dense layout flag set which minimizes the spacing between the fields.
- The labels used are very short, to allow long fields.
- The stack is meant to be used in full screen mode, a mode that MoStacks supports to make the full screen available to cards.
If you compare the screenshots above from a SE P1i with the usual UIQ3 dialogs that use rather big fonts and have to share screen space with a large assortment of elements above and below them, maybe you are surprised what is really possible!
Now to the least obvious, third background. This stack that wants to be an application has the need for some "variables" that hold the current state of the quiz: How many questions were asked already, and how many of them right and how many wrong?
Standard script variables are only valid within a script, and keep their value only during a single script execution. Obviously, something more durable is needed. Maybe you guessed it already: Its perfectly possible to treat fields on cards as variables because, obviously, they have the required durability and lifetime.
Even more: If the state of the quiz is stored in fields, you can stop in the middle of a quiz, save the stack, load it again tommorow and just continue with the quiz!
So this example stack has a third background called Variables and a single card of that background, with a number of fields holding values that are explained in detail later.
Script Overview
The stack works with 6 scripts, accessible through the 6 buttons on the Ask card. The Next script is by far the most complicated one because it has the job to choose a Question card and transfer question plus 4 possible answers to the Ask card.
The scripts behind the buttons 1, 2, 3 and 4 are almost identical: They decide whether the answer with the corresonding number is the right one, announce "Correct" or "Wrong" and count. Indeed, if MoStacks' script language was only a little more advanced it would be possible to fold those 4 scripts into one that takes a number as a parameter.
The Reset script resets everything and makes the stack ready for the start of another quiz.
All six scripts refer to the values on the Variables card and coordinate their work through them.
By the way, when taking the quiz, it's up to you to tap the buttons in the right order. The scripts don't contain any code that stops you from doing nonsense, like e.g. tapping Reset in the middle of a quiz and loosing what you did up to that point. It would be possible to make the scripts more or less foolproof - the script language is powerful enough for that - but that would make the scripts considerably more complicated.
The Next Script
The script Next behind the thus-labeled button has several sub-tasks that are explained in detail in the following so that it should be possible to get a good understanding of the whole script.
The first task is choosing a random card. The following is the part of the script doing that:
1 y=0 2 repeat while y=0 3 x=random(number of cards of background "Question") 4 repeat for each card c of background "Question" 5 if x=1 then 6 exit repeat 7 end if 8 x=x-1 9 end repeat 10 if not (field "Asked" of card c) then 11 exit repeat 12 end if 13 end repeat 14 put "T" into field "Asked" of card c
(No, MoStacks scripts don't have line numbers, those numbers are only written here to make referring to the lines easy.)
Line 3 calculates a random number in the range 1 up to the number of Question cards. The repeat loop on the lines 4 to 9 goes to that card which, after the loop, is contained in the variable c. (Of course the script language should offer a command to just grab card #x of background Question, in one simple line, and eventually it will, but does not yet.)
The card is then checked whether the question on it was already asked (line 10), and if not, a second repeat loop is left because the card is ok. That second, outer loop spans the lines 2 to 13 and works with an ending condition y=0, which is always true, meaning that the loop only ends by the exit repeat on line 11, meaning also that it will loop endlessly if all cards have been asked.
Just in case you wondered about that y=0 - maybe you guessed it: Proper boolean constants are another feature that awaits implementation.
Line 14 is there to mark the card as "asked". (The string "T" gives True when assigned to a boolean field.)
The second task is to prepare for the shuffling of the four possible answers as they are given on the choosen card c, because the correct answer always comes first on all Question cards, and it would of course be no good to just transfer them in that order to the Ask card:
1 x=random(4) 2 repeat while x>0 3 first=random(4) 4 second=random(4) 5 if first<>second then 6 temp=field first of card "Variables" 7 put field second of card "Variables" into field first of card "Variables" 8 put temp into field second of card "Variables" 9 end if 10 x=x-1 11 end repeat
Given all the limitations that the script language still has, the way how this can be done is far from obvious:
The card Variables has four integer fields, as the first four fields. Their names are not relevant here, as they will be addressed by number (1, 2, 3 and 4) and not by name as it is frequently done in scripts. Originally the four fields contained the numbers 1, 2, 3, and 4, in this order.
Now, the script language offers no arrays (yet), but a number of fields of identical type, immediately following each other on a card, addressed by field number instead of by field name, are a good substitute for an array.
The script section above chooses two out of the four fields at random (lines 3 and 4) and uses them only if indeed two different fields were chosen (test on line 5). It then swaps the values in those two fields (lines 6 to 8). With the help of the repeat loop spanning the lines 2 to 11 it does this randomly up to 4 times.
All this swapping has the result that at the end of this script fragment the numbers 1 to 4 end up in random positions within the four fields. Note that when beginning a new quiz there is no need to bring back order into this and again storing 1 into the first field, 2 into the second, and so on, because shuffling is possible from whatever starting point. The only important thing is that each number is contained in only one field.
Now we are finally ready to transer the question and the four randomized answers to the Ask card:
1 go to card "Ask" 2 put field "Question" of card c into field "Question" 3 put field (field 1 of card "Variables"+1) of card c into field "Answer 1" 4 put field (field 2 of card "Variables"+1) of card c into field "Answer 2" 5 put field (field 3 of card "Variables"+1) of card c into field "Answer 3" 6 put field (field 4 of card "Variables"+1) of card c into field "Answer 4"
What is done here is a little tricky because it is like using pointers in other languages. The four answer fields on the Ask card are again addressed by numbers - the four numbers that we prepared in the first four fields of the Variables cards. We just have to go 1 higher because on the Ask card the Question field is the first one; the first answer field has the number 2.
To make it more clear still, you could write line 3 also this way:
3 put field ( (field 1 of card "Variables") +1 ) of card c into field "Answer 1"
Here is the full script, in its full, unchanged glory:
on select y=0 repeat while y=0 x=random(number of cards of background "Question") repeat for each card c of background "Question" if x=1 then exit repeat end if x=x-1 end repeat if not (field "Asked" of card c) then exit repeat end if end repeat put "T" into field "Asked" of card c x=random(4) repeat while x>0 first=random(4) second=random(4) if first<>second then temp=field first of card "Variables" put field second of card "Variables" into field first of card "Variables" put temp into field second of card "Variables" end if x=x-1 end repeat go to card "Ask" put field "Question" of card c into field "Question" put field (field 1 of card "Variables"+1) of card c into field "Answer 1" put field (field 2 of card "Variables"+1) of card c into field "Answer 2" put field (field 3 of card "Variables"+1) of card c into field "Answer 3" put field (field 4 of card "Variables"+1) of card c into field "Answer 4" end select