Conglomerating similar very long functions from similar games: code review-ish question

Thanks, yes, they are open source – but I’m very worried there’s a lot of code to parse through.

So it only feels fair for me to do all the dirty work I can before you all see the relevant bits, so you can focus on the relevant/meaningful differences.

And also, your advice was a BIG help for a couple bottlenecks, so it’s quite possible there will be nothing to share. Realizing rulebooks could be empty helped push a few things ahead.

Plus I also know we’re all working for free here, so I don’t want to turn this into a “FIX MY MESSY CODE PLEASE” sort of thing" … and I created the chunks of similar code on my own initiative without planning. So if I can’t figure everything out for myself, I want to make it as likely as possible someone can walk in and say “Oh, you can just change THAT.”

In any case, if I am able to figure things out myself, I’d like to provide at least github commits to show what I did, so if anyone wants to do the same sort of thing in the future, they can. It feels nontrivial, and I’m probably not the first or last person to have to do this.

TLDR history of how this happened

The TLDR history is that I cut and pasted code from the first game (Very Vile Fairy File) to the 2nd (Quite Queer Night Near,) an EctoComp Petite Mort game, and then I added special cases to #1 and cut stuff from #2 so it would compile. And then the 3rd had some special cases that didn’t fit into #1 at first, so I cut and pasted and added stuff from #1, because I was putting out a post-comp release and didn’t want to have to deal with anything breaking.

And by that time I’d pasted code from #3 to #4 and #5 because each of those had their own wrinkles. I just needed to get stuff to compile before a deadline!

1 Like

You could set a global before following the verb-checker rule that is then checked within the rule to determine whether it should run a given bit.

Looking at the whole source, I was wondering whether the innards of that repeat loop might better be its own rulebook… but it looks like the issue is Inform’s inability to pass around a table row. You could make a kind of object called pseudo-row with properties corresponding to each column, and then create a pseudo-row based rulebook. Loading it up would be 15 tedious lines of code, but then you’d have the flexibility of rulebook preambles to control what runs.

1 Like

Or you could use a bit of I6 to hack around that limitation. I think this might be a case where that’s worth doing.

2 Likes

Is there a way to do it without the ugliness of choosing a row (to satisfy the compiler, which balks at a rule or phrase using the foo entry without a choose row) and then setting the row id?

Table of Spam
code
"Z"
"Y"
"A"

To decide which K is the (name of kind of value K) in question: (- parameter_object -).

when play begins:
  repeat with i running from 1 to the number of filled rows in the table of spam begin;
    follow the rb rules for i;
  end repeat;

to set the row id to (n - a number): (- ct_1 = {n}; -)

rb is a number based rulebook.

rb:
choose row 1 in the table of spam;
set the row id to the number in question;
say code entry;

This works but you’d need those two lines of code at the start of each individual rule.

I was thinking an alternative for “choose row N in T” that uses a global variable (or perhaps a rulebook variable), which is set at the beginning of the rulebook.

I’m still not seeing how one gets around the compiler itself balking at the use of entry without a choose row (unless you’re replacing entry with something else, too).

Ah, yeah, you’d have to replace that too, and that’s a huge pain because afaict it’s defined by the compiler rather than any extension.

1 Like

I think I may be missing something here: what does this I6 hack do that this standard I7 doesn’t?

rb is a number based rulebook.

rb a number (called N):
choose row N in the table of spam;
say code entry;

Mmmm… nothing. Something like it would have value if you were working with rows found by lookups by anything other than row number, to avoid repeated linear searches of the table, and I’m afraid I tunnel-visioned on that case.

Do you mean by passing the current row from one rule to another? Like with:

To decide which number is the current row id: (- (ct_1) -).

Follow the rb rules for the current row id.

Ha, easy-peasy lemon-squeezy. We can have a [column] entry equivalent phrase and forget about choosing a row altogether.

To decide what K is the (tc - value of kind K valued table column) column entry for/of (row-num - a number) in/from (tbl - table name):
(- TableLookUpEntry({tbl}, {tc}, {row-num}) -).

Table of Spam
code    num
"Z" 1
"Y" 5
"A" 25

To decide which K is the (name of kind of value K) in question: (- parameter_object -).

when play begins:
  repeat with i running from 1 to the number of filled rows in the table of spam begin;
    follow the rb rules for i;
  end repeat;

rb is a number based rulebook.

rb: say the code column entry for (the number in question) in the table of spam;
say the num column entry for (the number in question) in the table of spam;

rb: say line break;

when play begins:
  repeat with i running from 1 to the number of filled rows in the table of spam begin;
    follow the rb rules for i;
  end repeat;
2 Likes

The only thing you can’t do with this is set the values. But you can accomplish that with a new “change the ___ entry for ___ in ___ to ___” phrase.

Still not sure what extra lifting the ‘x in question’ is doing compared to …(called x) …? Perhaps because I still haven’t grasped the exact problem all this is intended to solve- if the row number is known and can therefore be passed to the rb rulebook as a number?

Not much… it lets you not say (called x) over and over in each rule. One can do that if one prefers…

Since parameter_object is a global, you could also hardcode it into the entry-selection phrase to make life easier on the end user.

Easy enough… (changed the syntax to include row)

To decide what K is (tc - value of kind K valued table column) column for/of row (row-num - a number) in/from (tbl - table name):
(- TableLookUpEntry({tbl}, {tc}, {row-num}) -).

To set (tc - value of kind K valued table column) column for/of row (row-num - a number) in/from (tbl - table name) to (v - K):
(- TableLookUpEntry({tbl}, {tc}, {row-num}, 1, {v}) -).

(Apologies to @aschultz if I thread-jacked. It’s on topic if you view it as what now seems like a viable means to replace the body of the repeat loop in your verb-checker rule with following the rules of a rulebook, which would let you split it up into rules and to express most of those conditionals as rule preambles.)

2 Likes

I’m thinking, for this case, this might be good:

The rb rulebook has a number called row-id.
rb a number (called n) (this is the set row-id rule): now row-id is n.
The set row-id rule is listed first in the rb rules.

[ now other rules can just use `row-id` ]
rb:
let x be the code column for row row-id in the table of spam;

Sure, but for something like this I don’t think there’s much benefit to making the author type that every time. Just store the table name and row number in global variables in the “first” rule, then have a phrase that consults those globals that can be used in every rule.

Imo Inform’s greatest strength is its readability, and when this phrase won’t ever be used with any parameters except “row-id” and “table of spam”, we can boost readability by removing them from the invocation. Like how the Standard Rules define “carried” and “worn” as equivalent to “carried by the player” and “worn by the player” to improve readability in the most common case.

1 Like

No problem with this … sorry for the delay in responding! There’s so much to process, I may not get to it right away, and also I wanted to re-release major fixes for everything on 11/22 because, well, reasons. So more in-depth stuff like has to slide compared to immediate testing and fixes, but I feel understanding this can help me still grow and learn Inform after many years of using it.

It wasn’t until relatively recently that I used rules acting on a direction or number or whatever, so I have so much to learn there.

And I was hoping to give a roll up response to this, but I’m surprised how much time I need to digest this all – and I appreciate everyone who’s stopped by with suggestions and requests. I had a feeling my code did the job but was a bit long. Making it smoother was a holy grail, but after a brief perusal, it seems so much more achievable now.