hchana has asked for the wisdom of the Perl Monks concerning the following question:

Hi, How do I adjust the code below so it re-iterates a question that was answered incorrectly.? Presently, if you get a question wrong, a new question is generated. Help

#!/usr/bin/perl use strict; use warnings; use diagnostics; use feature 'say'; use feature "switch"; my $input = 0; my $play_again = 0; srand; while () { my $random_integer1=int(rand(100)); #generate a random integer fro +m 0 to 99 my $random_integer2=int(rand(100)); #generate a random integer fro +m 0 to 99 if ($random_integer1 > $random_integer2){ print "What is $random_integer1 - $random_integer2 = "; $input = <STDIN>; if ($input == $random_integer1 - $random_integer2){ print "Well done.! you are corect.\n\n"; }else{ print "Sorry you're wrong, have another go.\n\n"; } }else{ print "What is $random_integer1 + $random_integer2 = "; $input = <STDIN>; if ($input == $random_integer1 + $random_integer2){ print "Well done.! you are corect.\n\n"; }else{ print "Sorry you're wrong, have another go.\n\n"; } } }

Replies are listed 'Best First'.
Re: Repeat question
by haukex (Archbishop) on Nov 30, 2018 at 13:34 UTC

    One pattern you can apply for that kind of thing is:

    my $answer = 42; while (1) { print "What is the answer? "; chomp( my $input = <STDIN> ); if ( $input == $answer ) { print "Good!\n"; last; # break out of innermost loop } else { print "Please try again.\n"; } }
Re: Repeat question (redo)
by LanX (Saint) on Nov 30, 2018 at 13:39 UTC
    TIMTOWTDI:

    (as a variation of Haukex' answer, which is more straight forward )

    >perl my $answer = 42; { print "What is the answer? "; chomp( my $input = <STDIN> ); if ( $input == $answer ) { print "Good!\n"; } else { print "Please try again.\n"; redo; } } __END__ What is the answer? 1 Please try again. What is the answer? 2 Please try again. What is the answer? 42 Good!

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      this seems to be more of a guessing game, where the number is pre-defined. I wish to generate 2 random integers and create a sum e.g. '23-16=' whereby the larger integer is identified and placed on the left hand side. Only when the user inputs the right answer will a new sum be generated with two new integers. From my original code, a new sum is generated even if you get the answer wrong, how do I get the code to repeat the question answered incorrectly.? Do I need to store the random integers in variables or something.?

        You would put one of the constructs suggested by haukex or LanX inside the while from your original code, around your if/else block.

        (Also, rather than having that if/else block, and repeating two almost-identical pieces of code: after generating the two random numbers, I would suggest using this to swap them, so the first is always bigger than the second:

        if($random_integer1 < $random_integer2) { my $tmp = $random_integer2; $random_integer2 = $random_integer1; $random_integer1 = $tmp; }
        That way, you only need one piece of code for asking and checking the answer, rather than two nearly-identical pieces. There are more perlish ways of doing the swap, but I chose to make it easy for you to understand.)

        Do I need to store the random integers in variables or something.?

        Yes, but you are already doing that. Here's one approach with a subroutine and using an array to hold the operands.

        #!/usr/bin/env perl use strict; use warnings; while (1) { my @operands = (int(rand(100)), int(rand(100))); ask ($operands[0] > $operands[1], @operands); } sub ask { my ($subtract, @args) = @_; my $input; my $answer = $subtract ? $args[0] - $args[1] : $args[0] + $args[1] +; my $oper = $subtract ? '-' : '+'; until (defined $input && $input == $answer) { print "Nope, try again\n" if defined $input; print "What is $args[0] $oper $args[1] ? "; chomp( $input = <STDIN> ); }; print "Success!\n"; }

        Edit: sigil fix on the ask() call.

Re: Repeat question
by davido (Cardinal) on Nov 30, 2018 at 17:09 UTC

    IO::Prompt::Hooked based solution:

    while (1) { my @random_int = sort {$b <=> $a} map {int(rand(100))} 0..1; my $correct = 0; last if !defined prompt( message => "What is $random_int[0] - $random_int[1]? ('q' +to exit) ", validate => sub { my $raw = shift; return 0 unless looks_like_number($raw); return $correct = $raw == $random_int[0] - $random_int[1]; }, error => sub { my $raw = shift; return looks_like_number($raw) ? "Sorry, you are wrong. Have another go.\n" : "You need to enter a number.\n"; }, escape => qr/^q$/i, ); print "Well done! You are correct!\n\n" if $correct; }

    It's not a great solution, but it's pretty easy to work with.

    It might be worth explaining: The call to prompt only happens one time per random number, and the validation hook will cause prompt to re-query automatically until the validation hook passes.


    Dave

Re: Repeat question
by tybalt89 (Monsignor) on Nov 30, 2018 at 15:45 UTC
    #!/usr/bin/perl # https://perlmonks.org/?node_id=1226526 use strict; use warnings; while(1) { my $input; my $random_integer1 = int rand 100; my $random_integer2 = int rand 100; do { print "What is $random_integer1 - $random_integer2 = "; chomp( $input = <STDIN> ); } while $input != $random_integer1 - $random_integer2 and print "Sorry you're wrong, have another go.\n\n"; print "Well done.! you are correct.\n\n"; }
Re: Repeat question
by BillKSmith (Monsignor) on Dec 01, 2018 at 15:16 UTC
    The module IO::Prompt::Hooked verifies the answer and reprompts if wrong. It also provides a convenient way for the user to exit the program.
    $type hchana.pl use strict; use warnings; use IO::Prompt::Hooked; srand(999); # Delete for production my $correct_ans; my %opt = ( escape => qr/q(uit)?/i, # Type 'quit' to exit program error => "Sorry you're wrong, have another go.\n\n", validate => sub { $_[0] !~ /\D/ and $_[0] == $correct_ans}, ); while (1) { my $random_integer1=int(rand(100)); my $random_integer2=int(rand(100)); my $sign = ($random_integer1 > $random_integer2) ? '-' : '+'; $correct_ans = $random_integer1 + (($sign eq '+') ? $random_integer2 : -$random_integer2); my $msg = "What is $random_integer1 $sign $random_integer2?"; my $ans = prompt( message => $msg, %opt ); last if !defined $ans; print "Well done.! $ans is correct.\n\n"; } warn "Program terminated by user\n"; $perl hchana.pl What is 10 + 63? 73 Well done.! 73 is correct. What is 80 + 92? too hard Sorry you're wrong, have another go. What is 80 + 92? 22 Sorry you're wrong, have another go. What is 80 + 92? 172 Well done.! 172 is correct. What is 77 - 53? 44 Sorry you're wrong, have another go. What is 77 - 53? 24 Well done.! 24 is correct. What is 59 - 41? quit Program terminated by user $

    UPDATE: Started this yesterday. Did not notice that Dave had posted a similar solution while I was sleeping. Note that this version does handle sign the same as the OP.

    Bill

      Even though I posted an answer that uses the same module I upvoted this node because it was nice to see that same module used in a slightly different way. (Plus I was pleased to see that someone besides me is aware of the module's existence.)

      In a future version of the module I intend for validation failures to stash additional information that error can retrieve from its parameter list so that error doesn't need to try to figure out all over again why validate failed. ...so something of a try/catch notion.


      Dave