Update of /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser
In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv13229/src/games/stendhal/server/entity/npc/parser
Modified Files:
Sentence.java ConversationContext.java ConversationParser.java
Expression.java ExpressionType.java
Log Message:
task 1851849: make NPC conversation more flexible
https://sourceforge.net 2/tracker/?group_id=1111&func=detail&atid=973767&aid=1851849
implement sentence matching with joker strings and type string specifiers
Index: ConversationContext.java
===================================================================
RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/ConversationContext.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** ConversationContext.java 28 Dec 2007 13:45:40 -0000 1.3
--- ConversationContext.java 5 Jan 2008 22:07:05 -0000 1.4
***************
*** 8,17 ****
public class ConversationContext {
! // converation context states
static final int CCS_NONE = 0; // no current conversation context
static final int CCS_WAIT_FOR_YES_NO = 1; // wait for a yes/no answer
static final int CCS_WAIT_FOR_OBJECT = 2; // wait for a named object
! private int state = CCS_NONE;
public void setState(int state) {
--- 8,19 ----
public class ConversationContext {
! // conversation context states
static final int CCS_NONE = 0; // no current conversation context
static final int CCS_WAIT_FOR_YES_NO = 1; // wait for a yes/no answer
static final int CCS_WAIT_FOR_OBJECT = 2; // wait for a named object
! private int state = CCS_NONE; // current state
!
! private boolean forMatching = false; // flag for sentences to be used for matching
public void setState(int state) {
***************
*** 23,25 ****
--- 25,35 ----
}
+ public void setForMatching(boolean forMatching) {
+ this.forMatching = forMatching;
+ }
+
+ public boolean isForMatching() {
+ return forMatching;
+ }
+
}
Index: ConversationParser.java
===================================================================
RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/ConversationParser.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** ConversationParser.java 5 Jan 2008 12:03:37 -0000 1.9
--- ConversationParser.java 5 Jan 2008 22:07:05 -0000 1.10
***************
*** 60,73 ****
/**
* Parse the given text sentence.
*
* @param text
* @param ctx
! * @return sentence
*/
public static Sentence parse(String text, ConversationContext ctx) {
- //TODO mf - use context information
-
// 1.) determine sentence type from trailing punctuation
Sentence sentence = new Sentence();
--- 60,85 ----
/**
+ * Parse the given text sentence to be used for sentence matching.
+ *
+ * @param text
+ * @return
+ */
+ public static Sentence parseForMatching(String text) {
+ ConversationContext ctx = new ConversationContext();
+
+ ctx.setForMatching(true);
+
+ return parse(text, ctx);
+ }
+
+ /**
* Parse the given text sentence.
*
* @param text
* @param ctx
! * @return Sentence
*/
public static Sentence parse(String text, ConversationContext ctx) {
// 1.) determine sentence type from trailing punctuation
Sentence sentence = new Sentence();
***************
*** 86,90 ****
// 3.) classify word types and normalize words
! sentence.classifyWords(parser);
// 4.) evaluate sentence type from word order
--- 98,102 ----
// 3.) classify word types and normalize words
! sentence.classifyWords(parser, ctx!=null? ctx.isForMatching(): false);
// 4.) evaluate sentence type from word order
Index: Expression.java
===================================================================
RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/Expression.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** Expression.java 5 Jan 2008 21:14:05 -0000 1.7
--- Expression.java 5 Jan 2008 22:07:05 -0000 1.8
***************
*** 306,310 ****
* @return
*/
! private String getNormalizedMatchString() {
// special case for numeric expressions to disambiguate "no" from "0"
if (type != null && type.isNumeral()) {
--- 306,310 ----
* @return
*/
! String getNormalizedMatchString() {
// special case for numeric expressions to disambiguate "no" from "0"
if (type != null && type.isNumeral()) {
Index: Sentence.java
===================================================================
RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/Sentence.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** Sentence.java 5 Jan 2008 11:58:44 -0000 1.14
--- Sentence.java 5 Jan 2008 22:07:05 -0000 1.15
***************
*** 24,27 ****
--- 24,30 ----
private int sentenceType = ST_UNDEFINED;
+ /** Joker String used in pattern matches */
+ private static final String JOKER = "*";
+
private String error = null;
***************
*** 455,465 ****
* @param parser
*/
! public void classifyWords(ConversationParser parser) {
WordList wl = WordList.getInstance();
for (Expression w : expressions) {
String original = w.getOriginal();
! WordEntry entry = wl.find(original);
if (entry != null && entry.getType() != null) {
--- 458,479 ----
* @param parser
*/
! public void classifyWords(ConversationParser parser, boolean forMatching) {
WordList wl = WordList.getInstance();
for (Expression w : expressions) {
String original = w.getOriginal();
+ WordEntry entry = null;
! // If the parsed Sentence will be used for matching, look for ExpressionType specifiers.
! if (forMatching) {
! if (ExpressionType.isTypeString(original)) {
! w.setType(new ExpressionType(original));
! w.setNormalized(JOKER);
! }
! }
!
! if (w.getType() == null) {
! entry = wl.find(original);
! }
if (entry != null && entry.getType() != null) {
***************
*** 495,499 ****
if (verb != null) {
if (Grammar.isGerund(original)) {
! w.setType(new ExpressionType(verb.getTypeString() + ExpressionType.GERUND));
} else {
w.setType(verb.getType());
--- 509,513 ----
if (verb != null) {
if (Grammar.isGerund(original)) {
! w.setType(new ExpressionType(verb.getTypeString() + ExpressionType.SUFFIX_GERUND));
} else {
w.setType(verb.getType());
***************
*** 580,584 ****
Expression subject2 = getSubject(1);
! // [you] give me(i) -> [I] buy
// Note: The second subject "me" is replaced by "i" in the WordList
// normalization.
--- 594,598 ----
Expression subject2 = getSubject(1);
! // "[you] give me(i)" -> "[I] buy"
// Note: The second subject "me" is replaced by "i" in the WordList
// normalization.
***************
*** 596,600 ****
}
! // [SUBJECT] (would like to have) -> [SUBJECT] buy
if (verb.getNormalized().equals("have")
&& verb.getOriginal().contains("like")
--- 610,614 ----
}
! // "[SUBJECT] (would like to have)" -> ""[SUBJECT] buy"
if (verb.getNormalized().equals("have")
&& verb.getOriginal().contains("like")
***************
*** 844,853 ****
/**
! * Check if two Sentences match each other.
*
* @param other
* @return
*/
! public boolean matchesNormalized(Sentence other) {
// shortcut for sentences with differing lengths
if (expressions.size() != other.expressions.size()) {
--- 858,867 ----
/**
! * Check if two Sentences consist of identical normalized Expressions.
*
* @param other
* @return
*/
! public boolean equalsNormalized(Sentence other) {
// shortcut for sentences with differing lengths
if (expressions.size() != other.expressions.size()) {
***************
*** 855,859 ****
}
! // loop over all expressions and match them between both sides
Iterator<Expression> it1 = expressions.iterator();
Iterator<Expression> it2 = other.expressions.iterator();
--- 869,873 ----
}
! // loop over all expressions and compare both sides
Iterator<Expression> it1 = expressions.iterator();
Iterator<Expression> it2 = other.expressions.iterator();
***************
*** 878,889 ****
/**
* Check if the Sentence matches the given String.
*
! * @param str
* @return
*/
! public boolean matches(String str) {
! // TODO mf - evaluate expression types instead of just calling matchesNormalized()
! return matchesNormalized(ConversationParser.parse(str));
}
}
--- 892,965 ----
/**
* Check if the Sentence matches the given String.
+ * The match Sentence can contain explicit expressions, which
+ * are compared after normalizing, or ExpressionType specifiers
+ * like "VER" or "SUB*" in upper case.
*
! * @param text
* @return
*/
! public boolean matchesNormalized(String text) {
! return matches(ConversationParser.parseForMatching(text));
! }
!
! /**
! * Check if the Sentence matches the given Sentence.
! * The match Sentence can contain explicit expressions, which
! * are compared after normalizing, or ExpressionType specifiers
! * like "VER" or "SUB*" in upper case.
! *
! * @param other
! * @return
! */
! public boolean matches(Sentence other) {
! // shortcut for sentences with differing lengths
! if (expressions.size() != other.expressions.size()) {
! return false;
! }
!
! // loop over all expressions and match them between both sides
! Iterator<Expression> it1 = expressions.iterator();
! Iterator<Expression> it2 = other.expressions.iterator();
!
! while (it1.hasNext() && it2.hasNext()) {
! Expression e1 = it1.next();
! Expression e2 = it2.next();
! String matchString = e2.getNormalized();
!
! if (matchString.contains(JOKER)) {
! if (matchString.equals(JOKER)) {
! // Type string matching is identified by a single "*" as normalized string expression.
! if (!matchesJokerString(e1.getTypeString(), e2.getTypeString())) {
! return false;
! }
! } else {
! // Look for a normalized string match towards the string containing a joker character.
! if (!matchesJokerString(e1.getNormalizedMatchString(), matchString)) {
! return false;
! }
! }
! } else if (!e1.matchesNormalized(e2)) {
! return false;
! }
! }
!
! // Now there should be no more expressions at both sides.
! if (!it1.hasNext() || it2.hasNext()) {
! return true;
! } else {
! return false;
! }
}
+ /**
+ * Match the given String towards a pattern String containing JOKER characters.
+ *
+ * @param str
+ * @param matchString
+ * @return
+ */
+ private boolean matchesJokerString(String str, String matchString) {
+ return str.matches(".*" + matchString.replace(JOKER, ".*") + ".*");
+ }
+
}
Index: ExpressionType.java
===================================================================
RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/server/entity/npc/parser/ExpressionType.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** ExpressionType.java 2 Jan 2008 09:21:47 -0000 1.3
--- ExpressionType.java 5 Jan 2008 22:07:05 -0000 1.4
***************
*** 1,4 ****
--- 1,7 ----
package games.stendhal.server.entity.npc.parser;
+ import java.util.Arrays;
+ import java.util.List;
+
public class ExpressionType {
***************
*** 7,11 ****
// Expression type string constants
public static final String VERB = "VER"; // verb
! public static final String GERUND = "-GER"; // gerund form
public static final String CONDITIONAL = "CON"; // conditional form
public static final String NEGATED = "NEG"; // negated form
--- 10,14 ----
// Expression type string constants
public static final String VERB = "VER"; // verb
! public static final String GERUND = "GER"; // gerund form
public static final String CONDITIONAL = "CON"; // conditional form
public static final String NEGATED = "NEG"; // negated form
***************
*** 37,40 ****
--- 40,44 ----
// derived string type constants
+ public static final String SUFFIX_GERUND = SUFFIX + GERUND;
public static final String SUFFIX_COLOR = SUFFIX + COLOR;
public static final String SUFFIX_CONDITIONAL = SUFFIX + CONDITIONAL;
***************
*** 42,45 ****
--- 46,50 ----
public static final String SUFFIX_PRONOUN = SUFFIX + PRONOUN;
public static final String SUFFIX_FOOD = SUFFIX + FOOD;
+ public static final String SUFFIX_OBSESSIONAL = SUFFIX + OBSESSIONAL;
public static final String SUFFIX_FLUID = SUFFIX + FLUID;
public static final String SUFFIX_ANIMAL = SUFFIX + ANIMAL;
***************
*** 48,52 ****
public static final String SUFFIX_PLURAL = SUFFIX + PLURAL;
public static final String SUFFIX_QUESTION = SUFFIX + QUESTION;
! public static final String VERB_GERUND = VERB + GERUND;
public ExpressionType(String s) {
--- 53,82 ----
public static final String SUFFIX_PLURAL = SUFFIX + PLURAL;
public static final String SUFFIX_QUESTION = SUFFIX + QUESTION;
! public static final String VERB_GERUND = VERB + SUFFIX_GERUND;
!
! /** type string specifiers, which can be used in sentence matching */
! public final static List<String> TYPESTRINGS = Arrays.asList(
! VERB,
! OBJECT,
! AMOUNT,
! SUBJECT,
! ADJECTIVE,
! NUMERAL,
! PREPOSITION,
! QUESTION,
! //IGNORE,
!
! SUFFIX_GERUND,
! SUFFIX_COLOR,
! SUFFIX_CONDITIONAL,
! SUFFIX_NEGATED,
! SUFFIX_PRONOUN,
! SUFFIX_FOOD,
! SUFFIX_OBSESSIONAL,
! SUFFIX_FLUID,
! SUFFIX_ANIMAL,
! SUFFIX_NAME,
! SUFFIX_PLURAL
! );
public ExpressionType(String s) {
***************
*** 222,225 ****
--- 252,279 ----
/**
+ * Check if the given String contains a type string specifier.
+ *
+ * @param original
+ * @return
+ */
+ public static boolean isTypeString(String str) {
+ if (str.length() > 0) {
+ char first = str.charAt(0);
+
+ // All type strings must start with an upper case letter,
+ // even the SUFFIX character '-' is not allowed.
+ if (Character.isUpperCase(first)) {
+ for(String ts : TYPESTRINGS) {
+ if (str.contains(ts)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Merge with another ExpressionType.
*
***************
*** 262,264 ****
--- 316,319 ----
}
+
}
|