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,
Level A
numA and numB range from 0 to 9,
Level B
numA and numB range from 0 to 29, and
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."


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>

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( );

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
(1) when the page has finished loading,
(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 roundDiv div and its Please round your answer... alert string for a division,
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
loads the Do you want your browser to check your answer... confirm string into the checkInputDiv div.

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
writes the ...answer is correct|wrong... alert string to the checkAnswerDiv div.

Clicking the confirmButton1 button calls a cancel2( ) function, which
visualizes the checkAnswerDiv div and its br nextSibling and
loads the Please try again later! alert string into the checkAnswerDiv div.

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'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 links in these entries are dead; if you are interested in this tutorial, then go to the aforelinked resource and take it from there.)


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



Level A Level B Level C

Please round your answer to the nearest integer (round up for x.5-or-higher, round down for x.4-or-lower).

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.

Your assignment
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.

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)