Parser Limitation with number of words

Started by papste, Fri 12/06/2009 15:52:12

Previous topic - Next topic

papste

After having carefully checked the manual and forums, i couldn't find anywhere the maximum number of text parser words. However the specific game that i was trying to develop gives me the error message that i have used too many words. It would help to know the correct number so that i can manage my game better and remove the unnecessary words. Also is there any chance of increasing the limit or any other way to overcome this obstacle? 

magintz

You could always be really adventurous and use an alternative store for synonyms; such as an external file or by parsing data from somewhere like thesaurus.com using the tcp/ip plugin.

However these are silly ideas... silly but fun :)
When I was a little kid we had a sand box. It was a quicksand box. I was an only child... eventually.

monkey0506

#2
You could possibly just set up a function to return the appropriate synonym. It could quite easily become a mess to read, but might be the simplest option:

Code: ags
String GetParserWord(String userInput) {
  if (String.IsNullOrEmpty(userInput)) return null;
  if (userInput == "wood" || userInput == "timber" || userInput == "plank") {
    return "timber";
  }
  if (userInput == "dog" || userInput == "hound" || userInput == "mongrel" ||
  userInput == "mutt" || userInput == "man's best friend" || userInput == "pooch" ||
  userInput == "puppy" || userInput == "deadly piranha poodle") {
    return "dog";
  }
  return null;
}

// ...after getting the user's input from the textbox...
String userInput = txtParserInput.Text;
Parser.ParseText(userInput);
String badWord = Parser.SaidUnknownWord();
String goodWord = GetParserWord(badWord);
while (badWord != null && goodWord != null) {
  userInput = userInput.Replace(badWord, goodWord);
  Parser.ParseText(userInput);
  badWord = Parser.SaidUnknownWord();
  goodWord = GetParserWord(badWord);
}
if (badWord != null) { // ran out of viable replacement words...
  Display("This game does not recognize the word '%s'. Please use a different word!", badWord);
}


That's a pretty rough example, but you should get the basic gist of it...

papste

#3
Thank you both for the swift responce  :)
monkey_05_06 your idea works like a charm. I'm currently looking for a way to use your script but having AGS read the synonyms from a file instead of coding it directly into the script.  I guess i can achieve that by having AGS read groups of words from a file and then returning the first word in  the group.

edit: your script seems to work just fine with single words. It doesn't seem to work in the case of dog = deadly piranha poodle, which is a 3-word substitute. I guess its because String badWord = Parser.SaidUnknownWord() returns only 1 word, and in the case of the word being "deadly piranha poodle" your script will try to replace each word individually returning "dog dog dog". I suppose that's what the problem is but then again I'm not an expert with AGS programming yet.

monkey0506

You're exactly right about Parser.SaidUnknownWord returning only a single word at a time, so multi-word synonyms wouldn't be possible this way...not without a more complex custom comparison algorithm...(edit: ) or actually...the String.Replace function could come in use here...just using that on the raw user input...

As far as reading the synonyms from a file, can I ask what format would you want the file to be written in? I could come up with something, but if you could provide an outline of what you would want the raw text-file to look like as far as the word-synonym pairs that would be easier.

Once I've got the way to write the file sorted out (the order in which to write the data) then presumably it wouldn't be too difficult (and hopefully not too slow) to run a String.Replace for each synonym with its respective parser word.

papste

#5
If it turns out too slow then i guess i can always have the values loading from the file into an array at game start, so i don't have to access the file every time the parser input is used. The problem with that is i need to find a way to distinguish the different word groups within the array. I was thinking it could work if i programmed AGS to add a code ending with a special character at the start of the each word (eg 1.1@dog 1.2@hound 2.1@greet 2.1@hello etc.) while they are being read from the file at game start, and then remove the code just before i replace the words at userInput. As for the type of file i don't really mind about the format to be used as long as its easy to edit the words from outside the AGS editor. A simple text file could work without problems (if i find a way to distinguish the different word groups).

Anyway the original code that you provided has already helped overcome the parser limitation by removing the 1-word synonyms from the text parser, which i think will be enough to make the game work without sacrificing anything, since my original problem was that the parser had too many words.

papste

#6
I came up with the following code seems to work well so far. It works for multi-word synonyms too. I figured i should post it in case you guys could come up with a modification to handle the array better:

Code: ags

String synonym[10];
export synonym;

String replace_text(String userInput) {
  int i = 1;
  while ((i <= 10) && (!String.IsNullOrEmpty(synonym[i]))) {
    int result = userInput.IndexOf(synonym[i]);
    if (result != -1) {
      userInput = userInput.Replace(synonym[i], synonym[0]);
    }
    synonym[i] = null;
    i++;
  }
  return userInput;
}

String check_for_synonym(String userInput) {
  if (String.IsNullOrEmpty(userInput)) return null;

  synonym[0] = "dog";
  synonym[1] = "hound";
  synonym[2] = "mongrel";
  synonym[3] = "mutt";
  synonym[4] = "man's best friend";
  synonym[5] = "pooch";
  synonym[6] = "puppy";
  synonym[7] = "deadly piranha poodle";
  userInput = replace_text(userInput);

  synonym[0] = "abdulla";
  synonym[1] = "abdullah";
  synonym[2] = "doo";
  userInput = replace_text(userInput); 

  return userInput;
}

// ...after getting the user's input from the textbox...
  String userInput = txtParserInput.Text;
  userInput = check_for_synonym(userInput);
  Parser.ParseText(userInput);
  String badWord = Parser.SaidUnknownWord();
  if (badWord != null) { // ran out of viable replacement words...
    Display("You will not need to use the word \"%s\" in this game.", badWord);
  }


edit: the above code replaces every instance of the synonym found in the user input. In the case of the user input being "open the door", it finds "doo" and replaces with "abdulla" resulting to the text "open abdullar", which isn't what we seek. Thus i somehow have to add an additional check to see if the character following the synonym is a space (meaning its the end of the word) and replace the text only if it satisfies the check. I might need a little help with that since the sentence might end with that word and thus not contain any spaces.

Pumaman

Hmm interesting, looks like there's a 1500 word limit on the text parser ... I'd forgotten that this limitation even existed, probably because nobody's ever reached it before!

If it's a problem for you I can look into removing it in a future version.

papste

#8
A game that relies primarily on the text parser can grow quite big as far as the number of vocabulary words used is concerned. Just to give an idea, if you open the Quest for glory 2 (made more than a decade ago by sierra) with the resource viewer you can see that the vocabulary goes up to 4095 words not including synonyms. Now i suppose you can live without the use of adjectives like "BLACK" bird, or "BRONZE' lamp, etc where you can instead type "examine lamp" and remove the adjective completely. However it would make the game alot more real and immersive if AGS didn't have the 1500 word limitation. If it's not too much trouble for you Chris i would be grateful if you increased the limit to 5000 (or more if that is possible) in a future version.

papste

#9
Ok i temporarily found a solution to my problem. The correct code is the following:

Code: ags

String synonym[15];
export synonym;

String replace_text(String userInput) {
  int i = 1;
  while ((i <= 15) && (!String.IsNullOrEmpty(synonym[i]))) {
    int result = userInput.IndexOf(synonym[i]);
    while ((result != -1) && ((String.Format("%c", userInput.Chars[result - 1]) == " ") || (result == 0)) &&
    ((String.Format("%c", userInput.Chars[result + synonym[i].Length]) == " ") || (result + synonym[i].Length == userInput.Length))) {
      String tempInput1 = userInput.Substring(0, result + synonym[i].Length);
      String tempInput2 = userInput.Substring(result + synonym[i].Length, userInput.Length - 1);
      tempInput1 = tempInput1.Replace(synonym[i], synonym[0]);
      userInput = tempInput1.Append(tempInput2);
      result = userInput.IndexOf(synonym[i]);
    }
    synonym[i] = null;
    i++;
  }
  return userInput;
}

String check_for_synonym(String userInput) {
  if (String.IsNullOrEmpty(userInput)) return null;

  synonym[0] = "dog";
  synonym[1] = "hound";
  synonym[2] = "mongrel";
  synonym[3] = "mutt";
  synonym[4] = "man's best friend";
  synonym[5] = "pooch";
  synonym[6] = "puppy";
  synonym[7] = "deadly piranha poodle";
  userInput = replace_text(userInput);

  synonym[0] = "abdulla";
  synonym[1] = "abdullah";
  synonym[2] = "doo";
  userInput = replace_text(userInput); 

  return userInput;
}

// ...after getting the user's input from the textbox...
  String userInput = txtParserInput.Text;
  userInput = check_for_synonym(userInput);
  Parser.ParseText(userInput);
  String badWord = Parser.SaidUnknownWord();
  if (badWord != null) { // ran out of viable replacement words...
    Display("You will not need to use the word \"%s\" in this game.", badWord);
  }

Pumaman

I will certainly look into this for a future version, I can imagine that 1500 words isn't enough if you're making a full-length parser game.

SMF spam blocked by CleanTalk