#============================================================================== # ws.pl - generate a word search puzzle # # usage: perl ws.pl # by: steve browning # version: 1.0 #============================================================================== use PDF::Create; # get the config filename from the command line $config_filename=shift; # if the config file is not readable, print a message and quit if(! -r $config_filename) { print 'cannot read config file' . "\n"; print 'usage: ws.pl [config.txt]' . "\n"; exit; } # parse the config file open(CONFIGFILE, "<$config_filename"); while() { chomp; $line=strip_blanks($_); if($line=~m/^\#/ || $line=~m/^$/) { } elsif ($line=~m/^(.*)\=(.*)$/) { $$1=$2; } else { push(@words, $line); } } close(CONFIGFILE); # a little input checking if($size_x>22 || $size_y>22) { print 'error: size_x or size_y cannot exceed 22' . "\n"; exit; } if(eval($#words+1)>30) { print 'error: maximum of 30 words allowed on list' . "\n"; exit; } # define hashes for the increments to use for the 8 directions $inc_x{'E'}=1; $inc_y{'E'}=0; $inc_x{'S'}=0; $inc_y{'S'}=1; $inc_x{'W'}=-1; $inc_y{'W'}=0; $inc_x{'N'}=0; $inc_y{'N'}=-1; $inc_x{'NE'}=1; $inc_y{'NE'}=-1; $inc_x{'SE'}=1; $inc_y{'SE'}=1; $inc_x{'SW'}=-1; $inc_y{'SW'}=1; $inc_x{'NW'}=-1; $inc_y{'NW'}=-1; # initialize a grid full of empty cells @grid = empty_grid($size_x-1, $size_y-1); # loop thru all the words in the list randomly for $this_word (shuffle(@words)) { $placed=0; $tries=0; while ($placed == 0 && $tries < $max_attempts) { $x=int(rand $size_x); $y=int(rand $size_y); if ($grid[$x][$y] == '' || $grid[$x][$y] == substr($this_word,0,1)) { for $direction (shuffle(split(',',$directions))) { @temp_grid = empty_grid($size_x-1, $size_y-1); foreach ($position=0;$position($size_x-1) || $curr_y<0 || $curr_y>($size_y-1)) { last; # outside the bounds of the grid } # first chance, is the target cell empty? if ($grid[$curr_x][$curr_y] eq '') { $temp_grid[$curr_x][$curr_y]=$this_char; } else { # second chance - does the target cell contain the letter in question? if ($grid[$curr_x][$curr_y] eq $this_char) { $temp_grid[$curr_x][$curr_y]=$this_char; } else { last; # failed second chance also } } # if we reached the end of the word, transfer it to the real grid if($position == length($this_word)-1) { for $i (0..$size_x-1) { for $j (0..$size_y-1) { if($temp_grid[$i][$j] eq '') { } else { $grid[$i][$j]=$temp_grid[$i][$j]; } } } $placed=1; $placedword{$this_word}='Y'; } } if ($placed == 1 ) { last; # the word was placed, no need to check other directions } } } $tries++; } } print 'placed ' . scalar(keys %placedword) . ' out of ' . eval($#words+1) . ' words' . "\n"; # create the output pdf file $pdf = new PDF::Create('filename' => $pdf_filename, 'Version' => 1.2, 'PageMode' => 'UseNone', 'Author' => $author, 'Title' => $title); $root = $pdf->new_page('MediaBox' => [ 0, 0, 612, 792 ]); $f1 = $pdf->font('Subtype'=>'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica-Bold'); $f2 = $pdf->font('Subtype'=>'Type1', 'Encoding' => 'WinAnsiEncoding', 'BaseFont' => 'Helvetica'); # output two pages, one without solution and one with create_page('N'); create_page('Y'); $pdf->close; exit; sub strip_blanks { my ($temp) = @_; $temp =~ s/\t/ /g; # Change tabs to blanks $temp =~ s/^ *//; # Trim leading blanks $temp =~ s/ *$//; # Trim trailing blanks $temp; } sub shuffle { my @new; push @new, splice @_, rand @_, 1 while @_; @new; } sub empty_grid { my ($x, $y) = @_; my @my_grid; for $i (0..$x) { for $j (0..$y) { $my_grid[$i][$j]=''; } } @my_grid; } sub create_page { my ( $show_solution ) = @_; # make a page in the PDF file my $page = $root->new_page; my $xpos, $ypos; # draw title $xpos=$pdf_offset_x+100; $ypos=$pdf_offset_y+40; if($show_solution eq 'N') { $page->stringc($f1, 16, $xpos, $ypos, $title); } else { $page->stringc($f1, 16, $xpos, $ypos, $title . ' - Solution'); } # draw grid for $j (0..$size_y) { for $i (0..$size_x) { $xpos=$pdf_offset_x+($i*20); $ypos=$pdf_offset_y-($j*20); $page->line($xpos-10,$pdf_offset_y+15,$xpos-10,$pdf_offset_y-($size_y*20)+15); } $page->line($pdf_offset_x-10,$ypos+15,$pdf_offset_x+($size_x*20)-10,$ypos+15); } # draw puzzle for $j (0..$size_y-1) { for $i (0..$size_x-1) { $xpos=$pdf_offset_x+($i*20); $ypos=$pdf_offset_y-($j*20); if($grid[$i][$j] eq '') { if($show_solution eq 'N') { $this_letter=uc(chr(int(rand 26)+65)); } else { $this_letter=''; } $page->stringc($f1, 14, $xpos, $ypos, $this_letter); } else { $this_letter=uc($grid[$i][$j]); $page->stringc($f1, 14, $xpos, $ypos, $this_letter); } } } # draw wordlist $cnt=0; for $col (0..2) { $ypos=$pdf_offset_y-($size_y*20)-50; for $row (0..9) { if($cnt<=$#words) { if(exists $placedword{$words[$cnt]}) { $page->stringc($f2, 12, $pdf_offset_x+($col*190), $ypos, uc($words[$cnt])); $ypos-=15; } } $cnt++; } } }