Reputation: 744
This is fairly difficult to explain. I am working on a text adventure at the moment and I am parsing input from a player.
When a player enters input, there can be two possible subjects (let's call them subject1 and subject2). For example, in the following: "hit door with stick", subject1 is "door" and subject2 is "stick".
In this case, both door and stick are of the type "Item". There can also be subjects of the type "Character".
The problem is that if I parse items, then characters, the item parse will find the item as subject1 even if it's actually the second subject. The code I am using looks like this:
public static void ParseForSubjects(string Input, Player CurrentPlayer, ref object Subject1, ref object Subject2)
{
// This method doesn't really work properly, as it looks up Inventory items, Environment items and then Characters in order
// when it may well be that a character is subject1 and an item is subject2, but they will be reversed because of the parsing order
Input = Input.ToLower();
// Parse items in Player inventory
foreach (Item InventoryItem in CurrentPlayer.Inventory)
{
if (Input.Contains(InventoryItem.Name.ToLower()))
{
if (Subject1 == null)
{
Subject1 = InventoryItem;
}
else
{
Subject2 = InventoryItem;
}
}
}
// Parse items in environment
foreach (Item EnvironmentalItem in CurrentPlayer.CurrentArea.Items)
{
if (Input.Contains(EnvironmentalItem.Name.ToLower()))
{
if (Subject1 == null)
{
Subject1 = EnvironmentalItem;
}
else
{
Subject2 = EnvironmentalItem;
}
}
}
// Parse present characters
foreach (Character PresentCharacter in CurrentPlayer.CurrentArea.Characters)
{
if (Input.Contains(PresentCharacter.Name.ToLower()))
{
if (Subject1 == null)
{
Subject1 = PresentCharacter;
}
else
{
Subject2 = PresentCharacter;
}
}
}
}
I'm sure if this is really clear enough. Basically regardless of the type, I need subject1 to be the first subject in the Input string and subject2 to be the second subject in the Input string.
Feel free to ask questions, this probably isn't 100% clear.
Upvotes: 0
Views: 136
Reputation: 134125
I'd suggest turning your logic upside down. Rather than checking every inventory item to see if it's mentioned in the string, just parse the string and check the inventory for the item. For example:
string[] parsedInput = Input.Split([' ']);
Now you have an array that contains the user's input, word-by-word. If you always know that subject1 is the second word and subject2 is the fourth, then:
string subject1 = parsedInput[1];
// check to see if subject1 is in the Inventory or the Environment collections
Do the same thing with subject2
(i.e. parsedInput[3]
)
If you can't guarantee where the subjects are in the array, then you'll have to iterate over the array to determine which of the items are subjects. The key is to use the user's input to check the inventory/environment/character collections rather than the other way around. So rather than saying:
for each item in inventory/environment/characters
did user's input mention this?
You say instead:
for each item that the user mentioned
is it in the inventory/environment/characters collections?
Upvotes: 1
Reputation: 10001
If I understand you correctly, what you're actually saying is that "stick" becomes Subject1 if it is found first in the inventory collection, even though it is actually Subject2 in the input line. If so, why not change the Subject
variables into an array, and then populate that array based on the position of the noun in the input?
Thus, Subject[]
would be populated as: Subject[1]="door"
and Subject[2]="stick"
. You then iterate through the array, processing the subjects in ascending order.
This requires a little more support code to determine which of the 'n' nouns in the input you are currently parsing, but if you restructure the parse loop so that you're parsing the input rather than the inventory, this becomes trivial.
This article may also help refine the thought-process on this: Natural Language Processing
Upvotes: 0
Reputation: 5932
Just check Input.IndexOf(Subject1.Name.ToLower()) < Input.IndexOf(Subject2.Name.ToLower())
and if false, then switch them.
Upvotes: 2
Reputation: 19012
Could you do something incredibly simple like save the starting position of each subject you find, and then at the end of your function, use the saved positions to determine which subject came first?
Upvotes: 0