Dec 23 2007

perl: Word Search Generator

Published by at 11:26 am under Programming

Subroutines

Now here’s the 4 subroutines I use in the program.

First is strip_blanks, a very generic bit of code used to take any input string, remove leading and trailing whitespace, and return the modified string.

sub strip_blanks {
  my ($temp) = @_;
  $temp =~ s/\t/ /g;    # Change tabs to blanks
  $temp =~ s/^ *//;     # Trim leading blanks
  $temp =~ s/ *$//;     # Trim trailing blanks
  $temp;
}

Figure 9 – strip_blanks subroutine

Second is shuffle, which randomizes an array. I don’t claim credit for this bit, I found it somewhere online years ago. It is a great example of perl being able to do a lot of stuff in a very little amount of code. To tell you the truth I don’t pay much attention to how it is doing it, because it has never failed me. Give it an array and it returns an array of the same elements but in a different order. Read up on the splice command if you really want to get your mind wrapped around this one.

sub shuffle {
  my @new;
  push @new, splice @_, rand @_, 1 while @_;
  @new;
}

Figure 10 – shuffle subroutine

empty_grid returns a 2D array of a certain size, with all elements set to empty strings. There is probably a better way to do this (the undef command maybe?), but I know this works.

sub empty_grid {
  my ($x, $y) = @_;
  my @my_grid;
  for $i (0..$x) {
    for $j (0..$y) {
      $my_grid[$i][$j]='';
    }
  }   
  @my_grid;
}

Figure 11 – empty_grid subroutine

Finally here is create_page. We use the documented methods from the PDF::Create module to draw lines and letters onto a PDF page. It took a lot of trail and error to get the spacing correct. So, yes there is a lot of stuff hard-coded in this routine and no it can’t be easily reused in another program. Note pdf_offset_x and pdf_offset_y from our configuration file are used here to define the margins, so that can be customized.

This same routine will either create the puzzle page or the solution page. For the puzzle, we output the @words array, plus for any cell that is empty we output a random letter. For the solution, we output the @words array and leave the empty cells blank.

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++;
    }
  }
  
}

Figure 12 – create_page subroutine

Pages: 1 2 3 4 5 6 7

3 responses so far

Please do not load this page directly. Thanks!