Category: | Miscellaneous |
Author/Contact Info | Thomas Stanley |
Description: | This program will read data from a CSV file and let you select how many questions you wish to have on your test. It will then select random questions for you to answer. This program doesn't yet support multiple length questions(can't have multiple choice and true/false together) The format for a question in the CSV file is as follows: ID|Question|Choice|Choice|Choice|Choice|Answer Where ID is a number relating to the question **NOTE** I will be upgrading this program to include the use of modules, most likely Text::CSV_XS or tilly's Text::xSV module. I also would like to figure out how to include true/false questions as well. **NOTE 2**Version 1.02 is now official. It uses tilly's Text::xSV module to parse the question file, which is pipe delimited. **NOTE 3**Version 1.06 Now can support both true/false and multiple choice questions in the same question file. **NOTE 4**Version 1.08 Now has a text-based menu interface, which means you can chose from a number of tests. I also wrote some POD for it as well |
#!/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 = <STDIN>; 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 = <STDIN>; 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 = $F +ile_Lengths{$Choice}): "; my $MaxQuestions = <STDIN>; 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,$Ma +x); 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(<FH>){ @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=<STDIN>; 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 |
Back to
Code Catacombs