how and when does I7 guess which indirect article to use?

Well, I blundered through a whole bunch of things by trial and error, and I finally got something to apparently compile… but the story pane is blank and gray. That seems like it shouldn’t happen.

Here’s what I have right now, spoilered for ugliness:

[spoiler][code]The Lab is a room.

An animal can be honest or dishonest. Understand the honest property as describing an animal.

Before printing the name of an animal (called beast): say "[if beast is dishonest]dis[end if]honest ".

The unicorn is an animal. It is honest.
The yak is an animal. It is dishonest.

A block is a kind of thing. It has a number called weight. The description of a block is “It looks to be about [weight of the item described in words] pound[s].”
After examining a block (called B):
now the printed name of B is “[weight of B in words] - pound block of [B]”.

The yttrium is a block. The weight is one.

The uniform is wearable. The description is “It’s a United States Army uniform.”
After examining the uniform for the first time:
now the printed name of the uniform is “United States Army uniform”.

A unicorn, a uniform, an hourglass, a yak and yttrium are in the lab.

[Matt’s code - additions noted]

[create a global variable to be called later in i6:]
[Current vowel sound is a number that varies. Current vowel sound variable translates into i6 as “vowel_sound”.

Before printing the name of a thing (called x):
let T be a text;
now T is the printed name of x;
now Current vowel sound is T evaluated.
[say Current vowel sound.]

To decide what number is (s - a text) evaluated:
if s starts with a vowel sound:
decide on 1;
decide on 0. ]

To decide whether (string - a text) starts with a vowel sound (this is vowel sound checking):
let the first word be punctuated word number 1 in string;
if the first word is a word listed in the Table of Words That Start With Vowel Sounds, yes;
if the first word is a word listed in the Table of Words That Don’t Start With Vowel Sounds, no;
if character number 1 in the first word is a vowel, yes;
no.

To decide whether (letter - a text) is a vowel:
if letter exactly matches the regular expression “a|e|i|o|u|A|E|I|O|U”, yes;
no.

The initial sound rules are a rulebook. The initial sound rules have outcomes vowel and consonant.

An initial sound rule (this is the basic initial sound test rule):
if “[short name storage]” starts with a vowel sound:
vowel;
otherwise:
consonant.

To say the/-- short name storage:
(- PrintShortNameStorage(); -).

Include (-

[ PrintShortNameStorage len i;
len = StorageForShortName–>0;
for ( i = 0 : i < len : i++ )
{
glk_put_char_uni(StorageForShortName–>(i + 1));
}
];

-)
.

Table of Words That Start With Vowel Sounds
word
“hour”
“hourglass”
“honest”
“yttrium”

Table of Words That Don’t Start With Vowel Sounds
word
“uniform”
“unicorn”
“united”
“United”
“one”

[end]

Include (-
Global vowel_sound = 0;
-) after “Definitions.i6t”.

Include (-

Constant LanguageAnimateGender = male;
Constant LanguageInanimateGender = neuter;
Constant LanguageContractionForms = 2; ! English has two:
! 0 = starting with a consonant
! 1 = starting with a vowel
[ LanguageContraction text result rv;

!!! This is the old routine:
!if (text->0 == ’a’ or ’e’ or ’i’ or ’o’ or ’u’
!or ’A’ or ’E’ or ’I’ or ’O’ or ’U’) return 1;
!return 0;
!!! Out w/ old – in w/ new:
rv = FollowRulebook( (+ initial sound rules +) );
if ((rv) && RulebookSucceeded()) {
result = ResultOfRule();
if (result == (+ vowel outcome +)) return 1;
return 0;}
return 0;
];
Array LanguageArticles -->
! Contraction form 0: Contraction form 1:
! Cdef Def Indef Cdef Def Indef
"The " "the " "a " "The " "the " "an " ! Articles 0
"The " "the " "some " "The " "the " "some "; ! Articles 1
! a i
! s p s p
! m f n m f n m f n m f n
Array LanguageGNAsToArticles --> 0 0 0 1 1 1 0 0 0 1 1 1;
-) instead of “Articles” in “Language.i6t”.[/code][/spoiler]

What I did was to borrow the code that Text Capture uses to load the captured_text buffer into the “[captured text]” text substitution and used that to get something that will load StorageForShortName into the “[short name storage]” text substitution. Then I looked at the code the standard rules uses to call the Does the Player Mean rulebooks from inside I6 and did some similar stuff to call the initial sound rules, adding temporary variables to LanguageContraction until it compiled… which probably wasn’t safe. But I was just expecting some abject failures, not a gray pane.

Anyway, it’s pretty clear that I need to figure out how to get Inform 6 and 7 to talk to each other. I think one thing that may be going wrong here is that “text” is an input to LanguageContraction but my I7 code is just trying to look at StorageForShortName. What would be ideal would be to pass an I6 array to I7 as a text variable, but I suspect that’s not possible… I haven’t had much luck getting people to explain I6-I7 communication to me in this way, though.

The best I’ve managed for passing strings from I6 to I7 was to make a global I6 buffer, have the I6 code write into it, and make an I6 function which just printed the contents of that buffer. Then an I7 say-phrase would call that I6 function, so by calling that as a text substitution, the I6 buffer would be printed out into another I6 buffer which would be converted into an I7 string.

As you might guess from that description, I would NOT recommend doing this for a serious extension.

Well that’s basically what I was trying to do except much more clumsily–I copied the code from Text Capture that lets you get the captured_text buffer into “[captured text]” (for Glulx):

[ PrintCapture len i; len = captured_text-->0; for ( i = 0 : i < len : i++ ) { glk_put_char_uni(captured_text-->(i + 1)); } ];

except I pointed it at StorageForShortName instead. Probably a better way to do it, instead of trying to access StorageForShortName directly, would be to use BlkValueCopy to copy that into a global I6 buffer, and point my text substitution at that? I’m sort of guessing about BlkValueCopy because I noticed that when I defined a text-based rule the call to it got translated into I6 as

FollowRulebook(363, BlkValueCopy(I7SFRAME, TX_L_53), true);

So that may be what you have to do in a serious extension. Seems pretty suboptimal, though; passing strings between I6 and I7 should be simpler than this.

EDIT: Have improved things from a blank story pane to a memory access out of range error. Will, perhaps unwisely, keep tinkering.

OK, I have a concrete I6 question, I think. In the following code:

[code]Include (-

Array I6Buffer buffer 250;

[ PrintI6Buffer len i;
len = I6Buffer–>0;
for ( i = 0 : i < len : i++ )
{
glk_put_char_uni(I6Buffer–>(i + 1));
}
];

-).

Include (-

Constant LanguageAnimateGender = male;
Constant LanguageInanimateGender = neuter;
Constant LanguageContractionForms = 2; ! English has two:
! 0 = starting with a consonant
! 1 = starting with a vowel
[ LanguageContraction text result rv;

!!! This is the old routine:
!if (text->0 == ’a’ or ’e’ or ’i’ or ’o’ or ’u’
!or ’A’ or ’E’ or ’I’ or ’O’ or ’U’) return 1;
!return 0;
!!! Out w/ old – in w/ new:
SOMETHING GOES HERE TO TRANSFER “TEXT” INTO I6BUFFER
rv = FollowRulebook( (+ initial sound rules +) );
if ((rv) && RulebookSucceeded()) {
result = ResultOfRule();
if (result == (+ vowel outcome +)) return 1;
return 0;}
return 0;
];
Array LanguageArticles -->
! Contraction form 0: Contraction form 1:
! Cdef Def Indef Cdef Def Indef
"The " "the " "a " "The " "the " "an " ! Articles 0
"The " "the " "some " "The " "the " "some "; ! Articles 1
! a i
! s p s p
! m f n m f n m f n m f n
Array LanguageGNAsToArticles --> 0 0 0 1 1 1 0 0 0 1 1 1;
-) instead of “Articles” in “Language.i6t”.
[/code]

What should I put to copy “text” into I6Buffer? I thought it should be BlkValueCopy but that doesn’t seem to be working.

Actually, there is an extension that makes it possible to detect whether the printing the name activity is run to choose the article or for actual printing.

So you would write:

For printing the name of the hourglass: if the print-stage is article-choosing: say "ourglass"; [So the article will be "an"] otherwise: say "hourglass".
I don’t know if it’s relevant to what you’re doing, but I thought it could be useful.

Update: dfremont helped me solve the copying problem. I have something mostly working now.

The remaining problem is that it messes up on variable text substitutions, because the text substitution gets evaluated once when loading the results of the printing the name activity into StorageForShortName, and again when actually printing the name, which means that the string that Inform thinks it’s printing when evaluating the article might not be the same as the string it actually prints. This isn’t just a problem with my code but a general Inform bug.

Natrium, thank you so much for reminding me of that extension! I do want to try for a more general solution; if you know exactly what might get printed after the article, it’s not that hard to get the article right. I think you can set the indefinite article of the hourglass directly to “an,” or you could do things like what I did above:

The indefinite article of a cipher is usually "a[if the item described is open-woffle]n[end if]".

where we know that what gets printed first in the cipher’s name is the cryptotype, which will either be one-time, open-woffle, or Caesar. (We’re trying to make sure you get “a one-time cipher” and “an open-woffle cipher.”) But the idea behind that extension looks to be extremely useful for the things I’m looking at to take care of the substitution problem. I can’t figure out a way to do it directly for the I7 bug, but there’s an indirect way of doing it:

[code]Include Print Stage Detection by Taryn Michelle.

The cached preface is some text that varies.

Before printing the name of the traffic signal when the print-stage is article-choosing:
now the cached preface is the substituted form of "[one of]green[or]amber[or]red[cycling] ".

Before printing the name of the traffic signal:
say the cached preface.

Crossroads is a room. A traffic signal is in the Crossroads.

Test me with “l/l/l/l/l”.[/code]

I will have to think about whether I can use something like this to solve the general problem for my article-choosing code. I won’t be able to use Print Stage Direction directly, because my code also rewrites Articles.i6t, but I can incorporate its modifications of Articles.i6t into my modifications, and then maybe I can cache whatever gets written into “[I6 Buffer]” and spit it back out at the name-printing stage. Thanks again.

Hmm. Well, it’s working, but I’m not sure why it’s working the way it is.

With Print Stage Detection basically folded in:

[spoiler][code]The Lab is a room. North Lab is north of Lab. Gary is a man in North Lab. South Lab is south of Lab. “The south Lab.”

An animal can be honest or dishonest. Understand the honest property as describing an animal.

Before printing the name of an animal (called beast): say "[if beast is dishonest]dis[end if]honest ".

The unicorn is an animal. It is honest.
The yak is an animal. It is dishonest.

A block is a kind of thing. It has a number called weight. The description of a block is “It looks to be about [weight of the item described in words] pound[s].”
After examining a block (called B):
now the printed name of B is “[weight of B in words]-pound block of [B]”.

The yttrium is a block. The weight is one.

The uniform is wearable. The description is “It’s a United States Army uniform.”
After examining the uniform for the first time:
now the printed name of the uniform is “United States Army uniform”.

A unicorn, a uniform, an hourglass, a yak and yttrium are in the lab. An Æsop anthology is in the lab. An oenology text is in the lab. The printed name of the oenology text is “œnology text”.

Color is a kind of value. The colors are blue, black, brown, yellow, orange, red, violet, indigo, gray, and white.

A mood urn is in Lab. Before printing the name of the mood urn: say "[random color] ".
A mood ring is in the mood urn. Before printing the name of the mood ring: say "[random color] ".

[Matt’s code - additions noted]

To decide whether (string - a text) starts with a vowel sound (this is vowel sound checking):
let the first word be punctuated word number 1 in string;
if the first word is a word listed in the Table of Words That Start With Vowel Sounds, yes;
if the first word is a word listed in the Table of Words That Don’t Start With Vowel Sounds, no;
if character number 1 in the first word is a vowel, yes;
no.

To decide whether (letter - a text) is a vowel:
if letter exactly matches the regular expression “a|e|i|o|u|A|E|I|O|U”, yes;
no.

The initial sound rules are a rulebook. The initial sound rules have outcomes vowel and consonant.

To skip upcoming rulebook break: (- say__pc = say__pc | PARA_NORULEBOOKBREAKS; -).

First initial sound rule (this is the eliminate spurious line breaks rule): skip upcoming rulebook break.

Last before listing nondescript items when the number of marked for listing things is not 0 (this is the eliminate another spurious line break rule): skip upcoming rulebook break.

An initial sound rule (this is the basic initial sound test rule):
let temp be the substituted form of “[I6 buffer]”;
[say “(DBG: [temp])”;]
if “[temp]” starts with a vowel sound:
vowel;
otherwise:
consonant.

To say the/-- I6 buffer:
(- PrintI6Buffer(); -).

Include (-

Array I6Buffer buffer 250;

[ PrintI6Buffer len i;
len = I6Buffer->0;
for ( i = 0 : i < len : i++ )
{
glk_put_char(I6Buffer->(i + 1));
}
];

-)
.

Table of Words That Start With Vowel Sounds
word
“hour”
“hourglass”
“honest”
“yttrium”
“Æsop”
“œnology”

Table of Words That Don’t Start With Vowel Sounds
word
“uniform”
“unicorn”
“united”
“United”
“one”

[end]

[Include (-
Global vowel_sound = 0;
-) after “Definitions.i6t”.]

Include (-
Global short_name_case;

[ PrefaceByArticle obj acode pluralise capitalise i artform findout artval buflen;
if ( article_choosing ) { ! prevent reentrant calls from also attempting to choose an article, thereby disrupting article-choosing for the original object. (This is okay – they will get their turn to print as requested later on, during the name-printing stage for the original object.)
print (PSN__) obj; return;
}
if (obj provides articles) {
artval=(obj.&articles)–>(acode+short_name_case*LanguageCases);
if (capitalise)
print (Cap) artval, " ";
else
print (string) artval, " ";
if (pluralise) return;
print (PSN__) obj; return;
}

i = GetGNAOfObject(obj);
if (pluralise) {
    if (i < 3 || (i >= 6 && i < 9)) i = i + 3;
}
i = LanguageGNAsToArticles-->i;

artform = LanguageArticles
    + 3*WORDSIZE*LanguageContractionForms*(short_name_case + i*LanguageCases);

#Iftrue (LanguageContractionForms == 2);
if (artform-->acode ~= artform-->(acode+3)) findout = true;
#Endif; ! LanguageContractionForms
#Iftrue (LanguageContractionForms == 3);
if (artform-->acode ~= artform-->(acode+3)) findout = true;
if (artform-->(acode+3) ~= artform-->(acode+6)) findout = true;
#Endif; ! LanguageContractionForms
#Iftrue (LanguageContractionForms == 4);
if (artform-->acode ~= artform-->(acode+3)) findout = true;
if (artform-->(acode+3) ~= artform-->(acode+6)) findout = true;
if (artform-->(acode+6) ~= artform-->(acode+9)) findout = true;
#Endif; ! LanguageContractionForms
#Iftrue (LanguageContractionForms > 4);
findout = true;
#Endif; ! LanguageContractionForms

#Ifdef TARGET_ZCODE;
if (standard_interpreter ~= 0 && findout) {
    StorageForShortName-->0 = 160;
    @output_stream 3 StorageForShortName;
  article_choosing = true;
    if (pluralise) print (number) pluralise; else print (PSN__) obj;
  article_choosing = false;
    @output_stream -3;
    acode = acode + 3*LanguageContraction(StorageForShortName + 2);
}
#Ifnot; ! TARGET_GLULX
if (findout) {
  article_choosing = true;
    if (pluralise)
        buflen = Glulx_PrintAnyToArray(StorageForShortName, 160, EnglishNumber, pluralise);
    else
        buflen = Glulx_PrintAnyToArray(StorageForShortName, 160, PSN__, obj);
  article_choosing = false;
    acode = acode + 3*LanguageContraction(StorageForShortName, buflen);
}
#Endif; ! TARGET_

Cap (artform-->acode, ~~capitalise); ! print article
if (pluralise) return;
print (PSN__) obj;

];
-) instead of “Object Names II” in “Printing.i6t”.

Include (- Global article_choosing = false; ! flag to signal when printing to array for article determination -) after “Definitions.i6t”.

Include (-

Constant LanguageAnimateGender = male;
Constant LanguageInanimateGender = neuter;
Constant LanguageContractionForms = 2; ! English has two:
! 0 = starting with a consonant
! 1 = starting with a vowel
[ LanguageContraction text len result rv i;

!!! This is the old routine:
!if (text->0 == ’a’ or ’e’ or ’i’ or ’o’ or ’u’
!or ’A’ or ’E’ or ’I’ or ’O’ or ’U’) return 1;
!return 0;
!!! Out w/ old – in w/ new:
I6Buffer->0 = len;
for (i=0:i<len+1:i++) I6Buffer->(i+1) = text->i;
rv = FollowRulebook( (+ initial sound rules +) );
if ((rv) && RulebookSucceeded()) {
result = ResultOfRule();
if (result == (+ vowel outcome +)) return 1;
return 0;}
return 0;
];
Array LanguageArticles -->
! Contraction form 0: Contraction form 1:
! Cdef Def Indef Cdef Def Indef
"The " "the " "a " "The " "the " "an " ! Articles 0
"The " "the " "some " "The " "the " "some "; ! Articles 1
! a i
! s p s p
! m f n m f n m f n m f n
Array LanguageGNAsToArticles --> 0 0 0 1 1 1 0 0 0 1 1 1;
-) instead of “Articles” in “Language.i6t”.

Section - Adding pass-detection to the printing the name activity (from Print Stage Detection by Taryn Michelle)

To decide whether name-printing is choosing articles: (- ( article_choosing ) -).

A printing-stage is a kind of value. The printing-stages are article-choosing and name-printing.
To decide what printing-stage is the print-stage:
if name-printing is choosing articles:
decide on article-choosing;
decide on name-printing.

Section - Using Print Stage Detection

A thing can be variably-named. The mood ring is variably-named. The mood urn is variably-named.

The cached name is some text that varies.

Last after printing the name of a variably-named thing when the print-stage is article-choosing:
now the cached name is “[I6 Buffer]”;
[say “DBG: caching happened”.]

First before printing the name of a variably-named thing when the print-stage is name-printing:
rule succeeds.

First for printing the name of a variably-named thing when the print-stage is name-printing:
say the cached name.

First after printing the name of a variably-named thing when the print-stage is name-printing:
rule succeeds.
[/code][/spoiler]

Sorry the code is probably unreadable, it’s pretty much a palimpsest at this point.

The thing is that I’m not sure why I have to do this:

Last after printing the name of a variably-named thing when the print-stage is article-choosing: now the cached name is "[I6 Buffer]";

rather than use the substituted form of “[I6 Buffer]”. Using the unsubstituted form seems weird and risky, but if I use the substituted form it prints things like “…a œnology text and a ?nology text (in which is an gray mood urn) here” when it should be printing “a œnology text and a gray mood urn (in which is an orange mood ring) here.”

Anyway, something that’s working at all is cool–thanks for pointing me back to Print Stage Detection and saving me a lot of work!