/// <summary> /// Adds a category to the graphmaster structure /// </summary> /// <param name="sEnd">a string to be mapped by this node</param> /// <param name="cat">the cCategory to be associated with the nodemapper</param> public void addCat(string sEnd, cCategory cat) { // this node represents the end of the sentence to be mapped so set // the cCategory for this node to the cCategory that was passed to the // function if (sEnd == "" || sEnd.Length <= 0) { thisCategory = cat; return; } // otherwise, this sentence requires further child nodemappers in order to // be fully mapped within the GraphMaster structure. // split the input into its component words string[] sWords = sEnd.Split(" ".ToCharArray()); // get the first word (to form the key for the child nodemapper) string sFirst = sWords[0]; // concatenate the rest of the sentence into a suffix (to act as the // sEnd argument in the child nodemapper) string endstr = sEnd.Substring(sFirst.Length, sEnd.Length - sFirst.Length); endstr = endstr.Trim(); // o.k. check we don't already have a child with the key from this sentence cNodeMapper wordmap = (cNodeMapper)htChildren[sFirst]; // if we do then pass the handling of this sentence down the branch to the // child nodemapper if (wordmap != null) { wordmap.addCat(endstr, cat); } // otherwise the child nodemapper doesn't yet exist, so create a new one else { cNodeMapper mapper = new cNodeMapper(); mapper.sWord = sFirst; mapper.addCat(endstr, cat); htChildren.Add(mapper.sWord, mapper); } }
/// <summary> /// Adds a category to the graphmaster structure /// </summary> /// <param name="sEnd">a string to be mapped by this node</param> /// <param name="cat">the cCategory to be associated with the nodemapper</param> public void addCat(string sEnd, cCategory cat) { // this node represents the end of the sentence to be mapped so set // the cCategory for this node to the cCategory that was passed to the // function if (sEnd == "" || sEnd.Length <= 0) { thisCategory = cat; return; } // otherwise, this sentence requires further child nodemappers in order to // be fully mapped within the GraphMaster structure. // split the input into its component words string[] sWords = sEnd.Split( " ".ToCharArray() ); // get the first word (to form the key for the child nodemapper) string sFirst = sWords[0]; // concatenate the rest of the sentence into a suffix (to act as the // sEnd argument in the child nodemapper) string endstr = sEnd.Substring( sFirst.Length, sEnd.Length - sFirst.Length ); endstr = endstr.Trim(); // o.k. check we don't already have a child with the key from this sentence cNodeMapper wordmap = (cNodeMapper)htChildren[sFirst]; // if we do then pass the handling of this sentence down the branch to the // child nodemapper if (wordmap != null) { wordmap.addCat(endstr, cat); } // otherwise the child nodemapper doesn't yet exist, so create a new one else { cNodeMapper mapper = new cNodeMapper(); mapper.sWord = sFirst; mapper.addCat(endstr, cat); htChildren.Add(mapper.sWord, mapper); } }
/// <summary> /// Searches the nodemapper with the input string /// </summary> /// <param name="sInput">Normalised input concatenated with "that" and "topic" parameters</param> /// <param name="iMatchState">Denotes what part of the input path this node is a part of: /// 0=raw input /// 1="that" /// 2="topic" /// Used when pushing values represented by wildcards onto ArrayLists for /// the star, thatstar and topicstar AIML values</param> /// <param name="sWildcard">contents of the user input absorbed by the AIML wildcards "_" and "*"</param> /// <returns>the appropriate cCategory for the given input</returns> public cCategory evaluate(string sInput, int iMatchState, string sWildcard) { // make sure the input string is nice and tidy string sInputTrim = sInput.Trim(); // o.k. if this is the end of a branch in the GraphMaster // return the cCategory for this node if (thisCategory != null && htChildren.Count == 0) { cCategory tempCat; if (thisCategory != null) { tempCat = new cCategory(thisCategory); tempCat.filename = thisCategory.filename; cGlobals.writeLog("Category found using path: " + thisCategory.sPath + "\r\nAnd with this template: " + thisCategory.sTemplate + "\r\nFrom this file: " + thisCategory.filename); } else { tempCat = null; } return(tempCat); } // if we've matched all the words in the input sentence and this is the end // of the line then return the cCategory for this node if (sInputTrim.Length == 0) { cCategory tempCat; if (thisCategory != null) { tempCat = new cCategory(thisCategory); tempCat.filename = thisCategory.filename; } else { tempCat = null; } return(tempCat); } // otherwise split the input into it's component words string[] sWords = sInputTrim.Split(" \r\n\t".ToCharArray()); // get the first word of the sentence string sFirstword; if ((sWords[0] == "<that>") || (sWords[0] == "<topic>") || (iMatchState > 0)) { sFirstword = sWords[0]; } else { sFirstword = sWords[0].ToUpper(); } // and concatenate the rest of the input into a suffix string string sMessagesuffix = sInputTrim.Substring(sFirstword.Length, sInputTrim.Length - sFirstword.Length); // first option is to see if this nodemapper contains a child denoted by the "_" // wildcard. "_" comes first in precedence in the AIML alphabet if (htChildren.ContainsKey("_")) { // o.k. look for the path in the child nodemapper denoted by "_" cNodeMapper LeafNode = (cNodeMapper)htChildren["_"]; // Aha! we've found the right cNodeMapper (don't you just love it when stuff works!) if (LeafNode != null) { // move down into the identified branch of the GraphMaster structure cCategory tempcat = LeafNode.evaluate(sMessagesuffix, iMatchState, sWords[0]); // and if we get a result from the branch process and return it if (tempcat != null) { // capture and push the star content appropriate to the current matchstate switch (iMatchState) { case 0: if (sWildcard.Length > 0) { tempcat.alInputStar.Insert(0, sWildcard); } break; case 1: if (sWildcard.Length > 0) { tempcat.alThatStar.Insert(0, sWildcard); } break; case 2: if (sWildcard.Length > 0) { tempcat.alTopicStar.Insert(0, sWildcard); } break; } return(tempcat); } } } // second option - the nodemapper may have contained a "_" child, but led to no match // or it didn't contain a "_" child at all. So get the child nodemapper from this // nodemapper that matches the first word of the input sentence. if (htChildren.ContainsKey(sFirstword)) { // make sure we're not changing the iMatchState (encountering <that> or <topic> tags) if (sFirstword == "<that>") { iMatchState = 1; } else if (sFirstword == "<topic>") { iMatchState = 2; } else if ((iMatchState == 2) & (sMessagesuffix.Length == 0)) { iMatchState = 3; } cNodeMapper LeafNode = (cNodeMapper)htChildren[sFirstword]; // Aha! we've found the right cNodeMapper if (LeafNode != null) { // move down into the identified branch of the GraphMaster structure cCategory tempcat = LeafNode.evaluate(sMessagesuffix, iMatchState, ""); // and if we get a result from the branch return it if (tempcat != null) { // capture and push the star content appropriate to the PREVIOUS matchstate switch (iMatchState) { case 0: if (sWildcard.Length > 0) { tempcat.alInputStar.Insert(0, sWildcard); } break; case 1: if (sWildcard.Length > 0) { tempcat.alInputStar.Insert(0, sWildcard); } break; case 2: if (sWildcard.Length > 0) { tempcat.alThatStar.Insert(0, sWildcard); } break; case 3: if (sWildcard.Length > 0) { tempcat.alTopicStar.Insert(0, sWildcard); } break; } return(tempcat); } } } // third option - the input part of the path might have been matched so far but hasn't // returned a match, so check to see it contains the "*" wildcard. "*" comes last in // precedence in the AIML alphabet. if (htChildren.ContainsKey("*")) { // o.k. look for the path in the child nodemapper denoted by "*" cNodeMapper LeafNode = (cNodeMapper)htChildren["*"]; // Aha! we've found the right cNodeMapper if (LeafNode != null) { // move down into the identified branch of the GraphMaster structure cCategory tempcat = LeafNode.evaluate(sMessagesuffix, iMatchState, sWords[0]); // and if we get a result from the branch process and return it if (tempcat != null) { // capture and push the star content appropriate to the current matchstate switch (iMatchState) { case 0: if (sWildcard.Length > 0) { tempcat.alInputStar.Insert(0, sWildcard); } break; case 1: if (sWildcard.Length > 0) { tempcat.alThatStar.Insert(0, sWildcard); } break; case 2: if (sWildcard.Length > 0) { tempcat.alTopicStar.Insert(0, sWildcard); } break; } return(tempcat); } } } // o.k. if the nodemapper has failed to match at all: the input contains neither // a "_", the sFirstWord text, or "*" as a means of denoting a child node. However, // if this node is itself representing a wildcard then the search continues to be // valid if we proceed with the tail. if ((sWord == "_") || (sWord == "*")) { return(this.evaluate(sMessagesuffix, iMatchState, sWildcard + " " + sFirstword)); } // If we get here then we're at a dead end so return a null. Hopefully, if the // AIML files have been set up to include a "* <that> * <topic> *" catch-all this // state won't be reached. return(null); }