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

My question is about code structure. Below I've printed some of the code that raises my question. I hope my #comments within the code will clarify what I'm doing. But just in case: 1) Ask the question 2) Check whether answer is correct or incorrect 3) Implement variables 4) Check to see if any inccorect answers 5) If "yes" to 4), ask student if s/he wants to see correct answer 6) If yes to 5), use the appropriate $question value to show the correct answer. I'm leaving out a lot of code of course. The full script actually runs! (No one more amazed than moi.) My question is whether my approach to presenting the answers to the questions answered incorrectly is the best approach. Is there another way to do this? Is there a better way to do this? An approach with less code?

#variable initialization @question = qw(1 2 3 4 5); $wrong_count = 0; . . . #sample question print "Question #1: Who is buried in Grant's tomb?\n\n"; print "A. Grant\n"; print "B. Lincoln\n"; print "C. Frank\n"; print "D. None of the above.\n\n\n\n"; print "The answer is: "; . . . #checking for correct answer if (lc ($reply) eq "a") { $answers[0] = "correct"; #creating @answers array } else { #the $incorrect variable doesn't figure into #the code in ques +tion here $answers[0] = "incorrect"; #following line added to gather info as which #answers are +incorrect with @question array $question[0] = "no"; } . . . #incrementing $wrong_count if ($question[0] eq "no") { print "Your answer to question number one is incorrect.\n\n"; $wrong_count++; } if ($question[1] eq "no") { print "Your answer to question number two is incorrect.\n\n"; $wrong_count++; } . . . if ($wrong_count != 0) { print "Would you like to see the correct answers to the questions +you missed?\n\n"; } . . . while ($wrong_count != 0) { if (lc $question[0] eq "no") { clear_the_screen(); print "Question #1: Who is buried in Grant's tomb?\n\n"; print "A. Grant\n"; print "B. Lincoln\n"; print "C. Frank\n"; print "D. None of the above.\n\n\n\n"; print "The answer is: "; print "The answer is: a\n "; ($wrong_count--);

Replies are listed 'Best First'.
Re: Best code approach for this goal
by CountZero (Bishop) on Nov 23, 2009 at 22:59 UTC
    Best is of course not to re-invent the wheel, so have a look at Games::QuizTaker or Quiz::Flashcards.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Best code approach for this goal
by almut (Canon) on Nov 23, 2009 at 22:53 UTC

    Personally, I would put all the questions in a separate text file (or in the __DATA__ section of the Perl file, if you like to keep it in one file). Use a record separator of your choice and set $/ accordingly to read them one by one. This way, you'd have to write the code for presenting the questions, getting the reply, etc. only once (at least for a certain type of question, like multiple choice), instead of literally spelling out dozens of prints and ifs...

    To indicate correct/incorrect choices, you might want to use different capitalisation (e.g. a. ... for incorrect, A. ... for correct), or indentation, that you extract out of the question text, but remove prior to presenting the question. That might make it easier than having/parsing a separate entry per question which indicates what's correct (just a suggestion...)

    Storing the questions in an easily (human-)readable form would also have the added benefit that you can much more easily manage the set of questions in case of additions or updates.

Re: Best code approach for this goal
by GrandFather (Saint) on Nov 23, 2009 at 23:41 UTC

    First off, always use strictures (use strict; use warnings;).

    The major problem is that the questions are embedded in the code. That makes the code incredibly fragile and horrific to maintain. Move your questions out into a data structure, or better still a file (then build the data structure). Consider:

    use strict; use warnings; #variable initialization my @questions = ( {question => "Question #1: Who is buried in Grant's tomb?", answers => [ "Grant", "Lincoln", "Frank", "None of the above.", ], answer => 'a', }, ); my $wrong_count = 0; for my $question (@questions) { printQuestion ($question); print "\nThe answer is: "; $question->{reply} = lc <STDIN>; chomp $question->{reply}; if ($question->{reply} eq $question->{answer}) { print "Correct\n\n"; next; } ++$wrong_count; } print "\n\n"; exit if ! $wrong_count; print "Correct answers:\n\n"; for my $question (@questions) { my $reply = ord ($question->{reply}) - ord ('a'); my $ans = ord ($question->{answer}) - ord ('a'); next if $reply == $ans; printQuestion ($question); print "\nThe answer is: $question->{answers}[$ans]\n"; if ($reply > @{$question->{answers}}) { print "You didn't give a valid answer\n" } else { print "Your answer was: $question->{answers}[$reply]\n"; } print "\n"; } sub printQuestion { my ($question) = @_; my $letter = 'A'; print "$question->{question}\n"; for my $answer (@{$question->{answers}}) { print "$letter: $answer\n"; ++$letter; } }

    True laziness is hard work
      Thank you all. I'm glad I asked the question. You have pointed me in a direction I wouldn't have encountered for a while. But...more homework!