Comparing Commands to Table Entries - Or - Text vs Snippet

I am attempting to compare a player’s command to a table of possible items. I tried reading about reading a command and snippets, but I’m still unsure why I can’t try to check if the player’s command matches some text in a table. Can someone help explain that and give an example of what it takes to “convert” one into the other for the purpose of being able to compare them? My example not working code is:

[...prior stuff above...]
now the suspect-prompt is true;
now the command prompt is "Who did it? >";			

Table of Suspects
who	
"Professor Plum"
"Mrs. White"
"Mr. Green"
"Mrs. Peacock"
"Miss Scarlet"
"Colnel Mustard"

Last after reading a command when suspect-prompt is true:
	repeat through Table of Suspects:
		if the player's command matches the who entry:
			say "And might I ask where [who entry] did the deed?";
                        now the suspect-prompt is false;
                        now the where-prompt is true;
			now the command prompt is "Where did [who entry] do it? >";
			
[...other stuff to follow...]

Now, I realize there are other things wrong with this code from a finished game perspective (the command will be an unrecognized verb for one) but these are all things to take care of later if I get the current problem resolved first. I also realize this may not be the optimal way to do what this code seems to be built to do in the first place… but the point of my current question is really to ask how to compare the player’s command to the record in the table. As long as that is answered, additional critique and advice is gladly welcome. As always, this is not a real game (obviously it references “Clue”, but I mean this is not meant to ever be a real Inform IF game), but is just an exercise for me to learn from.

You can’t actually compare the player’s command directly with a text, but only with so-called topics (the game dictionary words). So you have to declare the who column to be a column of topics:

[code]
Table of Suspects
who (topic)
“Professor/Plum”
“Mrs White” or “White”
“Mr/Green”
“Mrs Peacock” or “Peacock”
“Miss/Scarlet”
“Colonel/Mustard”

[/code]On the other hand you can’t print topics, so you will need another column of text that corresponds to the different topics and which you can print instead of the topics.

[code]
Table of Suspects
who (topic) name (indexed text)
“Professor/Plum” “Professor Plum”
“Mrs White” or “White” “Mrs. White”
“Mr/Green” “Mr. Green”
“Mrs Peacock” or “Peacock” “Mrs. Peacock”
“Miss/Scarlet” “Miss Scarlet”
“Colonel/Mustard” “Colonel Mustard”

[/code]Note also that topic words mustn’t contain interpunction like full stops or commas!

All in all, it might be more convenient to use indexed text in the table and use a phrase that implicitly converts the player’s command to indexed text before it is compared to the table entries. (Ordinary text can only be compared wholesale, I think, with an “if <text 1> is <text 2>” syntax.)

[code]
Table of Suspects
who (indexed text)
“Professor Plum”
“Mrs. White”
“Mr. Green”
“Mrs. Peacock”
“Miss Scarlet”
“Colonel Mustard”

Last after reading a command:
repeat through Table of Suspects:
if the who entry matches the text the player’s command, case insensitively:
instead say “And might I ask where [who entry] did the deed?”;
instead say “Let’s keep to the usual suspects, shall we.”.

[/code]The syntax here is “<indexed text 1> matches the text <indexed text 2>”: note the words “the text” in the syntax for indexed text matching; it makes the difference from the syntax for matching snippets with topics.

Nice! The third way is definitely the one I’d prefer personally. So, to reference the player’s command as if it is text in the context of a given activity, just preface it as “the text” the player’s command (and make sure the item on the other end is indexed text too). Thank you! Your example also provided a good, simple syntax example for how to finish after the loop if no matches were found, which is something else I haven’t tried myself yet, and now I know.

As a follow up question: in your second example you have some syntax like “Mr/Green”. What does this syntax accomplish, and how does it differ from ‘“Mr” or “Green”’?

Inform tries to convert to indexed text as needed. It isn’t specifically the words “the text” that does the trick; I only meant to draw the attention to the difference between these two pieces of syntax: 'if matches ’ and 'if matches the text ’ (since I tend to forget about it and end up trying to use the simpler syntax in both cases). The explicit way to convert the player’s command to indexed text is 'After reading a command: let T be indexed text; let T be the player's command;' . There’s more on indexed text in Ch. 19 of the Manual. And more on snippets somewhat hidden away in section 17:31 on the Reading A Command Acitivity.

That’s syntactic sugar, I guess. I don’t think it differs from ‘“Mr” or “Green”’. You can only use it while dealing with so-called topics, though – like in Understand Statements: ‘Understand “get in/on” as entering.’ It’s not for use with text or indexed text. See Ch. 16 (especially 16.12 and 16.13)

Revisiting the text vs snippet questions… I hope that a response I get to this question will finally help me figure out the difference between a text and a snippet and how to work with the two (currently I just have noob anger that the two are different, and wish I could just compare and contrast the two freely):

Let’s say I want to add to the below code…

Table of Names
name "indexed text"
"Peggy"
"Sue"

Last after reading a command while character-prompted is true:
	repeat through Table of Names:
		if the name entry matches the text the player's command, case insensitively:
			say: "What about [name entry]?";

… some more code that will allow the player to enter the command “Peggy-Sue”, and instead of adding a record “Peggy-Sue” to the table, have the code “figure out” that you can combine two of the names from the table into that combination and separate it with a “-”. I have not even attempted to write pusedo or noob code for this, as I am at a loss.

A snippet is a number that identifies a part of (a certain stretch of words in) the latest player’s command.
“Appendix B”, i.e. the commented version of the I6 Templates, explains it thus:

This, of course, is nowhere near a general answer to the question as stated, but the easiest way to make the game recognize “Peggy-Sue” as well as “Peggy” and “Sue” would be:

[code]

Table of Names
name (indexed text)
“Peggy-Sue”

Last after reading a command:
repeat through the Table of Names:
if the name entry matches the text Player’s Command, case insensitively:
say “What about [name entry]?”.[/code]
And, if you want the form of the name in the response to match the form of the name in the player’s command:

[code]

Table of Names
name (indexed text)
“Peggy-Sue”

Last after reading a command:
repeat through Table of Names:
if the name entry matches the text player’s command, case insensitively:
say “What about [player’s command in title case]?”.[/code]

Does this mean I can’t understand or convert a snippet to a form that can be compared to an indexed text without learning or using I6?

I was hoping there was an answer, in I7, for taking the player’s command, and converting it verbatim into a text so it can be used later. I notice now I had some syntax errors in my example above, but what I meant to ask wasn’t to put “Peggy” and “Sue” into one record together with a “-” in the table, but to leave them separate and have some code “piece them back together as compared to the player’s command”. I think everything I’ve tried myself is so wrong I didn’t post anything, but let me try some noob/psuedo code again to try to illustrate what I’m asking again:

Table of Names
name (indexed text)
"Peggy"
"Sue"

Last after reading a command while character-prompted is true:
	repeat through Table of Names:
		if the name entry matches the text the player's command, case insensitively:
			say: "What about [name entry]?";
        repeat through Table of Names:
                Let T be indexed text;
                Let T be the player's command;
                Let X be indexed text;
                If T includes the name entry:
                         if T does not match the name entry:
                                   Let X be "[the name entry]-";
                                   repeat through table of names:
                                           if X + name entry matches the player's command:
                                                   say "What about [X + name entry]?";

Again, some of the above is not correct I7 code, because I don’t know what the correct code would be. Essentially, I want to first check if there is an exact match… that part apparently is easy as you described it before. The second repeat is the part that I am at a loss with… what I want to do is check if there is a partial match, where if the name entry is included in, but not the entirety of, the player’s command, then I want to trigger a series of events that try to figure out if the player’s command could be a hyphenated name. In those events, I want to compare the player’s command to the name entry and additional information…

Essentially, this would be so easy as strings in an object oriented language. I was hoping there was the equivalent for a snippet something like .ToString() in a C-based langauge, where a text might be analogous to a string. I have to admit I am still a little frustrated that I don’t know how to retrieve a player’s command as a “string”. That’s really the point of this exercise for me, is to try to sort out how to manipulate and convert the player’s command into something useful and comparable with other text directly.

The player’s command (a snippet) can be stored directly to an indexed text variable; the system does the conversion automatically. You almost have this part right already.

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	say "... '[T]'."

The rest can be done pretty easily with the phrase “if T1 matches the text T2”, where both parameters are indexed text. You’d want the table to contain indexed text.

However, it looks like you’re going down a rabbit-hole of technical infrastructure which has little to do with making a game happen. Yes, you can set up a system to automatically recognize “Peggy-Sue” when “Peggy” and “Sue” are already in the table. Or you can just add “Peggy-Sue” as a synonym, and that will be faster both in coding time and execution speed.

Aha! Ok, so basically the majority of the problem was that I was using “let” when I should have been using “now”… whoops. OK, so now I know how to convert snippets into indexed text. Phew.

I realize this may not be a good way to go about it, and this probably won’t make it into any actual game of mine. As always, this is just a tinkering learning device. I was trying to come up with a scenario that would necessitate the conversion. Now that I have the conversion made, I see I may have a new problem. It seems to my noob eyes that “matches” or “includes” doesn’t apply to indexed text, only to snippets… is this correct? To again use other languages as an example, I would hope that there is some equivalent of .Contains() or .indexOf() to apply to two indexed texts:

psudocode:

if(thePlayersCommandIndexedText.Contains(theNameEntryIndexedText)) {
foo;
}

//or

if(thePlayersCommandIndexedText.indexOf(theNameEntryIndexedText) != -1) {
foo;
}

I ask because this inform code that I would think approximates the above doesn’t work:

Table of Names
name (indexed text)
"Peggy"
"Sue"

After reading a command:
	let T be an indexed text;
	now T is the player's command;
        repeat through Table of Names:
                  if T includes the name entry:
                           say "It's a partial match!";

It seems that and indexed text cannot “includes” another indexed text? Or am I making another simple noob error somewhere?

Don’t apologize – read the documentation.

The phrasebook tab shows what’s available to manipulate indexed text. Also, the manual, e.g. section 19.5.

Well, two things about that… reading the documentation end to end doesn’t really “stick”, I have to have an actual problem to solve to best remember what I’ve learned. I’m not against reading the documentation myself, I may have given that impression, but I need to find and read a section of it that is relevant, not the whole thing. I was unable to find the place in the documentation I was looking for… these searches, for example, failed to find what I was looking for:

Inform 7 indexed text includes
Inform 7 indexed text contains
Inform 7 indexed text vs snippet
etc.

The documentation isn’t quite an “API” documentation like you might find for C# where you can click a hyperlinked “Indexed Text” and find all the methods and properties that apply. Searching on various items seems to be woefully hit and miss. Again, not really complaining or saying the documentation sucks or anything, I couldn’t do anything remotely close to as good myself, but I’m very glad this forum is here because I’m not sure I could learn Inform by myself given the documentation.

Also, the other thing is now that you have pointed me to the correct information, I still seem to be having an issue that I can’t see the answer for in that page of the documentation. I tried modifying my code to this:

Table of Names
name (indexed text)
"Peggy"
"Sue"

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	repeat through Table of Names:
		if "[T]" matches "the name entry", case insensitively:
			say "It's a partial match!";

The above looks just like the example code on page 19.5 of the manual, but I get the problem that it says it can’t match the two because “the name entry” is a “topic”. I thought I labeled it an indexed text in the table, so although I thought this redundant I tried:

Table of Names
name (indexed text)
"Peggy"
"Sue"

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	repeat through Table of Names:
		let N be an indexed text;
		now N is the name entry;
		if "[T]" matches "[N]", case insensitively:
			say "It's a partial match!";

Yet, this too returns a problem stating that “N” is a topic, instead of treating it as an indexed text.

Edit, I see what I was missing:

Table of Names
name (indexed text)
"Peggy"
"Sue"

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	repeat through Table of Names:
		if "[T]" matches the text "[name entry]", case insensitively:
			say "It's a partial match!";

I was missing “the text” before “[name entry]”… I still wonder why that is necessary when it has already been declared explicitly that “the name entry” is indexed text. Should that have been intuitive and I missed something?

The problem with your first code (I bet) is that you wrote

"the name entry"

which is the string “the name entry,” which is getting interpreted as a topic. You need to omit the quotes:

the name entry

and then Inform will try to look up the name entry.

This probably isn’t much different from putting a function call or variable name in quotes in any other language.

Yeah, not being confident in the rest of it makes for some syntax mistakes.

Now I have it working… almost, all but one thing and one possible optimization thing left to ask on this one. My code below works, except for the very last condition:

Table of Names
name (indexed text)
"Peggy"
"Sue"

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	let N1 be an indexed text;
	now N1 is "nothing";
	let N2 be an indexed text;
	now N2 is "nothing";
	repeat through Table of Names:
		if T matches the text name entry, case insensitively:
			if N1 is "nothing":
				now N1 is "[name entry]";
				next;
			otherwise if N1 is "[name entry]":
				next;
			if T matches the text name entry, case insensitively:
				now N2 is "[name entry]";
	if N1 is not "nothing" and N2 is "nothing" and T exactly matches the text "[N1]", case insensitively:
		say "What about [N1]?";
	if N1 is not "nothing" and N2 is not "nothing":
		if T exactly matches the text "[N1]-[N2]", case insensitively:
			say "What about [N1]-[N2]?";
		if T exactly matches the text "[N2]-[N1]", case insensitively:
			say "What about [N2]-[N1]?";
	if N1 is "nothing":
		say "Who?";
	if T does not exactly match N1:
		say "Who?";
	stop the action;

‘if T does not exactly match N1’ doesn’t seem to work. Is there a way to check the negative on a “matches the text”? I think I’ve tried several variations of that syntax like ‘if T does not exactly match the text “[N1]”’ and possibly others, but they don’t seem to work. The intention of that last condition is to prevent reporting a partial match of a hyphenated name where one half of the hyphen is wrong, as in if the player’s command is “Molly-Sue”, the final condition there should return “Who?” but the whole thing should not first return “What about Molly-Sue?” because “Molly” isn’t in the table.

Also, is there a better way to indicate an indexed text is empty and reference that fact than setting it to “nothing”?

Basically, it’s because the phrase you’re using is literally named “(indexed text) matches the text (indexed text)”. In terms of more conventional programming languages, it’s as if you had two different methods, one named just matches() and another named matchesTheText(), which do similar but slightly different things.

You could just define your own phrase:

To decide whether (A - indexed text) does not match the text (B - indexed text): if A matches the text B, decide no; otherwise, decide yes.

Or, perhaps easier yet, just invert the order of the last two conditions in your example code.

The standard way would be to set it to “”, i.e. an empty string.

Ah… I had thought it was “matches(the text X)” or “matches(x)”… it makes sense why I was having trouble understanding it now that you clarified it is “matches(x)” or “matches the text(x)”… nice. I get the impression that knowing I6 would make a lot of sense of I7, but I was hoping to get to writing a story sooner than later haha.

That’s pretty neat that it is possible to create a phrase like that! I think some things are, maybe just barely, coming into focus for me about how these “phrases” work…

For the other solution, I am not sure what you mean by inverting the last two conditions… could you extrapolate on that?

I figured that, but left “nothing” in explicitly for the purpose of asking my question so it wasn’t ambiguous… but do you have to set it to “” explicitly either is what I meant. Rather, can you just say “x is indexed text”… and this already has set x to “”? It should be safe to do this and use later logic like ‘if x is “”’ etc.?

Another thing you can do is “Unless T exactly matches N1”.

Ah, the “Unless” solution works for all cases as is, but does require some, I think or what might in another language be, verbose of redundant phrasing. It does work though, thank you.

I have the whole thing working now, all cases considered and coded for. If you would like to look at the below and see if it could be written in a more optimized way, I’d love to know. No cheating and just adding “Peggy-Sue” to the Table… I realize that’s the practical way to do this if the only three names in a real game were “Peggy”, “Sue”, and “Peggy-Sue”, but this is not a practical example of that scenario, but instead an exercise to test the player’s command for various possible outcomes, compare as text, and loop through tables, etc. as shown. If that way of going about it can be more optimized than what I wrote below, it would be very helpful to know.

Also, in vyznev’s solution, defining a new phrase for “does not match the text” worked… however, it didn’t seem to work automatically with “, case insensitively” appended to the phrase. How would one make that solution compatible with “, case insensitively” or other appended modifications?

After reading a command:
	let T be an indexed text;
	now T is the player's command;
	let N1 be an indexed text;
	now N1 is "";
	let N2 be an indexed text;
	now N2 is "";
	repeat through Table of Names:
		if T matches the text name entry, case insensitively:
			if N1 is "":
				now N1 is "[name entry]";
				next;
			otherwise if N1 is "[name entry]":
				if T exactly matches the text N1:
					break; 
				otherwise unless T exactly matches the text N1:
					next;
			if T matches the text name entry, case insensitively:
				unless N1 exactly matches the text "":
					now N2 is "[name entry]";
					break;
	if N1 is not "" and N2 is "" and T exactly matches the text "[N1]", case insensitively:
		say "What about [N1]?";
	if N1 is not "" and N2 is not "":
		if T exactly matches the text "[N1]-[N2]", case insensitively:
			say "What about [N1]-[N2]?";
		if T exactly matches the text "[N2]-[N1]", case insensitively:
			say "What about [N2]-[N1]?";
	Unless T matches the text " ":
		if N1 is "":
			say "Who?";
		Unless T exactly matches the text N1, case insensitively:
			if N2 is "" and N1 is not "":
				say "Who?";
	If T matches the text " ":
		say "Are you sure you spelled that right?";
	if N1 is not "" and N2 is not "":
		unless T exactly matches the text "[N1]-[N2]", case insensitively:
			unless T matches the text " ":
				say "That's complete nonsense.";
	stop the action;		

Actually, I slightly misread your code, so that probably why I sounded so confusing. Anyway, I just meant that, instead of:

	if T does not exactly match N1:
		say "Who?";

you could always invert the condition and write:

	if T exactly matches N1:
		do nothing;  [this would make more sense if you actually had something to do here]
	else:
		say "Who?";

or, as matt w suggested:

	unless T exactly matches N1:
		say "Who?";

Yes, the default value of the indexed text kind is “”.

Not very easily, but you can do it: see Chapter 11.14. “Phrase options”.

However, one further possibility I forgot to mention earlier (because I rarely use it) is that Inform 7 does allow you to use “not” to negate truth values, just like in conventional programming languages. So yet one way to write your condition would be:

	if not (T exactly matches N1):
		say "Who?";

It’s not a very “natural” way of writing a conditional (that is to say, it looks more like math or program code than English), but it works, and it may well be the simplest option in some cases. I think you could even omit the parentheses here, although they do make the expression less ambiguous and easier to parse both for Inform and for human readers.