Serial And Fix

Matt W says in a comment on dhakajack’s review of A Beauty Cold and Austere that it would be nice if ABCA allowed the serial comma when taking multiple objects. For example, allowing “take sword, lamp, and egg” and not just “take sword, lamp and egg.” He calls this the “Serial And Fix.”

How does one implement the Serial And Fix? Including “Use serial comma” in the source code only seems to affect output, not input.

After reading a command: Let T be "[the player's command]"; replace the regular expression ", and " in T with " and "; change the text of the player's command to T.
(See section 18.33 of Writing With Inform, Example 3e).

The specific code I was referring to was this I6 thing from Andrew Plotkin. Not sure what the comparative merits and demerits of jrb’s approach with that would be. (I’ve included this in a couple of projects as an extension called “Serial And Fix,” but I don’t think it’s actually downloaded under that name.)

Thanks, jrb and Matt W!

jrb’s code seems to work just fine, and I understand what it’s doing (Inform 6 still seems a bit too much like Deep Magic from Before the Dawn of Time to me), so I think I’ll go with that.

Just put Zarf’s code in the github. I include this extension in every project I do. Serial And Fix.i7x

Just include it and voilà.

I thought I remembered solving this problem once… thanks for finding it.

A regexp solution is always the slowest solution for any problem. It also blows away a layer of abstraction which you’d really rather keep. I.e.:

>GET SWORD, LAMP, AND EGG
You can't see any such thing.

>get sword,lamp,and egg
You can't see any such thing.

>get  sword,  lamp,  and  egg
You can't see any such thing.

You can fix all those cases by tweaking the regexp, but will you remember to?

As for efficiency, my I6 version works on the tokenized version of the input, which is an array of dict words rather than an array of characters. Much more efficient to check.

I7 doesn’t expose the tokenized form; it exposes the raw characters and a regexp package. So that’s what people naturally use. I understand that, but it gripes me.

I still don’t understand I6 well enough to I feel like I could successfully modify Zarf’s code to handle a similar problem, but for this particular problem you’ve convinced me that it’s a better solution: It’s cleaner, and it covers more cases. Thanks, Zarf.

And thanks, Draconis, for the suggestion of just making it an extension. I’ve done that, and it works beautifully.

I took this advice to heart and did some testing. It actually seems like

replace the regular expression "^(hi|hello)," in N with "say hello to";
saves some opcodes (13577) compared to

replace the text "hi," in N with "say hello to"; replace the text "hello," in N with "say hello to";
I don’t know if that is the exception that proves the rule.

Heh, testing is always good. :slight_smile:

I’m not surprised that the regexp package is efficient for what it is doing, i.e. string searches. Two separate string searches will be less efficient. So my brief rule isn’t very accurate.

What I should have said is more like “Don’t work at the character level if you can work at the dict-word level. Don’t work at the dict-word level if you can work at the object-and-action level.” But, again, I7 doesn’t give you any leverage on the dict-word buffer, so regexps are what people post in these threads.

So if I’m reading the Serial And Fix code correctly, what it does is check if consecutive dict words are comma_word and AND1_word, and removes the comma_word if so?

Pretty much. It walks through the input word by word, checking each word against the dictionary as it does so. If it finds the sequence of comma_word and AND1__WD, it overwrites the AND1__WD with spaces. Then if it removed any AND1__WDs, it calls the tokenizer again on the edited input, and updates a few global variables that depend on the number of words.