/// <summary>
   /// Finds the object that best matches the phrase
   /// </summary>
   /// <param name="lexer">The text being matched</param>
   /// <param name="score">The score for the best match: 0 if no match[out]</param>
   /// <param name="numWordsMatch">The number of words that match [out]</param>
   /// <param name="bestMatch">The object that best matches [out]</param>
   /// <param name="seen">Set of objects already examined</param>
   void matchInContext(ZObject addressedTo, Lexer lexer, 
               ref double score, ref int numWordsMatch,
               ref object bestMatch,
               ref LexState lexerState, Dictionary<object,object> seen)
   {
      // Make a note of where we are in the text
      var state = lexer.Save();
      // Search for the best item within the addressedTo object and it's children
      addressedTo.match(lexer, ref score, ref numWordsMatch, ref bestMatch,
         ref lexerState, seen);

      // Check to see if it a reference to the other party of a relationship
      //  a. Make a list of objects; eg connected to this via relationship/2
      //   i. If the link has a gatekeeper, see if the gate is open or closed
      // b. See which matches best the noun phrases

      //TODO: Bump the score to keep things closer to ourselves ?
      // Scan in each of the directions
      // We can't traverse the edge though
      foreach (var pair in relations)
      {
         // Go back to the saved point in the text
         lexer.Restore(state);
         // Match the relation/direction
         pair.Key.match(lexer, ref score, ref numWordsMatch, ref bestMatch,
            ref lexerState, seen);

         if (!(pair.Value is SparseGraph<ZObject>))
            continue;

         // Get the edge.. if none, then nothing can match
         List<Edge<ZObject>> edges;
         if (!((SparseGraph<ZObject>)pair.Value).successors(addressedTo, out edges) || edges.Count < 1)
         {
            // There is no specific destination here for this location;
            // the player could have given an abstract direction without a
            // concrete direciton.  We'll keep the direction as a match,
            // if it did match.
            continue;
         }

         // If the direction matched, we will keep the edge as it's referrant
         if (bestMatch == pair.Key) 
         {
            // We match the direction, so we are referring to the edge
            bestMatch     = edges[0];
         }

         // Go back to the saved point in the text
         lexer.Restore(state);

         // Match the room or gating door
         // Search for the best item within the addressedTo object and it's
         // children
         match(edges[0], lexer, ref score, ref numWordsMatch, ref bestMatch,
            ref lexerState, seen);
      }
      // Go back to the saved point in the text
      lexer.Restore(state);

      // bump the search to parents and their children
      if (null != addressedTo.Parent)
      {
         //TODO: Bump the score to keep things closer to ourselves ?
         matchInContext(addressedTo.Parent, lexer, ref score, ref numWordsMatch,
                                 ref bestMatch, ref lexerState, seen);
      }
   }
   /// <summary>
   /// Finds a verb phrase that matches
   /// </summary>
   /// <param name="lex"></param>
   /// <param name="stateEndVerbPhrase"></param>
   /// <returns></returns>
   WordList findVerbPhrase(Lexer lex)
   {
      // First, make a list of all verb phrases
      var candidates = new List<WordList>();
      foreach (var item in verbs)
      {
         candidates.Add(item.Key);
      }

      // The words of the verb phrase
      var verbWords = new List<string>();
      var prevState = lex.Save();
      LexState stateEndVerbPhrase=prevState;

      // Next, get words from the lexer as long they match a phrase
      lex.Preprocess();
      while (!lex.EOF)
      {
         var word = lex.Symbol();
         lex.Preprocess();
         
         // See if the word matches any candidate
         var newCandidates = new List<WordList>();
         var numVerbWords = verbWords . Count;
         foreach (var candidate in candidates)
         {
            // Skip "shorter" phrases
            if (numVerbWords >= candidate.words.Length)
                continue;
            // Get the word for this far in
            var item = candidate.words[numVerbWords];

            // Is there a match?
            // Check for exact, but caseless match; or a partial
            if (item.Equals(word, StringComparison.CurrentCultureIgnoreCase)
               || ((word. Length < item.Length)
                     && item.Substring(0, word.Length).Equals(word, StringComparison.CurrentCultureIgnoreCase)))
            {
               // keep it
               newCandidates.Add(candidate);
            }
         }
         // Did anyone match?
         if (newCandidates . Count < 1)
            break;
         // Save the word and the matches
         candidates = newCandidates;
         verbWords.Add(word);
         stateEndVerbPhrase = lex.Save();
      }


      // Check to see if any matched
      if (candidates.Count < 1 || verbWords.Count < 1)
      {
         lex.Restore(prevState);
         return null;
      }

      // Jump back tot he end of the verb phrase
      lex.Restore(stateEndVerbPhrase);

      /// The words for the verb phrase
      WordList verbWordList = new WordList(verbWords.ToArray());

      // Rank the matched phrases, finding the best one
      var bestScore = 0.0;
      WordList bestCandidate = null;
      foreach (var candidate in candidates)
      {
         // Assign a score to the candidate.
         var score = candidate.score(verbWordList);
         // Is it a better match?
         if (score > bestScore)
         {
            // Keep it
            bestScore = score;
            bestCandidate=candidate;
         }
      }

      // Return the best matched phrase
      return bestCandidate;
   }