Main Menu  | 
         
        
            | 
	
            
 | 
         
        
            | 
         
       
        
           
            Forums  | 
           
           
            |  
             | 
           
           
              | 
           
         
        
        
           
            Programming 
                Contest  | 
           
           
            |   | 
           
           
              | 
           
         
        
        
           
            Documentation 
                | 
           
           
            |   | 
           
           
              | 
           
         
        
        
           
            Partner 
                Sites   | 
           
           
             
 
 | 
           
           
              | 
           
         
        
        
           
            Sponsors  | 
           
           
            | 
				 | 
           
           
              | 
           
         
       
       
     | 
    
        
          
 
Code of larry 
<html>
   <head>
     <title>PHP-Editors Contest B3 - Jumbled Words - June 2003</title>
   </head>
 
   <body>
 <?php
   /* | PHP-Editors Contest - June 2003
    * | Contest B3 (Jumbled Words)
    * +---------------------------------------------------------------------------+
    * | Title           : Contest B3 - Jumbled Words
    * | Filename        : contest_b3.php
    * | Author          : Larry J. Rutledge (larry@ixoyedesign.com)
    * | Created         : June 3, 2003
    * | Last Modified   : June 5, 2003
    * +---------------------------------------------------------------------------+
    * | Description     : Find supplied word(s) in a sentence. The word(s) you
    * |                 : find will be intact, but the sentences will be
    * |                 : muddled-up and may have many unused letters. There are
    * |                 : two blank letters available, per list, which can be used
    * |                 : to complete words. Blanks can be any letter, but they
    * |                 : cannot be the same, for example:
    * |                 : Blank 1 = g, Blank 2 = h (valid)
    * |                 : Blank 1 = f, Blank 2 = f (invalid)
    * |                 :
    * |                 : Input
    * |                 : 1. The input contains pairs of lists and sentences.
    * |                 : 2. The list gives the words to search for in the
    * |                 :    following sentence.
    * |                 : 3. Lists are terminated by a comma.
    * |                 : 4. All letters are in lower case.
    * |                 : 5. Words are at most 20 letters long and are separated
    * |                 :    by a single space.
    * |                 : 6. Each line is at most 80 characters long.
    * |                 : 7. Sentences may occupy more than one line, and are
    * |                 :    terminated by a full stop.
    * |                 : 8. The input will be given in a text file named
    * |                 :    "lists.txt" and will be stored in the same directory.
    * |                 :
    * |                 : Output
    * |                 : 1. For each pair of list and sentence, find the words
    * |                 :    from the list that appear in the sentence with the
    * |                 :    letters shuffled.
    * |                 : 2. Print these words in order of highest character
    * |                 :    count, separated by a single space.
    * |                 : 3. Highlight (in red) any letters used from your blanks,
    * |                 :    all other letters should be black.
    * |                 : 4. If no words from the list match the words in the
    * |                 :    sentence, just print a blank line.
    * |                 : 5. On the last line print the total number of letters
    * |                 :    found (including any blanks used).
    * |                 :
    * |                 : EACH LETTER CAN ONLY BE USED ONCE!!
    * |                 :
    * |                 : Sample Input
    * |                 :
    * |                 : string constant variable sausages,
    * |                 : tstnacon bleiangrav igtni ksiypappsle.
    * |                 : class function objects hypertext preprocessor,
    * |                 : sslas nyyoitcf teztxrpyhre krtbhwopqowo
    * |                 : jksksjajajahshshj.
    * |                 :
    * |                 : Sample Output
    * |                 :
    * |                 : constant variable string
    * |                 :                     -
    * |                 : hypertext objects class
    * |                 :              --
    * |                 : 43
    * |                 :
    * +---------------------------------------------------------------------------+
    * | Restrictions    : 1. Must run on Windows and Unix systems.
    * |                 : 2. Must run with PHP 4.2 (register_globals OFF)
    * |                 : 3. No third part PHP extensions (other than ones
    * |                 :    supplied with PHP 4.2 on PHP.NET)
    * |                 : 4. Maximum execution time - 60 seconds
    * +---------------------------------------------------------------------------+
    * | Instructions    : Put a "lists.txt" file in the same directory as this
    * |                 : script. The file should consist of pairs of lines. The
    * |                 : first line should be a list of words separated by spaces
    * |                 : and terminated by a comma (,). The second line should be
    * |                 : a list of letters terminated by a period (.).
    * +---------------------------------------------------------------------------+
    * | Important Note  : No notes for this project
    * |
    * | History         : Version  Date        Author   Description
    * |                   -------  ----------  ------   --------------------------
    * |                    1.0.0   07/03/2003   LJR     Initial Development
    * |                    1.0.1   07/05/2003   LJR     Added weighting to improve
    * |                                                 results.
    * |
    * +---------------------------------------------------------------------------+
    * | Proposed
    * | Revisions       : 1. No proposed revisions at this time.
    * +---------------------------------------------------------------------------+
    */
 
    // Constant Declarations
    // ---------------------
 
    // Names used for user-defined sorting routines
    DEFINE("__USER_SORT_DIFFERENCE__",  "usort_diff");
    DEFINE("__USER_SORT_WEIGHTS__",     "usort_weight");
    DEFINE("__USER_SORT_REV_WEIGHTS__", "usort_rev_weight");
    DEFINE("__USER_SORT_REV_LENGTH__",  "usort_rev_len");
 
    // Delimiter characters - used to separate out lines from source.
    DEFINE("__WORD_DELIM__",   ',');
    DEFINE("__LETTER_DELIM__", '.');
 
    // Index Positions for Statistics array
    DEFINE("__STATS_NEED__", 0);
    DEFINE("__STATS_HAVE__", 1);
    DEFINE("__STATS_DIFF__", 2);
 
    // Index Positions for Weight Array
    DEFINE("__WEIGHT_COUNT__", 0);
    DEFINE("__WEIGHT_TOTAL__", 1);
    DEFINE("__WEIGHT_PCT__",   2);
 
    // Index Positions identifying each "blank" in blank array
    DEFINE("__BLANK__ONE__", 0);
    DEFINE("__BLANK__TWO__", 1);
 
    // Index Positions for sub-array in "blank" array
    DEFINE("__BLANK_CHAR__", 0);
    DEFINE("__BLANK_WORD__", 1);
    DEFINE("__BLANK_POS__",  2);
 
    new Searcher;
 
    /**   Function: usort_diff
     *    ----------------------------------------------------------------------
     *    Purpose     : This method sorts a "statistic" array based on the
     *                : difference between what is needed and what is
     *                : available - for example, if the word list needs five (5)
     *                : of the letter 'a', but the letter list only has two (2),
     *                : then the value to be sorted on would be (-3).
     *                :
     *    Arguments   : a - First of two values to be compared
     *                : b - Second of two values to be compared
     *                :
     *    Assignments : None
     *                :
     *    Returns     : Returns an integer less than, equal to, or greater then
     *                : zero if the first argument ($a) is considered to be
     *                : respectively less than, equal to, or greater than the
     *                : second ($b)
     *                :
     *    Assumptions : None
     *                :
     *    Constraints : None
     */
    function usort_diff($a, $b) {
      if ($a[__STATS_DIFF__] == $b[__STATS_DIFF__]) return 0;
      return ($a[__STATS_DIFF__] < $b[__STATS_DIFF__]) ? -1 : 1;
    }
 
    /**   Function: usort_weight
     *    ----------------------------------------------------------------------
     *    Purpose     : This method sorts a "weight" array based on the
     *                : weighting applied to the words in the original word
     *                : list. This weight is a number identifying how many of
     *                : its characters are potentialy unavailable in the letter
     *                : list. If the weights are equal, the the percentage is
     *                : used, which is calculated by the ratio of the weight to
     *                : the total number of characters in the word.
     *                :
     *    Arguments   : a - First of two values to be compared
     *                : b - Second of two values to be compared
     *                :
     *    Assignments : None
     *                :
     *    Returns     : Returns an integer less than, equal to, or greater than
     *                : zero if the first argument ($a) is considered to be
     *                : respectively less than, equal to, or greater than the
     *                : second ($b)
     *                :
     *    Assumptions : None
     *                :
     *    Constraints : None
     */
    function usort_weight($a, $b) {
      if ($a[__WEIGHT_COUNT__] == $b[__WEIGHT_COUNT__]) {
        if ($a[__WEIGHT_PCT__] == $b[__WEIGHT_PCT__]) {
          if ($a[__WEIGHT_TOTAL__] == $b[__WEIGHT_TOTAL__]) return 0;
          return ($a[__WEIGHT_TOTAL__] < $b[__WEIGHT_TOTAL__]) ? -1 : 1;
        }
        return ($a[__WEIGHT_PCT__] < $b[__WEIGHT_PCT__]) ? -1 : 1;
      }
      return ($a[__WEIGHT_COUNT__] < $b[__WEIGHT_COUNT__]) ? -1 : 1;
    }
 
    /**   Function: usort_rev_weight
     *    ----------------------------------------------------------------------
     *    Purpose     : This method is the same as "usort_weight", except it
     *                : reverses the sort order.
     *                :
     *    Arguments   : a - First of two values to be compared
     *                  b - Second of two values to be compared
     *                :
     *    Assignments : None
     *                :
     *    Returns     : Returns an integer greater than, equal to, or less than
     *                  zero if the first argument ($a) is considered to be
     *                  respectively less than, equal to, or greater than the
     *                  second ($b)
     *                :
     *    Assumptions : None
     *                :
     *    Constraints : None
     */
    function usort_rev_weight($a, $b) {
      if ($a[__WEIGHT_COUNT__] == $b[__WEIGHT_COUNT__0]) {
        if ($a[__WEIGHT_PCT__] == $b[__WEIGHT_PCT__]) {
          if ($a[__WEIGHT_TOTAL__] == $b[__WEIGHT_TOTAL__]) return 0;
          return ($a[__WEIGHT_TOTAL__] < $b[__WEIGHT_TOTAL__]) ? 1 : -1;
        }
        return ($a[__WEIGHT_PCT__] < $b[__WEIGHT_PCT__]) ? 1 : -1;
      }
      return ($a[__WEIGHT_COUNT__] < $b[__WEIGHT_COUNT__]) ? 1 : -1;
    }
 
    /**   Function: usort_rev_len
     *    ----------------------------------------------------------------------
     *    Purpose     : This method sorts an array of strings from longest to
     *                  shortest. This is included to satisfy the requirement
     *                  that the final word list appear in this order.
     *                :
     *    Arguments   : a - First of two values to be compared
     *                  b - Second of two values to be compared
     *                :
     *    Assignments : None
     *                :
     *    Returns     : Returns an integer greater than, equal to, or less than
     *                  zero if the first argument ($a) is considered to be
     *                  respectively less than, equal to, or greater than the
     *                  second ($b)
     *                :
     *    Assumptions : None
     *                :
     *    Constraints : None
     */
    function usort_rev_len($a, $b) {
      if (strlen($a) == strlen($b)) {
        if ($a == $b) return 0;
        return ($a < $b) ? 1 : -1;
      }
      return (strlen($a) < strlen($b)) ? 1 : -1;
    }
 
    /**   Class: Searcher
     *    ----------------------------------------------------------------------
     *    Purpose     : This class is the main class for the word search script.
     *                : The constructor triggers the process and the conclusion
     *                : of the constructor code is also the conclusion of the
     *                : script.
     *                :
     *    Assumptions : None
     *                :
     *    Constraints : None
     */
    class Searcher {
      // Private Members - (should only be directly access by the class)
 
      // Name of file to be processed
      var $_filename    = "lists.txt";
 
 
      // Arrays used by the script
      var $_words       = array(); // Contains the list of words from the file
      var $_letters     = array(); // Contains the list of letters from the file
      var $_stats       = array(); // Contains statistics calculated during the
                                   // script processing
      var $_weights     = array(); // Contains weightings for words, calculated
                                   // during the script processing
 
      var $_foundWords  = array(); // Contains the words found that satisfy the
                                   // word search criteria
 
      var $_blanks      = array(); // Contains information about the "blanks"
                                   // used during processing of a word list.
                                   // Identifies the blank used, the letter it
                                   // was used in, and the position in the word.
 
      var $_currPos     = 0;       // Indicates the position in the file (used
                                   // cases where the file contains more than
                                   // one set of lines.
 
      var $_letterCount = 0;       // Maintains the count of letters added to
                                   // "$_foundWords" array. Used for reporting.
 
      /**   Accessor: getFilename
       *    ----------------------------------------------------------------------
       *    Purpose     : Used to treat the "private" member as a property
       *                :
       *    Arguments   : None
       *                :
       *    Assignments : None
       *                :
       *    Returns     : Contents of private member "_filename"
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function getFilename() {
        return $this->_filename;
      }
 
      /**   Mutator: setFilename
       *    ----------------------------------------------------------------------
       *    Purpose     : Used to treat the "private" member as a property
       *                :
       *    Arguments   : _value - contains value to assign to property.
       *                :
       *    Assignments : Sets contents of private member "_filename"
       *                :
       *    Returns     : None
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function setFilename($_value) {
        if ($this->_filename != $_value) {
          $this->_filename = $_value;
        }
      }
 
      /**   Function: _countLetters
       *    ----------------------------------------------------------------------
       *    Purpose     : Counts the number of lowercase characters in a string.
       *                : Only counts the letters 'a' through 'z', no symbols,
       *                : numbers, or spaces.
       *                :
       *    Arguments   : _value - The string to be counted
       *                :
       *    Assignments : None
       *                :
       *    Returns     : Returns an integer value indicating the number of
       *                : characters contained in "_value"
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function _countLetters($_value) {
        $_count = 0;
        for ($iCount=0;$iCount<strlen($_value);$iCount++) {
          $_char = substr($_value,$iCount,1);
          if (preg_match("/[a-z]/",$_char)) $_count++;
        }
 
        return $_count;
      }
 
      /**   Function: _readLine
       *    ----------------------------------------------------------------------
       *    Purpose     : Returns a single line from a file, where a "line" is
       *                : defined by a sequence of characters followed by a
       *                : specific delimiter, ignoring carriage return and line
       *                : feed characters. The result is returned as a single
       *                : string with all characters as they were in the file,
       *                : except the carriage returns and line feeds are removed.
       *                : Also, the delimiter is removed from the source data.
       *                :
       *    Arguments   : _fp   - File Pointer obtained when the source file was
       *                :          opened.
       *                : delim - The delimiter character used to identify the
       *                :          end of a logical line.
       *                :
       *    Assignments : None
       *                :
       *    Returns     : A string containing the contents of a "line" from the
       *                : source file.
       *                :
       *    Assumptions : Delimiter must always appear physically as the last
       *                : character on a line, even if the logical line extends
       *                : over multiple lines.
       *                :
       *    Constraints : None
       */
      function _readLine($_fp, $delim) {
        $_line = "";
        $line  = "";
 
        // As long as we don't reach the end of the file and we don't have the
        // delimiter, keep reading lines from the file and appending them
        // together.
        while ((!feof($_fp)) && (substr($_line,-1,1)!=$delim)) {
          $_line = rtrim(fgets($_fp,1024));  // rtrim removes carriage returns
                                             // and line feeds
          $line .= $_line;
        }
 
        if (strlen($line)>0) {
          return substr($line,0,-1);  // Remove delimiter character
        }
        else {
          return null;
        }
      }
 
      /**   Function: read
       *    ----------------------------------------------------------------------
       *    Purpose     : Open the file for reading and call "_readLine()" to
       *                : obtain the word lists and letter lists.
       *                :
       *    Arguments   : None
       *                :
       *    Assignments : Adds word lists to the "_words" array.
       *                : Adds letter lists to the "_letters" array.
       *                :
       *    Returns     : None
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function read() {
        if (file_exists($this->getFilename()) &&
            is_readable($this->getFilename())) {
          $fp = fopen($this->getFilename(), "r")
                or die("An error occurred while attempting to open ".
                       $this->getFilename());
 
          while (!feof($fp)) {
            $temp = $this->_readLine($fp, __WORD_DELIM__);
            if (!is_null($temp)) {
              array_push($this->_words, $temp);
            }
 
            $temp = $this->_readLine($fp, __LETTER_DELIM__);
            if (!is_null($temp)) {
              array_push($this->_letters, $temp);
            }
          }
        }
        else {
          die ($this->getFilename()." doesn't exist or is not readable.");
        }
      }
 
      /**   Function: _checkBlank
       *    ----------------------------------------------------------------------
       *    Purpose     : If either of the "blanks" have been used, check to see
       *                : if they appear in the provided word. If they do appear
       *                : in the word, there is no need to process the word
       *                : because this means that one of the letters it needs is
       *                : no longer available and the word cannot be completed.
       *                :
       *    Arguments   : _word - The word to be checked
       *                :
       *    Assignments : None
       *                :
       *    Returns     : True  - if "_word" contains at least one of the "blanks"
       *                : False - if "_word" does not contain either of the
       *                :         "blanks"
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function _checkBlank($_word) {
        $_found = false;
        for ($iCount=0;$iCount<strlen($_word);$iCount++) {
          $_char = substr($_word,$iCount,1);
          if (($_char == $this->_blanks[__BLANK__ONE__][__BLANK_CHAR__]) ||
              ($_char == $this->_blanks[__BLANK__TWO__][__BLANK_CHAR__])) {
            $_found = true;
          }
        }
 
        return $_found;
      }
 
      /**   Function: _setBlank
       *    ----------------------------------------------------------------------
       *    Purpose     : Attempts to assign a "blank". If either "blank" is open
       *                : the character isn't already stored in one of the
       *                : "blanks", then the character is assigned to the first
       *                : available blank. Also the word that used the blank and
       *                : the character position in the word where the blank
       *                : appears.
       *                :
       *    Arguments   : _char - The character to be used as a "blank"
       *                : _word - The word that needs to use the "blank"
       *                : _pos  - The position in the word where the character
       *                :          appears.
       *                :
       *    Assignments : none
       *                :
       *    Returns     : True  - If "_char" is successfully added as a blank.
       *                : False - If "_char" is not successfully added as a blank
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function _setBlank($_char, $_word, $_pos) {
        $_created = false;
 
        if (($this->_blanks[__BLANK__ONE__][__BLANK_CHAR__]!=$_char) &&
            ($this->_blanks[__BLANK__TWO__][__BLANK_CHAR__]!=$_char)) {
          if ($this->_blanks[__BLANK__ONE__][__BLANK_CHAR__] == '') {
            $this->_blanks[__BLANK__ONE__] = array($_char, $_word, $_pos);
            $_created = true;
          }
          else if ($this->_blanks[__BLANK__TWO__][__BLANK_CHAR__] == '') {
            $this->_blanks[__BLANK__TWO__] = array($_char, $_word, $_pos);
            $_created = true;
          }
        }
 
        return $_created;
      }
 
      /**   Function: _resetBlank
       *    ----------------------------------------------------------------------
       *    Purpose     : While processing a word, if a "blank" has been added and
       *                : then it is determined that the word is not useable, it
       *                : necessary to remove the added "blank(s)".
       *                :
       *    Arguments   : _word - The word that was being processed.
       *                :
       *    Assignments : If the word appears in one of the "blank" slots, then
       *                : that slot in "_blank" is reset to an empty value.
       *                :
       *    Returns     : None
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function _resetBlank($_word) {
        if ($this->_blanks[__BLANK__ONE__][__BLANK_WORD__] == $_word) {
          $this->_blanks[__BLANK__ONE__] = array('', "", 0);
        }
        else if ($this->_blanks[__BLANK__TWO__][__BLANK_WORD__] == $_word) {
          $this->_blanks[__BLANK__TWO__] = array('', "", 0);
        }
      }
 
      /**   Function: _highlightBlank
       *    ----------------------------------------------------------------------
       *    Purpose     : Used for reporting - colors the "blank" character red.
       *                : Used the information stored in the "_blanks" array to
       *                : determine if the supplied word should be highlighted and
       *                : the position of the character to highlight.
       *                :
       *    Arguments   : _word - The word to highlight.
       *                :
       *    Assignments : None
       *                :
       *    Returns     : The provided word is returned, if the word requires
       *                : highlighting it will be included in the returned value.
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function _highlightBlank($_word) {
        $word = $_word;
 
        for ($iCount=0;$iCount<2;$iCount++) {
          if ($_word == $this->_blanks[$iCount][__BLANK_WORD__]) {
            $_temp = $this->_blanks[$iCount][__BLANK_WORD__];
            $word = substr($_temp,0,$this->_blanks[$iCount][__BLANK_POS__]);
            $word.= "<font color=\"red\">";
            $word.= $this->_blanks[$iCount][__BLANK_CHAR__];
            $word.= "</font>";
            $word.= substr($_temp,$this->_blanks[$iCount][__BLANK_POS__]+1,
                           strlen($_word));
          }
        }
 
        return $word;
      }
 
      /**   Function: calcPercent
       *    ----------------------------------------------------------------------
       *    Purpose     : Calculates an integer percentage (0% - 100%) with no
       *                : decimals.
       *                :
       *    Arguments   : value - The value to compute the percentage from
       *                : total - The total amount
       *                :
       *    Assignments : None
       *                :
       *    Returns     : Integer percentage value (0 - 100).
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function calcPercent($value, $total) {
        return round(($value/$total)*100);
      }
 
      /**   Function: calcStatistics
       *    ----------------------------------------------------------------------
       *    Purpose     : Calculates statistics based on the provided word and
       *                : letter lists. The statistics collected are the number
       *                : of each letter required by all the words, the number of
       *                : each letter available in the letter list and the
       *                : difference between those two counts.
       *                :
       *    Arguments   : _wordList   - A string containing the words to locate
       *                : _letterList - A string containing the available letters
       *                :
       *    Assignments : None
       *                :
       *    Returns     : An equivalent of the statistics array - to be assigned,
       *                : by the calling routine, to the class' stats array.
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function calcStatistics($_wordList, $_letterList) {
        // Cycle through the word list and populate the "Need" column of the "stats"
        // array with the count of each occurrence of each letter in the words
        // provided.
        for ($iCount = 0; $iCount < strlen($_wordList); $iCount++) {
          $_char = substr($_wordList, $iCount, 1);
          if (preg_match("/[a-z]/", $_char)) {
            if (!isset($stats[$_char])) {
              $stats[$_char] = array(1, 0, 0);
            }
            else {
              $stats[$_char][__STATS_NEED__]++;
              $stats[$_char][__STATS_DIFF__] = $stats[$_char][__STATS_HAVE__] -
                                               $stats[$_char][__STATS_NEED__];
            }
          }
        }
 
        // Cycle throught the letter list and populate the "Have" and "Diff"
        // columns of the "state" array with the count of each occurrence of
        // each letter in the letters provided and the difference between
        // that count and the count of needed letters.
        for ($iCount = 0; $iCount < strlen($_letterList); $iCount++) {
          $_char = substr($_letterList, $iCount, 1);
          if (preg_match("/[a-z]/", $_char)) {
            if (!isset($stats[$_char])) {
              $stats[$_char] = array(0, 1, 1);
            }
            else {
              $stats[$_char][__STATS_HAVE__]++;
              $stats[$_char][__STATS_DIFF__] = $stats[$_char][__STATS_HAVE__] -
                                               $stats[$_char][__STATS_NEED__];
            }
          }
        }
 
        return $stats;
      }
 
      /**   Function: calcWordWeights
       *    ----------------------------------------------------------------------
       *    Purpose     : Calculates a weight for each word in the provided word
       *                : list. This weight is a count of how many letters in the
       *                : word may be unavailable. This is determined by checking
       *                : the "stats" array for the character, if the difference
       *                : column is less than '0' then there is not enough of that
       *                : character for all the words.
       *                :
       *                : For example:
       *                :  word = "class"
       *                :  stats['c'][DIFF] = -1
       *                :  stats['s'][DIFF} = -4
       *                :
       *                :  weight = 3
       *                :
       *    Arguments   : _words - Array where each entry is a word from the word
       *                :          list.
       *                :
       *    Assignments : None
       *                :
       *    Returns     : An equivalent of the weight array - to be assigned, by
       *                : the calling routine, to the class' weight array
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function calcWordWeights($_words) {
        $wordList = explode(" ", $_words);
 
        foreach ($wordList as $word) {
          for ($iCount = 0; $iCount < strlen($word); $iCount++) {
            $_char = substr($word, $iCount, 1);
            if (preg_match("/[a-z]/", $_char)) {
              if ($this->_stats[$_char][__STATS_DIFF__] < 0) {
                if (!isset($words[$word])) {
                  $words[$word] = array(1, strlen($word), 0);
                }
                else {
                  $words[$word][__WEIGHT_COUNT__]++;
                }
              }
              else {
                if (!isset($words[$word])) {
                  $words[$word] = array(0, strlen($word), 0);
                }
              }
            }
          }
        }
 
        foreach ($words as $key=>$val) {
          $words[$key][__WORDS_PCT__] = 100 -
                                        $this->calcPercent($val[0], $val[1]);
        }
 
        return $words;
      }
 
      /**   Function: processWordList
       *    ----------------------------------------------------------------------
       *    Purpose     : Cycles through the provided word list, in the currently
       *                : sorted order, one word at a time and tries to match it
       *                : based on available provided letters. As a word is
       *                : is located, the available letter counts are reduced by
       *                : the amount used by the word. Also, when necessary,
       *                : "blank" letters are filled in - up to two "blanks".
       *                :
       *                : When the process starts, the "letter" list is copied to
       *                : the "letter_bucket" array for processing. Before each
       *                : word in the list is processed, the "letter_bucket" is
       *                : copied to "trans_bucket". This allows for a database
       *                : style transaction by providing a snap-shot of the array
       *                : prior to processing the word, so that if the word can
       *                : not be located, the "letter_bucket" can rollback to the
       *                : the counts prior to processing the current word.
       *                :
       *    Arguments   : _words   - array containing individual elements for
       *                :            each word.
       *                : _letters - "stats" array, use "HAVE" column
       *                :
       *    Assignments : Located words are appended to the "foundWords" array
       *                :
       *    Returns     : A string containing each of the words sorted from
       *                : largest to smallest, with a space between each word
       *                : and any "blanks" highlighted red.
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function processWordList($_words, $_letters) {
        // Initialize "blank" array for new word list
        $this->_blanks = array(
          array('', "", 0),
          array('', "", 0)
        );
 
        // Make a work copy of the _letters array.
        $letter_bucket = $_letters;
        // Initialize the _foundWords array to an empty array
        $this->_foundWords = array();
 
        foreach ($_words as $word=>$val) {
          // Copy the letter bucket to a transaction bucket
          $trans_bucket = $letter_bucket;
 
          // If the word contains a used "blank", skip processing because
          // the word can not be completed.
          if (!$this->_checkBlank($word)) {
            $foundWord = true;
            for ($iCount=0; $iCount<strlen($word);$iCount++) {
              $_char = substr($word, $iCount, 1);
              if ((isset($letter_bucket[$_char])) &&
                  ($letter_bucket[$_char][__STATS_HAVE__] > 0)) {
                // If we have the letter we need, reduce it in the
                // letter bucket
                $letter_bucket[$_char][__STATS_HAVE__]--;
              }
              else if (!$this->_setBlank($_char, $word, $iCount)) {
                // If we didn't have the letter we needed and
                // we couldn't create a "blank", stop processing
                // the word.
                $foundWord = false;
              }
            }
 
            // If we couldn't find the word, copy the transaction
            // bucket back to the letter bucket in order to reset it to
            // the state it was in prior to processing this word. Also,
            // remove any "blanks" created for this word.
            if (!$foundWord) {
              $letter_bucket = $trans_bucket; // Rollback transaction
              $this->_resetBlank($word);
            }
            else {
              // Word was found - Add it to the "foundWords" array
              array_push($this->_foundWords, $word);
            }
          }
        }
 
        // Sort found words in order from largest to smallest based on
        // character length
        uasort($this->_foundWords, __USER_SORT_REV_LENGTH__);
 
        // Create string containing found words, with a space between
        // the words and any used "blanks" highlighted
        $word="";
        foreach ($this->_foundWords as $_word) {
          $word .= $this->_highlightBlank($_word)." ";
        }
 
        return $word;
      }
 
      /**   Constructor
       *    ----------------------------------------------------------------------
       *    Purpose     : Used to initialize the class when a new instance is
       *                : created. In the case of this script, creating an
       *                : instance of the class causes the whole script to run.
       *                :
       *    Assumptions : None
       *                :
       *    Constraints : None
       */
      function Searcher() {
        // Read word and letter lists from file - if there is not an equal number
        // of word and letter lists, then there was a problem and the script must
        // stop processing.
        $this->read();
        if (count($this->_words)!=count($this->_letters)) die("There is not an ".
          "equal number of word and letter lists");
 
        // Initialize letter counter for whole run
        $this->_letterCount = 0;
        for ($currPos=0; $currPos<count($this->_words); $currPos++) {
          // Calculate statistics for current word and letter list
          $this->_stats = $this->calcStatistics($this->_words[$currPos],
                                                $this->_letters[$currPos]);
          uasort($this->_stats, __USER_SORT_DIFFERENCE__);
 
          // Calculate weights for current word list
          $this->_weights = $this->calcWordWeights($this->_words[$currPos]);
          uasort($this->_weights, __USER_SORT_WEIGHTS__);
 
          $_result = $this->processWordList($this->_weights, $this->_stats);
          $count1 = $this->_countLetters(strip_tags($_result));
 
          uasort($this->_weights, __USER_SORT_REV_WEIGHTS__);
 
          $_result = $this->processWordList($this->_weights, $this->_stats);
          $count2 = $this->_countLetters(strip_tags($_result));
 
          // First, process words ordered by weight in ascending order (smallest
          // to largest weight), then process in descending order. Use the
          // result of whichever one produces a larger count.
          if ($count1 <= $count2) {
            $this->_letterCount += $count2;
            echo $_result."<br>\n";
          }
          else {
            uasort($this->_weights, __USER_SORT_WEIGHTS__);
            $_result = $this->processWordList($this->_weights, $this->_stats);
 
            $this->_letterCount += $this->_countLetters(strip_tags($_result));
 
            echo $_result."<br>\n";
          }
        }
 
        echo $this->_letterCount;
      }
      function __construct() {
        $this->Searcher();
      }
    }
 ?>
   </body>
 </html>
 
Back to results
  | 
 
 
 | 
   
 
 |