http://www.perlmonks.org?node_id=168771
Category: Miscellaneous
Author/Contact Info /msg cjf
Description: Simple command line quiz using Chemistry::Elements. Provides you with either the element name, symbol, or atomic number and asks you for the other two. All suggestions (especially those dealing with the 3 repetitive subs) are greatly appreciated.
#!/usr/bin/perl -w

use strict;

use Chemistry::Elements qw/get_name get_Z get_symbol/;

my $test_type = shift || "";

my %tests = (
    name   => \&name_test,
    number => \&number_test,
    symbol => \&symbol_test,  );

if (exists $tests{$test_type}) {
    $tests{$test_type}->();
} else {
    error("Invalid Test type. Choose 'name', 'number', or 'symbol'.");
}

sub name_test {

    while (1) {

        my $number = int(rand 109) + 1;
        my $symbol = get_symbol($number);
        my $name   = get_name($number);

        print "Element name = $name\n";
        print "Enter symbol: ";

        chomp (my $ans_symbol = <STDIN>);

        if (lc($ans_symbol) eq lc($symbol)) {
            print "Correct. $symbol is the atomic symbol for $name\n";
        } else {
            print "Incorrect. $symbol is the atomic symbol for $name\n
+";
        }

        print "Enter $name\'s atomic number: ";

        chomp (my $ans_number = <STDIN>);

        if ($ans_number eq $number) {
            print "Correct. The atomic number for $name is $number\n";
        } else {
            print "Incorrect. The atomic number for $name is $number\n
+";
        }

        print "\n";
    }

}

sub number_test {

    while (1) {

        my $number = int(rand 109) + 1;
        my $symbol = get_symbol($number);
        my $name   = get_name($number);

        print "Atomic number = $number\n";
        print "Enter symbol: ";

        chomp (my $ans_symbol = <STDIN>);

        if (lc($ans_symbol) eq lc($symbol)) {
            print "Correct. $symbol has the atomic number $number\n";
        } else {
            print "Incorrect. $symbol has the atomic number $number\n"
+;
        }

        print "Which element has the atomic number $number: ";

        chomp (my $ans_name = <STDIN>);

        if (lc($ans_name) eq lc($name)) {
            print "Correct. $number is the atomic number for $name\n";
        } else {
            print "Incorrect. $number is the atomic number for $name\n
+";
        }

        print "\n";
    }

}

sub symbol_test {

    while (1) {

        my $number = int(rand 109) + 1;
        my $symbol = get_symbol($number);
        my $name   = get_name($number);

        print "Element symbol = $symbol\n";
        print "Enter Name: ";

        chomp (my $ans_name = <STDIN>);

        if (lc($ans_name) eq lc($name)) {
            print "Correct. $symbol is the symbol for $name\n";
        } else {
            print "Incorrect. $symbol is the symbol for $name\n";
        }

        print "Enter $symbol\'s atomic number: ";

        chomp (my $ans_number = <STDIN>);

        if ($ans_number eq $number) {
            print "Correct. $symbol\'s atomic number is $number\n";
        } else {
            print "Incorrect. $symbol\'s atomic number is $number\n";
        }

        print "\n";
    }

}


sub error {
    my $error = shift;
    print "Error: $error\n";
    exit;
}
Replies are listed 'Best First'.
Re: Chemistry Elements Quiz
by mrbbking (Hermit) on May 24, 2002 at 13:37 UTC
    I like Chemistry.

    In my experience, the best way to get rid of repetitive almost-the-same things, like the loops you have, is usually found in a hash. Here's my suggestion. I'm also interested in any comments or suggestions.

    Changes:

    • Added more graceful way to exit.
    • Made the tests case-sensitive (because element symbols are case-sensitive. May be too strict, then, for element names, but maybe not. Depends on your teacher.. :-)
    • Removed three loops, replacing them with one.
    #!/usr/bin/perl -w use strict; use Chemistry::Elements qw/get_name get_Z get_symbol/; my $test_type = shift || ''; print "ChemTest. Testing your knowledge of the Periodic Table.\n"; print "Test by name, number or symbol\n"; die "\n\tUsage: $0 [name|number|symbol]\n\n" if $test_type !~ /name|number|symbol/; print "Testing by $test_type\n"; print "Enter 'quit' at any prompt to quit.\n"; while(1){ my $number = int(rand 109) + 1; my $name = &get_name($number); my $symbol = &get_symbol($number); my %element = ( 'number' => $number, 'name' => $name, 'symbol' => $symbol ); my $given = $element{$test_type}; print "\nElement $test_type is $given\n"; delete $element{$test_type}; foreach my $answer(keys %element ){ print "Enter the $answer: "; chomp (my $guess = <STDIN>); die "Thanks for playing\n" if $guess eq "quit"; if ($guess eq $element{$answer}) { print "Correct. "; } else { print "Incorrect. "; } print "$element{$answer} is the $answer for $given\n"; } }

      Exactly what I was looking for. Thanks :)

      C:\>perl chemquiz.pl
      Can't locate Chemistry/Elements.pm in @INC (@INC contains: C:/Perl/lib C:/Perl/site/lib .) at chemquiz.pl line 5.
      BEGIN failed--compilation aborted at chemquiz.pl line 5.

      C:\>