Abbreviations

i’d like to allow the player to use abbreviations, that is, if a character is named ‘mr. so-and-so’ or ‘dr. whose-its’.

the parser, though will split the input at the period.

seems like the simplest way to do this would be to split at “mr.” - so that, for instance, “give book to mr. johnson” would be parsed as “give book to johnson”, instead of 2 actions (“give book to mr” then “johnson”).

but i can’t find anywhere in stdlib where this can be changed or overridden.

is this possible?

1 Like

In my opinion, this goes against the expectations of modern parser-IF player. I would certainly not use periods in a name when typing input. To clarify, the following scenario is how I would have played a game:

> l
Office
It's an office.

Mr. Jones is here.

> ask mr jones about himself
“I'm Mr. Jones, the solicitor.”

Period in input is strictly for sentence termination for me. I think you need to change something deep in parser to overload its meaning.

Only because Inform gets it wrong by default!

5 Likes

agreed, but someone new to IF would almost certainly want to “give bowling pin to mr. smith” and it’s completely reasonable to do so.

i found a way to do it and, yes, it’s pretty deep in the bowels of the parser.

near the bottom of the (read parse act) predicate, you can insert:

(if)($Words contains sublist [mr .])(then)
		(split $Words by [mr] into $Left and $TempRight)
		(split $TempRight by [.] into $ and $Right)
		(append $Left $Right $Output)

		(parse commandline $Output with choices $ChoiceList)
		(fail)
		(endif)

just above:
(parse commandline $Words with choices $ChoiceList)

it removes the ‘mr.’ from the player input and still preserves the period in case the input is two sentences.

but it only removes it. there’s no way to check that the player has entered the correct honorific (i.e. mrs. for mr., dr. etc).

1 Like

You could delete only the period, and then have “mr” without the period be in the normal object vocabulary.

1 Like

but then multiple commands separated by a period wouldn’t work.

as an example below, i’m not smart enough or good enough with list manipulation to remove the period after ‘mr’ but not the one after ‘smith’, while still retaining ‘mr’

[give book to mr . smith . drop apple]

would be much easier with a stupid indexed array.

1 Like

This was an interesting problem. I have made some (not terribly efficient) rules to substitute arbitrary phrases. Here it is with an example scenario:

#player
(current player *)
(* is #in #office)

#office
(name *)     the office
(room *)
(look *)    It's an office.

#jones
(name *)		Mr. Jones
(male *)
(proper *)
(animate *)
(appearance *)  
            Mr. Jones is here.
(* is #in #office)

(perform [ask * about *])
	"I am Jones, the solicitor."

(perform [ask * about #smith])
	"She is my client."

#smith
(name *)		Mrs. Smith
(female *)
(proper *)
%%(descr *)		A nondescript animate human being.
(animate *)
(appearance *)  
            Mrs. Smith is here.
(* is #in #office)

(perform [ask * about *])
	"I am Smith, the mechanic."

(perform [ask * about #jones])
	"He is my solicitor."

%% These are not the same as the (rewrite $ into $) rule from the library.
%% That one is useless for our purposes, as it fires up after the user input
%% has already been split up by sentence ending periods in the
%% (parse action sequence $) rule.

(rewrite [mr .] as [mr])

(rewrite [mrs .] as [mrs])

%% Testing for cyclical infinite recursion guard
(rewrite [jones about mrs smith] as [smith about mrs jones])
(rewrite [smith about mrs jones] as [jones about mrs smith])

%%%%%%%%%%%%%%%%%%%
%% General Rules %%
%%%%%%%%%%%%%%%%%%%

(interface (make substitutions in $<Input into $>Output except $<Excluding))
%% $Excluding parameter is used as guard against cyclical infinite recursion,
%% by skipping rewrite rules that have already been used for transformation.
(make substitutions in $Input into $Output except $Excluding)
	(if)
		*(rewrite $A as $B)
		~($A is one of $Excluding)
		(substitute $A in $Input with $B into $InterOutput)
	(then)
		(make substitutions in $InterOutput into $Output except [$A | $Excluding])
	(else)
		($Output = $Input)
	(endif)

(interface (substitute $<Old in $<Input with $<New into $Output))
~(substitute $Sublist in $ with $List into $) %% Infinite recursion guard
	*($List contains sublist $Sublist)
(substitute [$Head | $Tail] in $List with $New into $Output)
	*(split $List by [$Head] into $Front and $Rest)
	(append $Tail $Back $Rest)
	(if)
		(substitute [$Head | $Tail] in $Back with $New into $NewBack)
	(then)
	(else)
		($NewBack = $Back)
	(endif)
	(append $Front $New $NewFront)
	(append $NewFront $NewBack $Output)

(parse action sequence $Input) (just)
	(make substitutions in $Input into $Words except [])
	(if) (split $Words by [. ; then] into $Left and $Right) (then)
		(parse action $Left)
		(rebuild scope)
		(parse action sequence $Right)
	(else)
		(parse action $Words)
	(endif)

%% To see the rewritten commands, for test purposes
(rewrite $A into $A)
	(log) $A

And here is a transcript from the debugger with actions on:

> look
[look]
ACTION: [look] (look around)
The office
It's an office.

Mr. Jones is here.

Mrs. Smith is here.

> ask mr. jones about mrs. smith. ask mrs. smith about mr. jones
[ask mr jones about mrs smith]
ACTION: [ask #jones about #smith] (ask Mr. Jones about Mrs. Smith)
"She is my client."

[ask mrs smith about mr jones]
ACTION: [ask #smith about #jones] (ask Mrs. Smith about Mr. Jones)
"He is my solicitor."

Edit: Added guard against infinite recursion when something like

(rewrite [mr .] as [mr .])

is defined in the source.

Edit 2: Slightly better infinite recursion guard. There are still ways to put the parser into infinite recursion, with cyclic rewrites like:

(rewrite [mr] as [mrs])
(rewrite [mrs] as [mr])

Edit3: And after much hair pulling and time spent on dead ends, updated code now also guards against cyclical recursion.

2 Likes

i’ll try that. you’re usually right.

a somewhat related question. i’ve been trying to get at this from a different angle and all i want to do is reverse a list.

so why doesn’t this work?

(program entry point)
                ($Input = [the quick brown fox jumped over the lazy dog])
                (log){\$Input = $Input}
                (reverse $Input $Output)
                (log){\$Output = $Output}

i’m running it in the debugger and the (reverse) predicate always fails. i’ve also tried brackets around every combination of $Input and $Output, but the debugger keeps telling me:

A query is made to ‘(reverse $ $)’, but there is no matching rule or interface definition.

1 Like

That example works for me:

> (restart)
The source code has been modified. Merging changes into the running program.
Program restarted.
$Input = [the quick brown fox jumped over the lazy dog]
$Output = [dog lazy the over jumped fox brown quick the]
Program terminated.
You can still enter debugging commands such as @help or @quit, as well as
arbitrary queries, including (restart) and (undo).
You may also press ^D to quit the debugger.
suspended> 

Something about (reverse $ $) in your stdlib.dg is changed probably.

Edit: About the other code, it works but now I think it is better to override the (parse commandline $ with choices $) and inject the substitution query in there, instead of in(parse action sequence $), because that one is a recursive rule and making rewrites at every recursion level is less than ideal:

(parse commandline $Words with choices $ChoiceList) (just)
	%% Before proceeding, save the current undo state:
	(if) (save undo 1) (then)
		(narrate undoing $Words)
		(stop)
	(endif)
	(if)
		(nonempty $ChoiceList)
		($Words = [$Index])
		(number $Index)
		(nth $ChoiceList $Index $Target)
	(then)
		(choose $Target)
	(else)
		(now) ~(allowing parse errors)
		(make substitutions in $Words into $NewWords except [])
		(parse action sequence $NewWords)
	(endif)

Also the following rule is no longer needed, cyclical infinite recursion guard also prevents sublist based infinite recursion anyway; with an added benefit that expansion rewrites would also be possible with the removal of this:

~(substitute $Sublist in $ with $List into $) %% Infinite recursion guard
	*($List contains sublist $Sublist)
1 Like

Technically, “Mr” is a contraction, not an abbreviation, so it should not be followed by a period. Unfortunately, Americans (and possibly the public at large) is not aware of this distinction and always spell it incorrectly. If you spell it correctly (without the period), then players will not be tempted to spell it incorrectly (with the period).

Just to clarify, a contraction is where letters are removed from the middle of the word and the last letter is the same as the original word. These do not use a period, hence Mr, Mrs, Miss, Dr, Ltd, St, Rd, Ave etc. An abbreviation is where letters are removed from the end of the word and the last letter is different to the original word, hence Prof., Co., fig., viz. etc.

“An entire country spells this incorrectly“ is silly. No, they spell it differently.

3 Likes