[I7] stopping the parser from automatically choosing things

Consider the following:

[code]Test Chamber is a room.

Gordon is a person in the test chamber. The bucket is an open scenery container in the test chamber.
Gordon carries a gun. A flute is in the bucket.

Ganking is an action applying to one thing. Understand “gank [something]” as ganking.

Carry out ganking: say “Ganked.”

test me with “gank / get flute / gank”.[/code]

If I type GANK without specifying a noun, the game will make assumptions, based on some series of obscure, internal rules. Only if more than one object is equally likely does it ask me to specify what I mean:

Is there a way to nake the game always ask the player what she wants to gank? Put another way, is there a way to make the parser treat all possibilities as equally likely?

I have this horrible fear that what you have just asked translates into “Hey, can someone update Disambiguation Control to work with 6M62?”

Ha, yeah, I had a sneaking suspicion that this delves into the spring-loaded can of worms and razor wire that is the core of the Inform perser. I was kind of hoping maybe someone had at least figured out a clunky hack, since there is literally only one action in my game where I even care about this behavior.

1 Like

Oh that wasn’t so bad!

OK, include the latest version of Disambiguation Control and that will take care of it automatically. (And, er, you have to rewrite any Does The Player Mean rules you may have, but I find that Disambiguation Control rules work better anyway.)

ETA: And as I understand it, the clunky hack is to make sure that there’s always at least two things tied for first place, when you care about it.

ETA 2: Also, I didn’t test that new version beyond making sure that it compiles and that all the examples run (and that your test case works), so if something’s going wrong let me know.

Hooray! It works on the test case, hopefully with some tinkering it will work on my WIP.

And thank you, by the way, and all of the other people on that thread, for volunteering to work on a new extensions site. It’s a bummer when really helpful updates like this can’t be found.

Mostly you should thank the other people on that thread, because they’re doing all the work on the site!

And this time the reason it couldn’t be found was that I hadn’t done it yet. I had tried the extension with 6L62, got like thirty compilation errors, and given up, but this time I poked it a little more and realized that the issue was that there were a bunch of “no” and “yes” phrases which apparently have to be “decide no” and “decide yes” now. [Correction; they’re clashing with the rulebook outcomes from Ingold’s “bypass disambiguation” rules, which as he says don’t work, so I think my next thing will be to kick them to the curb so they don’t break innocent code. But I’ll wait till tomorrow so I can give the extension a different version number.] That was all it took. (But yes, it’ll be much easier to find this when it’s centralized on the new site.)

Ugh. It looks like Disambiguation Control doesn’t work with Unified Glulx Input. They both try to completely replace NounDomain – I doubt there’s any nice way to reconcile that, is there?

Blah. At least you got me to update Disambiguation Control.

So as far as I know, there’s no nice way. As someone who really has no idea what’s going on in the internals, what I usually do here is to compare the NounDomain in the original parser to the NounDomain replacements in the two extensions that are trying to replace it, because often there’s only a few places in which they differ from the original parser, so it’s not too hard to merge them into one NounDomain replacement. (This is why, whenever I have to change one of these things, I always put either my or the extension’s initials in the comments wherever I changed it, so they can be control-F’ed.)

Unfortunately, these two extensions may be too complicated for that to work. I think that maybe what’s going on in UGI is that NounDomain’s call to Keyboard is getting replaced with a call to ParserInput, but it looks a little more complicated than that. Also, using all of Disambiguation Control when you only want this little bit of its behavior, but figuring out where to put that into effect probably involves opening that spring-loaded can of worms and razor wire that you were talking about. I think maybe it’s the part about dont_infer?

I might try to have a look later (it’d probably be worth coming up with a version of DC that’s compatible with UGI, if possible), but not right now.

Having looked at the code a little more, the prognosis is bad, at least as far as me getting anything done goes. The relevant part of DC seems to be this:

[code]! Now, if there’s more than one choice, let’s see if we can do better

number_of_classes=0;

if (number_matched > 1)
{
(+list-outcomes+) = false; ! we set the list-writer to false and see if the outcomes can make it true again

! Now we run Adjudicate, which in turn runs ChooseObjects and the I7 routines
! these routines will score the options, and delete inappropriate ones

i=Adjudicate(context);

! Did we fail to get anything from Adjudicate?
if (i == -1)
{
	! If we're guessing, then there was nothing valid. So let's ask the player to explain themselves.
	if (guessing) 
	{
		if (indef_possambig)
		{
			if (parser_trace == 5)
				print "    [Failed to find anything using an ambiguous input.]^";
			rfalse;
		}
		jump Incomplete;		
	}
	
	! otherwise, if we weren't guessing, then what the player typed made no sense after all, so fail the line.
	rfalse;
}

  if (i==1)  ! A multiple object was matched. 
  {

	! If we're not looking for a multiple noun, then we have a fundamental problem
 	if (~~MultiContext(context)) 
		 print "[BUG in Disambiguation: Multiple object made it out of Adjudicate!]^";

	rtrue;

  }

}[/code]

where UGI has this:

! Now look for a good choice, if there's more than one choice... number_of_classes = 0; if (number_matched == 1) { i = match_list-->0; if (indef_mode == 1 && indef_type & PLURAL_BIT ~= 0) { if (context == MULTI_TOKEN or MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN or NOUN_TOKEN or HELD_TOKEN or CREATURE_TOKEN) { BeginActivity(DECIDING_WHETHER_ALL_INC_ACT, i); if ((ForActivity(DECIDING_WHETHER_ALL_INC_ACT, i)) && (RulebookFailed())) rfalse; EndActivity(DECIDING_WHETHER_ALL_INC_ACT, i); } } } if (number_matched > 1) { i = true; if (number_matched > 1) for (j=0 : j<number_matched-1 : j++) if (Identical(match_list-->j, match_list-->(j+1)) == false) i = false; if (i) dont_infer = true; i = Adjudicate(context); if (i == -1) rfalse; if (i == 1) rtrue; ! Adjudicate has made a multiple ! object, and we pass it on }

But to do exactly what Disambiguation Control does there, we need list-objects defined in I7, and we need some modifications that it makes to Adjudicate I think; which just seems awfully complicated. Looking around in Parser.i6t it sort of seems like a routine called BestGuess might be the thing that’s doing what we want to stop–at least, it’s the one that’s getting called after this comment:

! When the player is really vague, or there's a single collection of ! indistinguishable objects to choose from, choose the one the player ! most recently acquired, or if the player has none of them, then ! the one most recently put where it is.

but now I’m wondering why my living room is full of worms and razor wire.

Well, I did figure out a workaround – the equivalent of setting up a rule for supplying a missing noun while ganking, which simply tells the player that they must provide a noun. Not as elegant as I wanted, but it gets the job done.

Yeah, apologies for this - DC is really “a different parser”, to be honest, so won’t play well with anything else that’s acting at low-level.

jon