#!/usr/bin/perl -w ############################################### ## Name: QuizTaker ## ## Version: 1.08 ## ## Author: Thomas Stanley ## ############################################### use strict; use File::Slurp; use Text::Wrap; my $A=0; my $Choice; while($A == 0){ system('clear'); print"\n"; print"\t\t ******************************* \n"; print"\t\t *** QuizTaker.pl *** \n"; print"\t\t *** Version 1.08 *** \n"; print"\t\t *** by Thomas Stanley *** \n"; print"\t\t ******************************* \n"; print"\n"x4; print"\t\t\t\t1) Take a test\n"; print"\t\t\t\t2) Exit\n"; print"\n\n"; print"\t\t\t\tYour choice: "; $Choice = ; chomp($Choice); my $B = 0; while($B == 0){ if($Choice == 1){ &Choose(); $B=1; }elsif($Choice == 2){ print"\n\n\t\t\t\tThanks for playing!\n"; $A = 1; } $B = 1; } } ############################## sub Choose{ system('clear'); my %File_Lengths=(); my %NumberOfTests=(); my $Choice; my $MaxQuestions; my $Length; my $File; my $C; my $D = 1; my $H = 0; my $I = 0; my $refFile_lengths = GetFileLengths(\%File_Lengths); foreach $C(keys %File_Lengths){ $C=~s/\.\w{3}//; $NumberOfTests{$D} = $C; $D++; } print"\n"; foreach $C(keys %NumberOfTests){ print"\t\t\t$C) $NumberOfTests{$C}\n"; } while($H == 0){ print"\n\t\t\tEnter the test number: "; my $number = ; chomp $number; $Choice = "$NumberOfTests{$number}.psv"; if(exists $NumberOfTests{$number}){ while($I == 0){ print"\n\t\tHow many questions do you wish to answer (Max = $File_Lengths{$Choice}): "; my $MaxQuestions = ; chomp $MaxQuestions; if(($MaxQuestions<1)||($MaxQuestions>$File_Lengths{$Choice})){ print"\n\n\t\tPlease re-enter the number of questions."; sleep(2); }else{ $Length = $File_Lengths{$Choice}; &Randomize($Choice,$Length,$MaxQuestions); $I = 1; } } }else{ print"\n\t\tPlease choose again!!\n\n"; sleep(2); } $H = 1; } return; } ################################## sub GetFileLengths{ my $File_Lengths = shift; my $Directory = "./Questions"; my $File; my @Files = read_dir($Directory); my $Check; my $path; foreach $File(@Files){ if($File=~/\.psv/){ $path = $Directory."/".$File; $Check = Check($path); if($Check<1){}else{ $$File_Lengths{$File} = $Check; } } } my $number = keys %$File_Lengths; if($number == 0){ die"No files available\n"; } return $File_Lengths; } ############################# sub Check{ my $file=shift; my $lines; if(-e $file){ $lines =`wc -l < $file`; }else{ die"Can't find $file!\n"; } return $lines; } ############################# sub Randomize{ my $File = shift; my $FileLength = shift; my $Max = shift; my $Directory = "./Questions"; my %Randoms = (); my %Data=(); my %TestQuestions=(); my %TestAnswers=(); srand(); my $Path = $Directory."/".$File; my $ref=Loader(\%Data,$Path); for(1..$Max){ my $question_number = int(rand($FileLength)+1); redo if exists ($Randoms{$question_number}); $Randoms{$question_number} = 1; } my @Randoms = keys %Randoms; my $ref2=shuffle(\@Randoms); for(my $a=0;$a<$Max;$a++){ $TestAnswers{$Randoms[$a]} = pop@{$Data{$Randoms[$a]}}; $TestQuestions{$Randoms[$a]} = $Data{$Randoms[$a]}; } my %QuestionLength = (); my $b; foreach my $key (keys %TestQuestions){ $b = @{$TestQuestions{$key}}; $QuestionLength{$key} = $b; } &Tester(\%TestQuestions,\%TestAnswers,\@Randoms,\%QuestionLength,$Max); return; } ###################### sub Loader{ my $Data=shift; my $file=shift; my $question_number; my $length; my $f; my @Sorter=(); open(FH,"$file")||die"Can't open $file: $!\n"; while(){ @Sorter=split /\|/; $question_number=shift @Sorter; $length=@Sorter; for($f=0;$f<$length;$f++){ $$Data{$question_number}[$f]=$Sorter[$f]; } } close FH; return $Data; } ########################## sub Tester{ my $Questions=shift; my $Answers=shift; my $Randoms=shift; my $question_length=shift; my $Max=shift; my $length; my $question_number=1; my $question_answer=""; my $answer; my $number_correct=0; my $key; my $g; system('clear'); print"\n"; while($question_number<=$Max){ $key=shift @$Randoms; $length=$$question_length{$key}; print"Question Number $question_number\n"; for($g=0;$g<$length;$g++){ print wrap("","","$$Questions{$key}[$g]\n"); } print"\nYour answer: "; $answer=; chomp $answer; $answer=uc $answer; $question_answer=$$Answers{$key}; chomp $question_answer; $question_answer = uc $question_answer; if($answer eq $question_answer){ print"That is correct!!\n\n"; $question_number+=1; $number_correct+=1; }else{ print"That is incorrect!\n"; print"The correct answer is $question_answer.\n\n"; $question_number+=1; } } &Final_Score($number_correct, $Max); return; } ########################### sub Final_Score{ my $Correct=shift; my $Max=shift; my $Percentage=($Correct/$Max)*100; print"You answered $Correct out of $Max correctly.\n"; printf"For a final score of %.2f%%\n",$Percentage; sleep(4); return; } # # Fisher-Yates Shuffle # sub shuffle { my $array = shift; my $i; for ($i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i]; } } __END__; =pod =head1 QuizTaker.pl Version 1.08 This program will allow you to take simple tests, based upon a file of questions and answers that you create. A sample file of questions have been included with this distribution, so you can see how its done. The values are stored within the file, with the pipe character "|" as a separator. Please ensure that you have an extension of .psv on the end of your question/answer files. To run this program, type the following at the command prompt in the directory where you have installed QuizTaker: ./QuizTaker.pl This program also requires the File::Slurp module which can be found on your nearest CPAN mirror. =head2 Improvements =over 4 =item 1 Now includes this section of POD =item 2 Now uses the Text::Wrap module found in the core distribution of Perl, to wrap the lines of long questions =item 3 Now has a menu based interface, and allows you to choose which test you would like to take. =item 4 Cleaned up some syntax within the functions to make them look better =item 5 Fixed a bug where if the letter in the answer file is in lowercase, it would break in the Test subroutine. =item 6 Implemented the Fisher-Yates shuffling algorithm to provide for a more random sequence in the array of questions =back =head2 To Do List =over 4 =item 1 Make a graphical user interface using the Tk module =back =head2 Questions/Comments If you have any questions or comments about this program please email me at Thomas_J_Stanley@msn.com . I am always striving to make this program better. =cut