JavaScript beginner - another blocking point

I joined few days ago this forum. I am trying to learn JavaScript and, as a “real case” exercise, I chose a simple MathGame I coded in VBA a while ago and I try to “translate” it in JavaScript.

Now I bumped into a new obstacle and I request your kind advice. I describe the issue:

- Desired behavior: Two random numbers are generated (integers, between 0-10, sum < 11) and their the addition is displayed. The player has to input the result in a textbox and press ENTER. The result has to be evaluated by the script (if it is the correct addition result) … and for the moment let’s stop here.
- What I achieved: The two numbers are generated and displayed, the textbox is displayed and make the refresh for each new addition.
[COLOR=“#FF0000”]- Where I got stuck: I failed to pass the user input (addition result) for evaluation.[/COLOR]

I read tens of pages of information but I still cannot figure the proper method (or maybe correct syntax) for using the value input by user.

For complete info, here is the code up to this moment:

<!DOCTYPE html>
<html>
<body>
<p id=“calc”></p>
<button onclick=“Add()”>CLICK HERE for a new addition</button>
<script>
function Add()
{
var y = Math.floor((Math.random()*11)+0)
var x = Math.floor((Math.random()*11)+0)
while ((x+y)>10)
{
var y = Math.floor((Math.random()*11)+0)
var x = Math.floor((Math.random()*11)+0)
}
var display = document.getElementById(“calc”)
display.innerHTML = x + " + " + y + " = <input type=‘text’ name=‘result’ id=‘result’ size=‘4’ autofocus>"
}
</script>
</body>
</html>]

I thank you in advance for any suggestion you might have.

Of course that for regular JS users the problem should be elementary. But please keep in mind I am totally new to JS and i am striving for better results.

What you’re looking for is either evaluation or parsing.

Here’s a simple parse, where we assume the user entered the right sequence:


var sumString = "1+2+3+4",
    sumArray = sumString.split("+"),
    sum = 0;
    
for (var i = 0; i < sumArray.length; i++) {
    sum = sum + sumArray[i]*1;
};

console.log(sum);


It get’s gradually complicated as the user input diversifies.

Why does this seem more like a homework assignment than anything else? I’m a bit rusty in my javascripting, but I figured it out in about five minutes, but I think your problem is more with your logic flow than anything.

Since it’s always better to try and figure out things on your own, here are some hints for you…

  1. Your basic page logic is flawed. You’re generating the form on the button click, which is not what you want. Your basic logic flow should be -> When the page is loaded, the number should be generated (and saved in memory), and the input box (which shouldn’t require scripting to create) available for the user to enter the value. The button click should then compare the entered number with the randomly generated value. Knowing this, how would you accomplish these two separate pieces of functionality?
  2. FYI - your randomizer is pulling in numbers from 0-11, not 0-10.
  3. Your loop logic is inefficient in recalculating BOTH numbers every time - how can you improve that logic?

I feel this is not what I am looking for. Maybe I expressed something wrong. I will try again:

  • The addition is generated by the script and displayed (x + y = )
  • After “=” sign I placed a textbox where the user (small child) inputs his guess about the addition result and press ENTER.

[COLOR=“#FF0000”]And here comes my obstacle:

  • I don’t succeed to transfer user input (the number in the textbox) to the script for validation as a correct result of the addition.[/COLOR]

I’m fiddling around with all kind of solutions, but nothing works. Is very possible that I made also syntax mistakes. That’s why i needed a small hint to put me on the right track.

I will try to clarify few of your doubts:

  • I don’t know why it seems like a homework. This was your assumption, so only you can clarify it. I’ve done the initial VBA script as a game for my child (when he was 7 yo). It was a huge support for fast-learning elementary math. Now I’m trying to learn JS, and I used the same script idea as a project in JS.
  • Is not necessary that all of us should have a brilliant mind. Maybe I am a less intelligent and for sure I am infinite less experimented in programming than you and most members of this forum. But I have no problem in asking support on a public platform dedicated to this scope.
  • (1) How do I generate then a new pair of random numbers to add, if not by a button? Reloading the page???
  • (2) You have my script. Try it! If you get any 11 value, you deserve a prize :slight_smile:
  • (3) For the moment I lack very basic JS skills, maybe is a little too early to dream about optimizing the script?. You can optimize something ONLY when you understand what you’ve done (wrong). This is not my case. For the moment at least :slight_smile:

In any case I thank you for the time you invested in reading my post and for the useful advice.

The function is very inefficient - and it does give eleven possible values - between 0 and 10.

function Add()  {
 var y = Math.floor((Math.random()*11)+0)
 var x = Math.floor((Math.random()*11)+0)
 while ((x+y)>10)  {
 var y = Math.floor((Math.random()*11)+0)
 var x = Math.floor((Math.random()*11)+0)
 }

If the sum of the two random numbers is supposed to be less than 11 then you can do it as:

function Add()  {
 var y = Math.floor((Math.random()*11)+0)
 var x = Math.floor((Math.random()*(11-y))+0)

You could also leave off the +0 as that doesn’t actually do anything useful given that the smallest value is going to be zero if you don’t add anything.

Sorry for the assumption, but this REALLY looks like a homework assignment, but if you say it’s not, then I’ll believe you. Part of the problem is you’re trying to treat a client side concept like a server side concept - won’t work. vbScript (asp classic) CREATES the generated HTML markup. Javascript works AGAINST the generated markup. In other words, one is before the markup, one is after.

To be honest, I missed that part of your assignment, but all your code does is display the initial problem - it doesn’t allow for anyway to check the answer (or save the answer for that matter)

True, as your loop weeds those out - I’m just pointing out a basic flaw - why check that something is over a threshold if the inputs can be invalid in the first place? How many times will either x or y in your example have 11 as the value in them? With that small of a random window to work from, pretty often.

It has nothing to do with code optimization - it’s basic logic and design patterns, which if you can get locked down, will allow you to transition from one language to another. Languages are only syntax - the logic and thought processes are essentially the same.

To show I’m accepting your answer to #1, I’ll show my quick and dirty script. It does exactly what your requirements ask for. I tried to comment it where I thought woud be helpful and appropriate.

Some caveats:

  • The scripting isn’t necessarily “best practice” - the onload and onclick methods aren’t the always the best methods to handle these pieces of functionality - it just works quick and dirty.
  • I’d probably also set the math.floor into a function as well to allow you to change that 1-10 value just once. Not a big deal, just a comment… - felgalls approach above is even better (and makes more sense). Changed to match that thought process…

<!DOCTYPE html>
<html>
<body onload="setValues()">
	<p><span id="x">&nbsp;</span> + <span id="y">&nsbp;</span> = </p>
	<input type="text" id="myValue" name="myValue" />
	<button onclick="CheckAnswer()">Try it</button>
	<p id="answer">&nbsp;</p>
	<script>
		var totalValue = 99;		// to create a "global" value which is saved to memory....
		
		// Create the problem to be resolved.....
		function setValues() {
		   totalValue = 99;  // to reset the counter.....
		   var x = Math.floor((Math.random()*10));		// see the *10?  Only generates a random number between 1-10, not 11.
		   var y = Math.floor((Math.random()*(11 - x)));
		   totalValue = x + y;
		   
		   // display the values to be added together...
		   document.getElementById("x").innerHTML = x;
		   document.getElementById("y").innerHTML = y;
		}


		// check the answer added by the user
		function CheckAnswer() {
			var myValue = document.getElementById("myValue");			// get the value entered by the user...
			if (myValue.value == totalValue) {
				// show that the user is correct, and get a new problem to solve.....
				document.getElementById("answer").innerHTML = "Correct";
				setValues();
			} else {
				// show that the user is incorrect and allow them to enter a new value....
				 document.getElementById("answer").innerHTML = "Incorrect";
			}
		}
	</script>
</body>
</html>

I prefer to write it like this in my first scripts because it helps me to memorize faster the general formula.

Thank you for the kind and detailed suggestions. They helped me very much in understanding the issues. I could write the correct code.

For the time being this topic will become dormant :slight_smile: I will wake it up again when I will encounter the next blocking point.

That code will NEVER return 11.

Math.random produces a number >= 0 and < 1 (note it can never return exactly 1)
Math.floor rounds down to the nearest integer

So Math.floor(Math.random()*11) will produce the following eleven values with each occurring approximately 1/11th of the time - 0,1,2,3,4,5,6,7,8,9,10

Note that 11 does not appear in the list of possible results as .9999999999… times 11 (no matter how many extra 9s you add to the end of the first number) rounded down is never going to be greater than 10.

As expected, I ask again for your kind guidance.

I progressed quit well with my exercise-game in JavaScript, but the new blocking point for me is:

  • I have 2 groups of 3 checkboxes each. To each checkbox belongs a function which should be available when the checkbox get a true value (is checked).

I want to implement the following functionality:

  • If the user checks one or more checkboxes, from the respective group of selected functions one will be called randomly.

And I cannot figure a way to make available the group of functions depending on what boxes the user checked each time.

I will give a practical example:

  • We have chechboxes: a1, a2, a3; b1, b2, b3 and the respective functions.
  • User checks a1, a3, b2. One of these functions is called randomly.
  • User checks a2, a3, b1, b3. One of these functions is again called randomly.
  • … and so on…

Thank you again for your assistance.

Well, seems this forum is very motivating for me :slight_smile: Again, it was sufficient to post my problem and I found the solution myself in a few hours.

My solution, just for info:

  • It’s not necessary to create the group of selected functions, … etc.
  • Simply generate the random number and validate it against the checked boxes.
  • If no match, generate a new number (WHILE). If match then, problem solved.

I am aware that my solution is probably the most inappropriate considering the JavaScript Best Practices. But still, I succeeded to discover it myself after only one week of studying JavaScript.

Thank you again for your “positive influence” :slight_smile:

Practically the exercise-game is completed now. Still, I’d like to bring some nice improvements to it. And to get the chance to gain more experience in JavaScript.

The first action of the user on site is actually to select (between radio buttons) what operation wants to practice - addition, subtraction, multiplication or division (remember the users are elementary school children).

I want to find a way of remembering, for each user, the selection he made at the last visit. To avoid re-selection of the same radio button if they come repeatedly during the day for a new session.

The first thought I had was to do it with cookies. I have zero experience with cookies, so I ask you to validate my “strategy”:

  • At browser (or page) closing the script collects the state of the buttons with getElementById
  • Creates the respective cookie(s)
  • At beginning of a new session gets from cookie(s) the previous value of the radio buttons
  • Changes the value of the radio buttons accordingly, also using getElementById

Of course instead of asking I could simply test the script. But my problem is that after only 2 weeks of JavaScript I am still “at the will” of some tiny inherent syntax mistakes, therefore I will not know if it’s one of my mistakes or the script idea is wrong.

I thank you again for your advice.

Hi there,

You will need to use some kind of persistent storage and cookies seem like a good choice.

This will not work. There is no reliable “onPageClose” event to hook into that works across browsers.
You will need to hook into the onChange event of the radio button and update the cookie every time the user selects something different.

This all sounds entirely reasonable.

Not at all. We’re happy to help and it is nice to see someone who is asking for advice on how to solve a problem, as opposed to asking for the solution.

Actually I was thinking to onunload event. It has the same unreliable behavior?

Depending on how quickly the page unloads you might get that to run one or possibly two statements before the script unloads to the point where the next statement no longer is there to run.

If trying to write a cookie the data to be written would almost certainly be unloaded before the save of the cookie was able to run.

Also the onunload event is not supported properly in Chrome or Opera.

I accomplished some good (I think) functionality:

  • The cookie is created each time a radio button is clicked
  • When reloading the page the cookie is retrieved and identified correctly

Where I failed:

  • I could not put in place the simple action of checking the respective radio button after reading the cookie.

Again I rely on your valuable input to get an idea on how should I do this.

The script so far (feel free to criticize it, this is a good help for me to correct my mistakes :slight_smile: ):

<!DOCTYPE html>
<html>
<head>
<script>
var OptCalc
function setCookie()
{
     var cname = "OptCalc"
     for (var i = 0; i < 3; i++)
     {
          if (OptCalc == i)
          {
               var cvalue = i
          }
     }
     var d = new Date();
     d.setTime(d.getTime() + (30 * 24 * 60 * 60 * 1000));
     var expires = "expires=" + d.toGMTString();
     document.cookie = cname + "=" + cvalue + "; " + expires;
}
function getCookie()
{
     var cname = "OptCalc"
     var name = cname + "=";
     var ca = document.cookie.split(';');
     for(var i=0; i<ca.length; i++)
     {
          var c = ca[i].trim();
          document.getElementById("cval").innerHTML=c.substring(name.length,c.length) // I used this workaround to visualize if the cookie is identified at [B][I]onload[/I][/B]
          if (c.indexOf(name)==0) return c.substring(name.length,c.length);
     }
     return "";
}



</script>
</head>

<body onload="getCookie()">

<form name="F0" id="F0" onsubmit="return false">
	<INPUT TYPE="Radio" Name="OpType" Value="Add10" id="r0" onclick="OptCalc=0, setCookie()">
	<INPUT TYPE="Radio" Name="OpType" Value="Add20p" id="r1" onclick="OptCalc=1, setCookie()">
	<INPUT TYPE="Radio" Name="OpType" Value="Add20" id="r2" onclick="OptCalc=2, setCookie()">
</FORM>

<p id="cval"></p>

<SCRIPT>



</SCRIPT>

</body>
</html>

Mission accomplished :slight_smile:

The code:

<!DOCTYPE html>
<html>
<head>
<script>

var OptCalc

function setCookie()
{
     var cname = "OptCalc"
     for (var i = 0; i < 3; i++)
     {
          if (OptCalc == i)
          {
               var cvalue = i
          }
     }
     var d = new Date();
     d.setTime(d.getTime() + (30 * 24 * 60 * 60 * 1000));
     var expires = "expires=" + d.toGMTString();
     document.cookie = cname + "=" + cvalue + "; " + expires;
}

 function getCookie()
{
     var cname = "OptCalc"
     var name = cname + "=";
     var ca = document.cookie.split(';');
     for(var i=0; i<ca.length; i++)
     {
          var c = ca[i].trim();
          document.getElementById("cval").innerHTML=c.substring(name.length,c.length) // used this workaround to visualise if the cookie is identified at onload
                   if (c.indexOf(name)==0) return c.substring(name.length,c.length);
     }
     return "";
}

function checkCookie()
{
var x=getCookie();
document.getElementById(x).checked=true
}

</script>
</head>

<body onload="checkCookie()">

<form name="F0" id="F0" onsubmit="return false">
	<INPUT TYPE="Radio" Name="OpType" Value="Add10" id="0" onclick="OptCalc=0, setCookie()">
	<INPUT TYPE="Radio" Name="OpType" Value="Add20p" id="1" onclick="OptCalc=1, setCookie()">
	<INPUT TYPE="Radio" Name="OpType" Value="Add20" id="2" onclick="OptCalc=2, setCookie()">
</FORM>

<p id="cval"></p>

<SCRIPT>



</SCRIPT>

</body>
</html>

Still your observations are welcome. The code does what I wanted, but I am pretty sure it is ugly, breaks some important JS good practices, it’s awkward … anyway I am glad I did not give up :slight_smile:

Now I have the ambition to adapt this solution to other form elements, to have a complete “personal” add-on for restoring forms.

Hi,

Well done on achieving your goal!

You asked for our feedback:

One thing that could easily be improved is the use of inline event handlers (e.g. onclick=“…”).
It makes for cleaner code and better maintainability to use unobtrusive event listeners.

Here’s a quick guide: http://coding.smashingmagazine.com/2013/11/12/an-introduction-to-dom-events/