Switchback finder

For information, see Column B.


#! /bin/sh
/bin/cat <<'%%%'
Content-type: text/plain
#! /usr/sbin/perl
# switchback.pl: Program to determine whether a given word is a "switchback."
#
# Version 1.0, copyright 1997 by Jed Hartman.
# Last modification: 10 July 1997.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation, in whole or in part, for any purpose and without fee is
# hereby granted, provided that: (a) the above copyright notice appear in
# all copies; (b) both the copyright notice and this permission notice
# appear in supporting documentation; and (c) no fee is charged for further
# redistribution of the software. This software is provided "as is" without
# express or implied warranty.
#
# Thanks to Jef Poskanzer for the permission-to-use notice.
#
#
# Notes:
#
# Takes a word as input. Creates a list of all strings which consist of reversing
# the given word and changing exactly one letter (to another letter). Then checks
# every string in the created list against a given file containing a list of valid
# words. The result is a list of all words (in the given word file) which can be
# obtained by spelling the original word backward *and* changing exactly one letter.
#
# If you have comments or suggestions, write to me at logos@kith.org. I'm a
# novice perl hacker and would be delighted to receive style comments.
$alphabet = "abcdefghijklmnopqrstuvwxyz";
$wordfilename = "/usr/dict/words";
# Some UNIX systems use "/usr/share/dict/words" instead.
$stop = 0;
while ($stop == 0)
{
  $wordcount = 0;
  @foundwords = ();
  @wordlist = ();
  print "Enter the word to check, or xxx to stop: ";
  $word = <>;
  chop($word);
  if ($word eq "xxx")
  {
    $stop = 1;
    print "\nGoodbye.\n";
    last;
  }
  $rev = reverse($word);
  $rev =~ tr/A-Z/a-z/;
  $wordlength = length($rev);
  for ($cur_let_index = 0; $cur_let_index < $wordlength; $cur_let_index++)
  {
    $cur_let = substr($rev, $cur_let_index, 1);
    for ($i = 0; $i < 26; $i++)
    {
      $new_let = substr($alphabet, $i, 1);
      if ($cur_let eq $new_let)
      {
         next;
      }
      substr($rev, $cur_let_index, 1) = $new_let;
      $wordcount++;
      $wordlist[$wordcount] = $rev;
      substr($rev, $cur_let_index, 1) = $cur_let;
    }
  }
  # Now @wordlist contains a list of 25 * length($word) words, each a reversal-
  # with-one-letter-changed from $word. So go through each line of the dictionary
  # file and compare with each of those words...
  @foundwords = (do lookup(@wordlist));
  foreach $word (@foundwords)
  {
    print "$word\n";
  }
}
# The 'lookup' function takes a list of word candidates and returns a list of
# those candidates which are found in the given word file.
#
# Assumption is that the word-list file contains one word per line, each line
# (including final line) terminated by a return. Words need not be in any
# particular order, though if we assume alphabetical, routine could be smarter.
#
# There's probably a nicer way to do this in Perl, but I didn't see it offhand.
sub lookup
{
  @found = ();
  $foundwordcount = 0;
  @words = @_;  # passed parameter list
  open(WORDFILE, "$wordfilename");
  while ($nextword = ) # get the next line from the word file
  {
    chop ($nextword);
    foreach $to_find (@words) # iterate over all candidate words
    {
      if ($to_find eq $nextword)
      {
        $found[$foundwordcount++] = $nextword;  # add to list of actual words
      }
    }
  }
  close(WORDFILE);
  return @found;
}
%%%