reptile7's JavaScript blog
Sunday, September 22, 2019

Approaching Quizmo, Part 3
Blog Entry #401

Today's post continues, and concludes, our Math Check discourse by presenting alternative approaches to
the generation of the numA and numB operands and
the `prompt( )`/`confirm( )`/`alert( )` calculation interface.

Better difficulty levels

The A, B, and C difficulty levels should be mutually exclusive, but they're not.
As detailed in the Add it section of Blog Entry #399,
the
Level A
numA and numB range from 0 to 9,
the
Level B
numA and numB range from 0 to 29, and
the
Level C
numA and numB range from 0 to 59.

For all three levels, a `multiply( )` run could serve up to the user a 0 * 0 = or 1 * 1 = problem, and that just wouldn't be right, would it? Clearly, it behooves us to equip Levels B and C with some minValues as well as maxValues. While we're at it, perhaps we should rejigger the maxValues somewhat as well - how many of you can carry out 59 * 58 = in your heads without recourse to pencil and paper?

Sticking with `random( )` and `ranom( )`, `getTime( )`, and %

Suppose that for a Level B multiplication we want
numA to range from 11 to 30 and
numB to range from 2 to 10.
For our consolidated `operate( )` function we can straightforwardly write:

```if (document.rekenen.arithmetic[1].checked && opIndex == 2) {     numA = random(20) + 11;     numB = ranom(9) + 2; }```

• The size of the numA range is 20. The numA range is initially 0-19: the `+ 11` shifts it to 11-30.
• The size of the numB range is 9. The numB range is initially 0-8: the `+ 2` shifts it to 2-10.
• We could specify and make use of maxValues and minValues here if we wanted to but it's not necessary.

`Math.random( )` it

A `new Date( ).getTime( )` return increases rapidly as time elapses, and modulo-ing that return does generate reasonably random numbers. That said, I prefer to generate random numbers with the Math object's `random( )` method, whose raison d'être, after all, is to return a random number. Moreover, `Math.random( )` was implemented for all platforms in JavaScript 1.1 and the Math Check authors could themselves have made use of it.

With help from the Math object's `floor( )` method, we can smoothly `Math.random( )` to the numA and numB ranges of the Level B multiplication example given earlier as follows:

```if (document.rekenen.arithmetic[1].checked && opIndex == 2) {     numA = Math.floor(Math.random( ) * 20) + 11;     numB = Math.floor(Math.random( ) * 9) + 2; }```

For the record, we've worked with such code once before: see the Animation #4 section of Blog Entry #210 vis-à-vis a discussion of HTML Goodies' "How to Create a JavaScript Animation" tutorial.

My preferred numA and numB ranges for the remaining levels and operations are specified in the Demo section at the end of the post.

A new dialogue

Several CCC sector scripts that we've covered previously feature `prompt( )` dialogs;
when I provided new demos for these scripts, I recast the `prompt( )` calls
as `<label>`ed `<input type="text">`s.
In crafting a new Math Check demo I similarly planned to convert
the `Answer = window.prompt(numA + " " + opArray[opIndex] + " " + numB + " = ", 0);` statement
to a `<span id="equationSpan"></span> <input id="userInput" name="userInput" size="10" />`
but then thought, "Why don't we do the equivalent with the `confirm( )` and `alert( )` calls? Just get it all to the page."

Structure

I divide all of the script information that the user deals with
after clicking the , , , or button
into discrete units of content and allocate those units to separate `<div>`s.

```<div id="dialogDiv"> <div id="roundDiv">Please round your answer...</div><br /> <div id="equationDiv"><span id="equationSpan"></span> <input id="userInput" name="userInput" size="10" /></div><br /> <div id="promptButtonsDiv"><button id="promptButton1" type="button" onclick="cancel1( );">Cancel</button> <button id="promptButton2" type="button" onclick="checkInput( );">OK</button></div><br /> <div id="checkInputDiv"></div><br /> <div id="confirmButtonsDiv"><button id="confirmButton1" type="button" onclick="cancel2( );">Cancel</button> <button id="confirmButton2" type="button" onclick="checkAnswer( );">OK</button></div><br /> <div id="checkAnswerDiv"></div><br /> <div id="clearDiv"><button type="button" onclick="clearIt( );">Clear It</button></div><br /> <div id="scoreDiv"><button type="button" onclick="check( );">Check Score</button> <button type="button" onclick="score( );">Reset Score</button></div> </div>```

The and `prompt( )` buttons are placed with a promptButtonsDiv div and the and `confirm( )` buttons are placed with a confirmButtonsDiv div; the onclick `cancel1( )`, `checkInput( )`, `cancel2( )`, and `checkAnswer( )` functions will be discussed shortly.

The Do you want your browser to check your answer... `confirm( )` string will be housed in the checkInputDiv div and the ...check response (answer is correct|wrong, try again later)... `alert( )` string will be housed in the checkAnswerDiv div.

I insert `<br>`s between the divs in order to double-space the units on the page.
I put the whole shebang in a dialogDiv div so I can collectively access the inner divs or brs via an Element.getElementsByTagName( ) command.

Clear it

I add a `clearIt( )` function

```<!-- I prefer to put this code at the very end of the document body, although you can window.addEventListener("load", function ( ) { ... }) it elsewhere in the document if you'd rather do that. --> <script type="text/javascript"> var dialogDivs = document.getElementById("dialogDiv").getElementsByTagName("div"); var dialogBrs = document.getElementById("dialogDiv").getElementsByTagName("br"); function clearIt( ) {     for (i = 0; i < dialogDivs.length - 1; i++) dialogDivs[i].style.display = "none";     for (i = 0; i < dialogBrs.length; i++) dialogBrs[i].style.display = "none";     document.getElementById("userInput").value = ""; } clearIt( ); </script> </body>```

that clears all of the dialog content dynamically (after all, the `alert( )`/`prompt( )`/`confirm( )` box content 'goes away' when a button on those boxes is clicked).
The `clearIt( )` function is called
(2) at the beginning of the `operate( )` function, and
(3) by clicking a button that sits right above the and buttons.
Note that the button and its clearDiv div container are themselves cleared by the `clearIt( )` function.

Initial dialog display

I visualize
the equationDiv div holding the equationSpan span and the userInput text box, and
the promptButtonsDiv and clearDiv divs and their buttons,
plus the divs' br nextSiblings,
with the `operate( )` function.

```...clearIt( ) call, numA and numB generation, numC calculation... if (opIndex == 3) {     numC = Math.round(numC);     document.getElementById("roundDiv").style.display = "block";     dialogBrs[0].style.display = "inline"; } document.getElementById("equationDiv").style.display = "block"; dialogBrs[1].style.display = "inline"; document.getElementById("equationSpan").textContent = numA + " " + opArray[opIndex] + " " + numB + " " + "="; ...```

Post-prompt responses

Clicking the promptButton2 button calls a `checkInput( )` function, which
visualizes the checkInputDiv and confirmButtonsDiv divs and their br nextSiblings and

Clicking the promptButton1 button calls a `cancel1( )` function, which
sets the userInput.value to `"null"`, as befits a `prompt( )` cancelation, and then
also runs the `checkInput( )` function.

Post-confirm responses

Clicking the confirmButton2 button calls a `checkAnswer( )` function that takes the place of the original `ans( )` function. The `checkAnswer( )` function
gets the userInput.value and assigns it to Answer,
visualizes the checkAnswerDiv div and its br nextSibling,
compares the Answer and numC values,
increments the correct or wrong tally as appropriate, and

Clicking the confirmButton1 button calls a `cancel2( )` function, which
visualizes the checkAnswerDiv div and its br nextSibling and

A bell that whistles

Lastly, I display a or image to the right of the userInput field if the Answer and numC values are equal or not equal, respectively.

```<div id="equationDiv">... <img id="check_or_x" src="" alt="" style="vertical-align:middle;" /></div> // In the checkAnswer( ) function: document.getElementById("check_or_x").style.display = "inline"; document.getElementById("check_or_x").src = Answer == numC ? "pathname/check.gif" : "pathname/x.gif"; /* In practice in the demo below, the check.gif and x.gif assignments are in separate if (Answer == numC) and else clauses, although you can certainly go the ?: route if you'd rather do that. */ // In the clearIt( ) function: document.getElementById("check_or_x").style.display = "none";```

Provenance-wise the images are part of the liveforms/ package that supplements WebReference.com's "Bring Your Forms to Life With JavaScript" tutorial, which we previously dissected in Blog Entries #202, #203, #204, #205, #206, #207, and #208. (The www.webreference.com links in these entries are dead; if you are interested in this tutorial, then go to the aforelinked www.webreference.com resource and take it from there.)

Demo

The preceding sections are distilled into the demo below - check the page source for the full coding.

USEFUL FOR THE AGES 3 TO 103

Level A Level B Level C

Difficulty level operand ranges
Level A

add, subtract, and multiply: numA and numB run from 2 to 10
divide: numA runs from 11 to 30, numB runs from 2 to 10
Level B

add and subtract: numA and numB run from 11 to 30
multiply: numA runs from 11 to 30, numB runs from 2 to 10
divide: numA runs from 31 to 60, numB runs from 2 to 10
Level C

add and subtract: numA and numB run from 31 to 60
multiply: numA and numB run from 11 to 30
divide: numA runs from 61 to 100, numB runs from 11 to 30
I trust you are up to the task of 'upping the ante' if my levels are too easy for your taste.

I've left the original `score( )` and `check( )` functions alone. Write the `check( )` function's `alert( )` message, with its running correct and wrong counts, to a `<span id="scoreSpan"></span>` on the page.