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