reptile7's JavaScript blog

Saturday, May 25, 2019

Approaching Quizmo

Blog Entry #399

Let's move on now to the next Calculators, Calendars, and Clocks sector item, that being Math Check, which went live in October 1997 and comes to us courtesy of Binoculars V.O.F.

Math Check assembles and presents to the user arithmetic problems having difficulty levels A < B < C and whose integer operands are themselves randomly generated;

per its title, it can check the user's answers to these problems against its own answers

and keep a running tally of correct and wrong user answers.

The /JSBook/mathcheck.html page does not feature a Grab the Script link although the Math Check code can be accessed at the corresponding mathcheck.txt page. The mathcheck.html demo works OK for the most part: its division module is somewhat buggy for a reason we will detail below.

**Initial display**

Before we do any arithmetic, we initially see on the mathcheck.html page

some metatext

IMPROVE YOUR ARITHMETIC SKILLS

USEFUL FOR THE AGES 3 TO 103

This page is best viewed with Netscape 3.0

`<h4><center>IMPROVE YOUR ARITHMETIC SKILLS</center></h4>`

<h4><center>USEFUL FOR THE AGES 3 TO 103</center></h4>

<center><h4>This page is best viewed with Netscape 3.0</center></h4>

and an series of push buttons

`<center><form name="rekenen">`

<input type="button" value="add" onclick="add( );">

<input type="button" value="subtract" onclick="subtract( );">

<input type="button" value="multiply" onclick="multiply( );">

<input type="button" value="divide" onclick="divide( );">

and a set of radio buttons

`<input type="radio" name="arithmetic">Level A`

<input type="radio" name="arithmetic" checked>Level B

<input type="radio" name="arithmetic">Level C

and a push button.

`<input type="button" value="Check Score" onclick="check( );">`

We should also see a push button to the right of the button but it doesn't show up because of a coding typo.

`<inputtype="button" value="Reset Score" onclick="score( );">`

__HTML notes__

• As detailed above, the metatext segments are structurally marked up as

`<h4>`

headings. Are those lines headings? They're not headings. Code them as a `<br>`

-newlining `<strong>`

, good enough.• The authors used four separate

`<center>`

s to horizontally center the metatext and the line boxes of the rekenen form (FYI, the h# elements can't validly have block-level children); just one `<center>`

would have sufficed.`<body onload="score( );" bgcolor="#ffffff" text="#000000">`

<center> ...metatext + form code... </center>

</body>

**Our baseline**

A

`score( )`

function sets correct and wrong variables to 0 when the mathcheck.html page has loaded.`function score( ) {`

correct = 0;

wrong = 0; }

**Add it**

It's time to get the math checking under way and put our arithmetic skills to the test, yes? We click the button, thereby calling an

`add( )`

function, which will create and display an addition problem having two operands. The `add( )`

function's first order of business is to set some maxValue upper boundaries for the operands:`function add( ) {`

if (document.rekenen.arithmetic[0].checked) maxValue = 10;

else {

if (document.rekenen.arithmetic[1].checked) maxValue = 30;

else { maxValue = 60; } } ...

For a problem, the operands will be less than 10;

for a problem, they'll be less than 30;

for a problem, they'll be less than 60.

In all three cases, the operand range runs up to but does not reach the maxValue value, per the following code.

The operands themselves are separately generated by external

`random( )`

and `ranom( )`

functions.`numA = random(maxValue);`

numB = ranom(maxValue);

function random(maxValue) {

day = new Date( );

hour = day.getHours( );

min = day.getMinutes( );

sec = day.getSeconds( );

mili = day.getTime( );

return(((hour * 3600) + (min * 60) + (sec) + mili) % maxValue); }

function ranom(maxValue) {

day = new Date( );

mil = day.getTime( );

return((mil) % maxValue); }

Both functions use a

`new Date( )`

-data % maxValue division/remainder operation to give a random (pseudorandom?) number in the range 0 to maxValue - 1, inclusive; regarding these operations,the

`random( )`

dividend is the number of seconds that have elapsed since the beginning of the current day *plus*the

`getTime( )`

number of milliseconds that have elapsed since 1970-01-01T00:00:00.000Z whereasthe

`ranom( )`

dividend is just the `getTime( )`

millisecond count.The % remainders are returned to the

`add( )`

function and respectively assigned to numA and numB variables.(We previously encountered a

`var num = new Date( ).getSeconds( ) % 10`

creation of random numbers in HTML Goodies' JavaScript Primers #20, which was discussed in Blog Entry #36.)Back at the

`add( )`

function,numA and numB are added

and the resulting sum is stored in a numC variable.

`numC = numA + numB;`

Next,

`add( )`

concatenates numA, +, numB, and = and displays the resulting addition problem string on a `prompt( )`

box; the `prompt( )`

's default input value is initially set to 0.`Answer = window.prompt(numA + "+" + numB + " = ", 0);`

The user does or does not enter a value into the box's input field and then clicks the box's or button; the

`prompt( )`

output is assigned to an Answer variable.Is the Answer correct? Up pops an if-conditioned

`confirm( )`

box whose message asksDo you want your browser

to check the answer you gave to the problem numA + numB?

`if (window.confirm("Do you want your browser\n to check the answer you gave to the problem " + numA + " + " + numB))`

ans( );

else { window.alert("Please try again later!"); } } // End of add( ) function

Clicking the box's button displays a Please try again later!

`alert( )`

. Clicking the box's button calls an external `ans( )`

function that compares the Answer and numC values.`function ans( ) {`

if (Answer == numC) {

correct == correct++;

window.alert("Congratulations your answer is correct."); }

else {

wrong == wrong++;

window.alert("The answer " + Answer + " that you gave is wrong. The correct answer = " + numC); } }

If Answer and numC are equal, then the correct count is increased by one and the user gets a Congratulations your answer is correct.

`alert( )`

; if they're not equal, then the wrong count is increased by one and the user gets a The answer Answer that you gave is wrong. The correct answer = numC `alert( )`

.The

`correct == correct++;`

and `wrong == wrong++;`

lines are kind of weird - if I understand the postfix increment operator correctly, they initially compare correct and wrong with themselves (thereby returning true, although nothing is done with those trues) and *then*increment correct and wrong - clearly,

`correct++;`

and `wrong++;`

are all we need here.
We'll get to the rest of the mathcheck.html JavaScript in the following entry.

Thursday, May 09, 2019

The Whole of a Circle

Blog Entry #398

We continue today our discussion of the Java/JavaScript Goodies Circle Calculator. Having taken stock of the calculator's HTML structure and metafunctionality in the previous post, we are ready to do some actual calculating - let's get to it, shall we?

**Area, diameter, circumference**

Suppose the user changes the area field's 0 value to 10. Subsequently blurring the field calls a

`circle( )`

function and passes thereto a this.form reference to the field's containing form and a this.name reference to the field's name, which are respectively assigned to form and changed variables.`function circle(form, changed) { /* circle( ) function body */ }`

...

<input type="text" name="area" value="0" onchange="circle(this.form, this.name);">

I trust y'all know that for a circle

A = π × r² and C = π × d

where A, r, C, and d are the circle's area, radius, circumference, and diameter, respectively.

(I previously used this image here in Blog Entry #361 and originally got it from this USF page.)

Spikeman put all of the

`circle( )`

value-getting and -setting code in a`with (Math) { ... }`

carrier so he could use the JavaScript PI property and

`sqrt( )`

method without a calling `Math.`

object reference. (Although Mozilla's current with statement page details a number of problems with with, Netscape raised no with red flags back in the day.)The with block begins by reading the area, diameter, and circumfrence fields' values and assigning them respectively to area, diameter, and circumfrence variables.

`var area = form.area.value;`

var diameter = form.diameter.value;

var circumfrence = form.circumfrence.value;

(Is it necessary to scoop up all three values? Two of them are 0, after all. A basic

`var area, diameter, circumfrence;`

declaration would suffice if we were to pass this itself to

`circle( )`

and give it, say, an inputObject identifier and then use an inputObject.value expression in place of area, diameter, and circumfrence in the calculations below.)Moving on, the above area/diameter/circumfrence assignments are followed by an if statement that tests if the area field has been changed and if so maps the area to the corresponding diameter and circumfrence via the formulae given earlier.

`if (changed == "area") {`

var radius = sqrt(area / PI);

diameter = 2 * radius;

circumfrence = PI * diameter; }

Changes to the diameter and circumfrence fields are processed by analogous conditionals.

`if (changed == "diameter") {`

area = PI * (diameter / 2) * (diameter / 2);

circumfrence = PI * diameter; }

if (changed == "circumfrence") {

diameter = circumfrence / PI;

area = PI * (diameter / 2) * (diameter / 2); }

That's it for the math. The area, diameter, and circumfrence are lastly loaded into their designated form fields.

`form.area.value = area;`

form.diameter.value = diameter;

form.circumfrence.value = circumfrence; } /* End of with block */ } /* End of circle( ) function */

As regards the area = 10 input

the final outputs are:

Area: | |

Diameter: | |

Circumfrence: |

__In the name of completeness__

Immediately after the

`circle( )`

function are`var toDegrees = 360 / (Math.PI * 2);`

var toRadians = (Math.PI * 2) / 360;

statements of which no use is made: throw them out.

**Demo + notes**

We're just about ready to wrap this guy up, and as is our custom, we do so by addressing the age-old question: "

*How might we improve things?*"

I noted early on that the calculator's onchange action rubs me the wrong way.

Relatedly, the use of the area, diameter, and circumfrence fields for both inputting and outputting data strikes me as poor design.

I gave some thought to what I would like the calculator to be and here's what I came up with:

**Circle Math**

C = π × d

A = π × r²

The user initially interacts with a set of three radio buttons vis-à-vis a somewhat-confusing 'menu' of text boxes.

Clicking a radio button

`<label><input type="radio" name="termName" value="Diameter:" onclick="chooseTerm(this.form, this.value);" /> Diameter</label>`

calls a

`chooseTerm( )`

function thatwrites a corresponding label to the rows[1].cells[0] cell and

sends focus to a name="input3" text box in the rows[1].cells[1] cell.

`var inputLabels = circleTable.getElementsByTagName("label");`

function chooseTerm(form, inputLabel) {

inputLabels[3].textContent = inputLabel;

form.input3.focus( ); }

The user enters a value into the input3 field

and then clicks a button

`<button type="button" onclick="getValues(this.form, this.form.input3.value);">Calculate the Remaining Terms</button>`

thereby calling a

`getValues( )`

function that outputs labels and values for the remaining circle parts in the rows[3] and rows[4] rows.`function getValues(form, inputValue) {`

if (inputLabels[3].textContent == "Diameter:") {

inputLabels[4].textContent = "Circumference:";

inputLabels[5].textContent = "Area:";

form.input4.value = Math.PI * inputValue;

form.input5.value = Math.PI * Math.pow(inputValue / 2, 2); } ... }

The inputValue is validated: the empty string and other non-numeric strings

`else if (isNaN(inputValue)) { /* The isNaN( ) function was implemented for "all platforms" in JavaScript 1.1. */`

window.alert("Your input must be a bona fide number."); form.input3.value = ""; form.input3.focus( ); }

and non-positive numbers are all flagged and turned away by tests that Spikeman could have made use of.

The form.input4.value and form.input5.value are truncated/rounded at the thousandths place.

`form.input4.value = Number(form.input4.value).toFixed(3);`

form.input5.value = Number(form.input5.value).toFixed(3);

(Spikeman didn't have access to the

`toFixed( )`

method but he could've easily accomplished the same via some decimal-point shifting and `Math.round( )`

ing, e.g.:`form.area.value = Math.round(area * 1000) / 1000;`

)Check the page source for the full coding. BTW, most but not all of the stylings

`for (var i = 3; i < inputLabels.length; i++) inputLabels[i].style.color = "silver";`

are effected JavaScriptically.

Math Check is up next.

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