Jump to content

Php random math test with form entry


Go to solution Solved by mac_gyver,

Recommended Posts

Hello everyone. I hope you're having a great day!


I'm attempting to make a basic math test that gives one question, a input field to enter an answer, and if its correct then it shows the answer and an image to say they win. If in correct then still shows the answer with an image that says they didn't win.

Sounds pretty basic right? I can't wrap my head around what I'm doing wrong. When I run this, then weather it's right or wrong, I just get a blank page. I've been at this for so long with different variations that I'm starting to feel fatigue haha. Any help is greatly appreciated.

The file is math8.php

PS
I also get the follow errors which is confusing me because in my mind, these ARE defined. But I can see that the errors say their not. I'm not understanding why though.

Warning: Undefined array key "number_entered" in math8.php on line 32

Warning: Undefined array key "submit" in math8.php on line 34

<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

$rand1 = rand(0, 9);
$rand2 = rand(0, 9);
$operator = array('*', '/', '+', '-');
$randoperator = $operator[rand(0, 3)];
switch ($randoperator) {
    case "+":
        $finaalvalue = $rand1 + $rand2;
        break;
    case "-":
        $finaalvalue = $rand1 - $rand2;
        break;
    case "*":
        $finaalvalue = $rand1 * $rand2;
        break;
    case "/":
        $finaalvalue = $rand1 / $rand2;
        break;

echo $rand1 . $randoperator . $rand2 . '=' . $finaalvalue;

}
;


if(!isset($_POST['number_entered'])){

$number= $_POST['number_entered'];

$submitbutton= $_POST['submit'];


echo '
<form  id="id" action="" method="POST">
<br><b>Level 1<br>Do The Math</b><br><br>';

echo $rand1 . $randoperator . $rand2 . '=';

echo '<input type="text" name="number_entered" value="" autocomplete="off"> <br><br>';

echo '
<input class="button" type="submit" name="submit" value="Enter Guess"><br><br>
</form>
';




if ($submitbutton){

if ($number != $finaalvalue){

echo "Incorrect guess<br>The correct<br>number was <b>$finaalvalue</b>
<br><img src='sorry-tryagain.png'><br>";

}else{

echo "<img src='you-win.png'><br><b>$finaalvalue</b> IS THE<br>CORRECT GUESS!</b><br>";
}
}
}

?>

 

Edited by PNewCode
Link to comment
https://forums.phpfreaks.com/topic/318470-php-random-math-test-with-form-entry/
Share on other sites

web servers are stateless. they don't know or care what has happened outside of the current request.

each time your code runs, it generates new random values. if you want to remember these values, from one request to the next, you need to store them in session variables, and only generate new ones if the session variables are empty/not-set.

@mac_gyver and @Barand thank you for that info! I appreciate it. I think I understand what you're saying. But then again not really haha. 
If I'm understanding you, then it's not really working to post anything but is just recycling the page to make a new math problem? But then, it's not?
Just translating in my own mind that is less skilled with less termonology haha.

Okay so, is what I'm attempting to accomplish even possible then to do all in one page? The only session that I have with it is the users session (different php script that is going to be included once I get this working so I can add some database scores and etc etc)

I hope I'm not stepping out of bounds on this, but is there a way I can just pay someone to make this work? If I'm out of line then I appologize. Another 5 hours have passed and I can't make heads or tails out of how to make this work.
I don't need to save the answer in a database or anything like that. It's just going to be as basic as can be.
A random math question shows, the user enters the answer, then it shows if it's right or wrong without showing a new math question.
I feel foolish I can't find a single thing online to where I can learn what to do here. And I'm sure you both are correct in what you're saying. Unfortunately, I don't understand what you're saying :(

  • Solution

are you doing this as a learning exercise? what is your goal?

some pointers -

  1. the code for any page should be laid out in this general order - 1) initialization, 2) post method form processing, 3) get method business logic - get/produce data needed to display the page, 4) html document.
  2. the post method form processing should not attempt to detect if the submit button is set, there are cases where it won't be. instead, detect if a post method form was submitted before referencing any of the form data.
  3. keep all the form data as a set, in a php array variable, then operate on elements in this array variable throughout the rest of the code.
  4. trim all the input data before validating it, mainly so that you can detect if all white-space characters were entered.
  5. validate all the trimmed input data at once, storing user/validation errors in an array, using the field name as the main array index.
  6. after the end of the validation logic, if there are no errors (the array holding the user/validation errors is empty), use the input data. since all you are doing is comparing an input value with the correct answer, you can do this as part of the validation logic. if you were storing data in a database, authenticating a user, sending an email, ... you would put the code needed to perform these actions here.
  7. after using the input data, if there are no errors, perform a redirect to the exact same URL of the current page to cause a get request for the page. this will prevent the browser from trying to resubmit the form data should the page get reloaded or browsed back to.
  8. to display a one-time success message, store it in a session variable, then test, display, and clear that session variable at the appropriate location in the html document.
  9. if there are user/validation errors, the code will continue on to display the html document, display any errors, redisplay the form, populating the field values with any existing data, so that the user doesn't need to keep reentering values over and over.
  10. any dynamic value you output in a html context needs to have htmlentities() applied to it to help prevent cross site scripting.

there's a programming issue with the division operator and computers. this operation can result in a fractional part that cannot be represented exactly in a computer and then cannot be easily compared. you may want to test the answer produced is this case and limit the question/answer to those which only have whole integer answers, i.e. keep something like 9/3, but not 7/6, and also don't allow division by 0.

if you do all of that, except for handling the division cases, you would end up with code that looks like this -

<?php

// initialization

// the error related settings should be in the php.ini on your system
error_reporting(E_ALL);
ini_set('display_errors', '1');

session_start();

$post = []; // array to hold a trimmed working copy of the form data
$errors = []; // array to hold user/validation errors

// post method form processing
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
	// inputs: number_entered, $_SESSION['answer']
	// trim all the post data at once
	$post = array_map('trim',$_POST); // if any input is a array, use a recursive trim call-back function here instead of php's trim
	
	// validate inputs
	if($post['number_entered'] === '')
	{
		$errors['number_entered'] = 'You must enter a number';
	}
    // note: this assumes that only integer answers are permitted (in the case of the division operator)
	else if((int)$post['number_entered'] !== (int)$_SESSION['answer'])
	{
		$errors['number_entered'] = "Incorrect guess<br>The correct<br>number was <b>{$_SESSION['answer']}</b>
		<br><img src='sorry-tryagain.png'><br>";
		// since you are displaying the correct answer, you would want to generated a new question in this case?
		//unset($_SESSION['question']);
	}
	
	// if no errors, success
	if(empty($errors))
	{
		$_SESSION['success_message'] = 	"<img src='you-win.png'><br><b>{$_SESSION['answer']}</b> IS THE<br>CORRECT GUESS!</b><br>";
		// to continue, you would generated a new question
		//unset($_SESSION['question']);

		// redirect to the exact same url of the current page to cause a get request - PRG Post, Redirect, Get.
		die(header("Refresh:0"));
	}
}

// get method business logic - get/produce data needed to display the page

// if there's no question/answer, generate one
if(!isset($_SESSION['question']))
{
	$rand1 = rand(0, 9);
	$rand2 = rand(0, 9);
	$operator = array('*', '/', '+', '-');
	$randoperator = $operator[rand(0, 3)];
	switch ($randoperator)
	{
		case "+":
		$finaalvalue = $rand1 + $rand2;
		break;
		case "-":
		$finaalvalue = $rand1 - $rand2;
		break;
		case "*":
		$finaalvalue = $rand1 * $rand2;
		break;
		case "/":
		// note: this can produce a fractional number, which you must take care with when performing comparisons.
		// also division by zero.
		$finaalvalue = $rand1 / $rand2;
		break;
	}

	$_SESSION['question'] = "$rand1 $randoperator $rand2 = ";
	$_SESSION['answer'] = $finaalvalue;
}

// html document - this is an incomplete document. it only shows the necessary parts for the demonstration.
?>

<?php
// display any success message
if(isset($_SESSION['success_message']))
{
	echo $_SESSION['success_message'];
	unset($_SESSION['success_message']);
}
?>

<?php
// display any errors
if(!empty($errors))
{
	echo "<p>".implode('<br>',$errors)."</p>";
}
?>

<?php
// display the form
if(!empty($_SESSION['question']))
{ ?>
<form method="POST">
<br><b>Level 1<br>Do The Math</b><br><br>

<?=$_SESSION['question']?>

<input type="text" name="number_entered" value="<?=htmlentities($post['number_entered']??'',ENT_QUOTES)?>" autocomplete="off"><br><br>
<input class="button" type="submit" value="Enter Guess"><br><br>
</form>
<?php
}

 

Edited by mac_gyver

@mac_gyver
To answer your question, the goal was for learning and also give my viewers a simple math question that will go along with a bunch of other trivia. Just for fun. And yes also to learn from.
I'm told by most people that I know that my mind works weird. I tend to reverse engineer things to learn most. I'll take a web page and see it as a viewer to see what it does, then look at the script to see how it works, then learn and build from there. Most of the time it works for me, but then other times it doesn't. Unfortunately I have a learning handicap to where if I was to be given instructions on how to build a clock (like a literal one that is on the wall) I would be lost. But if I took a clock apart, then I can see how it's done and build another one. And then often enough I can build more to add to that clock from there. I know... I'm strange.

That being said, what you posted is VERY educational to me! I simply pasted your code that you provided into a page and then uploaded it. I saw it working. Then I went back to go line by line from what you said before providing the code and learned from it while going through that code. And now it all MOSTLY makes sense to me. I confess that not all of it does but I know it will soon, as some of it is just termonology that I'm unfamiliar with. HOWEVER, it has some terms that I didn't understand 2 or 3 months ago, but now do because of this website. Overall, I understand a lot more of why it works as apposed to what I had created to begin with.

Sorry this is a long post but I wanted to properly thank you by explaining exactly how it educated me. I am very greatful for that! THANK YOU!

@mac_gyver I resolved the division zero issue by changing the lines rand(0, 9) to rand(1, 9)

If you don't mind an extenstion on it, is there a way to not show the question and answer form after the answer is given? Right now, it shows the answer again under the CORRECT or INCORRECT display, after the answer is given.

As well as chaging the rand() ranges to 1-9 I would also change the way rand1 and rand2 are used in the case of division.

allocate rand1 to the finalvalue and then multiply rand1 by rand2. This avoids none integer results. IE..

rand1 * rand2
-------------   =   rand1
    rand2

My code for this bit would be

$rand1 = rand(1, 9);
$rand2 = rand(1, 9);
$randoperator = rand(0, 3);

$operators = array('&times;', '&divide;', '&plus;', '&minus;');

$finalvalue = match($randoperator) {
                    0 => $rand1 * $rand2,
                    1 => handleDivide($rand1, $rand2),
                    2 => $rand1 + $rand2,
                    3 => $rand1 - $rand2
                };

$question = "$rand1 {$operators[$randoperator]} $rand2 =";

echo "$question $finalvalue<br>";


function handleDivide(&$r1, $r2)
{
    $fv = $r1;
    $r1 *= $r2;
    return $fv;
}

 

@Barand Thank you I will try to put that in with what @mac_gyver gave too. I've been studying this a lot over the last couple days and I'm starting to understand how it all works. I'm still stuck on how to keep a new question from showing (or the current question) below the results (after the user answers it).

I unset it all to get it to do a new one in case of refresh so that works but even before I did that then it would still show that question again below the results. The problem with that is that it will allow the user to answer again if they get it wrong. If they get it wrong then there's no redo, I don't want them to have the ability to put in a new answer to move forward.

Like this?

image.png.cc2eee06897a8bac78bf501c2cf0f5aa.png    image.png.8ae00d0f455154caf0397358e5c945ac.png

Code

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST')  {
    ##
    ##  Process posted data
    ##
    $number = $_POST['number_entered'] ?? 0;
    $answer = $_POST['answer'] ?? 0;
    $question = $_POST['question'] ?? '';
    $check = $number == $answer ? "<span class='w3-badge w3-green w3-xlarge'>&check;</span>" :
                                   "<span class='w3-badge w3-red w3-xlarge'>&times;</span>";
    $output = <<<OUT
        <span class="qtext">$question $number</span>
        $check
        <br><br>
        <a href='' class='w3-button w3-indigo'>Ask me another</a>
OUT;
}
else  {
    ##
    ## Ask new question
    ##
    $rand1 = rand(1, 9);
    $rand2 = rand(1, 9);
    $randoperator = rand(0, 3);

    $operators = array('&times;', '&divide;', '&plus;', '&minus;');

    $finalvalue = match($randoperator) {
                        0 => $rand1 * $rand2,
                        1 => handleDivide($rand1, $rand2),
                        2 => $rand1 + $rand2,
                        3 => $rand1 - $rand2
                    };

    $question = "$rand1 {$operators[$randoperator]} $rand2 =";

    $output = <<<OUT
        <form method='POST'>
            <span class="qtext">$question</span>
            <input type='hidden' name='question' value='$question'>
            <input type='hidden' name='answer' value='$finalvalue'>
            <input type='number' name='number_entered' placeholder='?' autofocus>
            <br><br>
            <button class='w3-button w3-indigo'>Submit answer</button>
        </form>
OUT;
    
}

    


function handleDivide(&$r1, $r2)
{
    $fv = $r1;
    $r1 *= $r2;
    return $fv;
}


?>
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8">
   <title>Example</title>
   <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> 
   <style type='text/css'>
       div {
           padding: 16px;
           text-align: center;
       }
       input {
           width: 70px;
           text-align: center;
           font-size: 20pt;
       }
       .qtext {
           font-size: 20pt;
       }
   </style>
</head>
<body>
<div class='w3-blue-gray'>
    <h1>Do the Math</h1>
</div>
<div>
    <?= $output ?>
</div>
</body>
</html>

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.