Breaking up huge blocks of code

It’s time to break up some of my custom actions that have become quite complex and chunky…lots of IFs and Otherwises, and lots of Repeat through Tables…

It’s getting to the point where Inform is struggling to compile if I add any more IF’s to some of my actions.
Nothing wrong with the code in terms of syntax or errors; just too huge in one chunk it would seem.

So the question is:

How do you break up code in Inform?

Let’s say you have a custom action that has like 3 layers of IF’s… what’s the best way of breaking that out into manageable chunks Inform can process?

Can you have seperate ‘Instead of’ with the same name?

Example:

Instead of stealing:
	if there are no people in the location of the player:
		try taking the noun;
		
Instead of stealing:
	if there are people in the location of the player:
		say "OI! Put that back!";

instead of:

Instead of stealing:
	if there are no people in the location of the player:
		try taking the noun;
	otherwise:
		say "OI! Put that back!";

Obviously that’s a silly example as the IF/Otherwise will work fine and is a better way of doing it in that case, but it would help break up seperate IF’s for the same action.

Example:

Instead of stealing:
	if there are no people in the location of the player:
		try taking the noun;
	otherwise:
		say "OI! Put that back!";
		
Instead of stealing:
	if there are things carried by the player:
		say "You are carrying too much to take that right now!"
	otherwise:
		try taking the noun;

But then even if that was allowed, how does Inform know the order/priority to give those two actions?
Doesn’t seem ideal.

So, all that aside, what is the best way in inform to take a huge complicated IF and break it down into bite size chunks it won’t get its knickers in a twist over when compiling? lol

One of my custom actions is 142 lines deep for example, containing about 6 different repeat throughs, one after the other.

I guess I could define sub actions and ‘try’ them?

Example:

code nexting is an action applying to nothing.
Instead of code nexting:
     Repeat Through Table Two:
          If Entry Check Works:
              Do Next Task;

Then Instead of having a huge chunk:

Instead of Code:
     Repeat Through Table One:
          if Entry Check Works:
              Do First Task;
     Repeat Through Table Two:
          if Entry Check Works:
              Do Next Task;

It would be split…

Instead of Code:
    Repeat Through Table One:
       if Entry Check Works:
          Do first Task;
     Try Code Nexting;

Anyway, any help would be greatly appreciated! :slight_smile:

I prefer to let the rules sort themselves by sticking the conditions in the head:

Instead of stealing when someone can see the player, say "'Oi! Put that back!'"

Instead of stealing when the player carries something, say "You are carrying too much to take that right now."

Instead of stealing, try taking the noun.

As for the code nexting bit, it’s difficult to say without seeing the actual code.

2 Likes

in my case, however, it’s more complicated than my examples.
My bad for being overly simplistic in my examples.

My custom action IF’s are full of table entry comparisons and variable checks.

if this variable matches this table entry do conditional1, but if its not that but this then do conditonal2, but if its something else, do conditional3.
Those conditional actions as a result involve repeating through tables to set various things if true etc as well.
Now imagine a custom action that does that 8 of those, one after the other. lol

See how it gets complicated and chunky?

I understand. If you like, PM me and I’d be happy to have a look at it.

One example would be my ‘when play begins:’

It’s built on random generation each time you play, so I have a Table of Rooms, a series of tables of items (divided into if they are a weapon or tool or misc), a series of tables of people (divided into friendly or hostile) and on play beginning, distributes things throughout the map.

When play begins:
	Repeat with N running from 1 to the number of filled rows in the Table of Weapons:
		choose row N in the Table of Weapons;
		Let placement be a random number from 1 to 49;
		Repeat through Table of Rooms:
			if Room ID is placement:
				Move Weapon entry to Room entry;
	Repeat with N running from 1 to the number of filled rows in the Table of Tools:
		choose row N in the Table of Tools;
		Let placement be a random number from 1 to 49;
		Repeat through Table of Rooms:
			if Room ID is placement:
				Move Tool entry to Room entry;
	Repeat with N running from 1 to the number of filled rows in the Table of Misc Items:
		choose row N in the Table of Misc Items;
		Let placement be a random number from 1 to 49;
		Repeat through Table of Rooms:
			if Room ID is placement:
				Move Misc Item entry to Room entry;
	Repeat with N running from 1 to the number of filled rows in the Table of NPC:
		choose row N in the Table of NPC;
		Let placement be a random number from 1 to 49;
		Repeat through Table of Rooms:
			if Room ID is placement:
				Move NPC entry to Room entry;
	Repeat with N running from 1 to the number of filled rows in the Table of Enemies:
		choose row N in the Table of Enemies;
		Let placement be a random number from 1 to 49;
		Repeat through Table of Rooms:
			if Room ID is placement:
				Move Enemy entry to Room entry;

Already that’s quite a process in one chunk…now imagine that the player has the option to decide rather than random they want the distribution to be specific.

So now each repeat through has to check if its randomly distributing the thing, or putting it where it was originally defined.

Thats a lot of code in one block.

Each Repeat with N could be a separate When play begins rule.

I’d need to know what you mean by ‘struggling to compile’.

Do you mean - it compiles but takes ages? Or it doesn’t compile and throws an error you can’t get past? Or it throws errors that you can fix, but that are hard to tease out each time?

If you can follow your own code, you don’t necessarily need to rewrite anything. I mean, almost any code can be made more efficient somehow, but it doesn’t have to be if it works for you and runs OK.

If there are gross inefficiencies in runtime performance of the game, that’s potentially a more serious problem where you would benefit from programming optimisation (and knowing which things are making it slow to execute) but you didn’t say there are.

I know you pointed out this was a silly example, but again in terms of runtime performance, splitting this into two rules means Inform has to consider both rules every turn. If it’s one rule that deals with both cases, Inform only has to consider that one rule every turn. On its own, that’s nothing, but for instance if you program a whole, heavy game in a way where Inform has to check irrelevant rules unnecessarily, and there are masses of them, that could effect performance.

-Wade

it doesn’t compile…Translating the source failed…it says the code was fine but for some reason the compiler ran into a problem.

‘sorry for the inconvenience’

Sometimes, the difference between it compiling and not can be commenting out a single line, for example,
if i comment out [pause the game;] and it compiles!! lol
Uncomment it and it won’t.
Clearly that a) is a valid command that works on its own elsewhere and b) has no bearing on IF/ELSE structure as it’s a resulting action.

The fact I need to start commenting out things tells me the issue is the size of the code hence the need to consider how to split things out.

You wouldn’t want to do this by creating new actions, but by new To… phrases, e.g.

Instead of Code:
	Process Table 1;
	Process Table 2;
	...

To process Table 1
	 Repeat Through Table Two:
		  If Entry Check Works:
			  Do Next Task;

To process Table 2
	 Repeat Through Table Two:
		  If Entry Check Works:
			  Do Next Task;

To process Table 3:
	...
1 Like

Several ideas:

  • You could use "To … " phrases to break up code, for example like this:
To distribute weapons:
    [... your distribution code for weapons here]

To distribute tools:
    [...]

When play begins:
    distribute weapons;
    distribute tools;

See chapter 11 in the documentation (here’s a simple example in 11.2).

  • You could group some actions together to a new kind of action and write code for the kind, that might simplify things:
    See section 7.15 (Kinds of action) in the documentation.

  • You could create new conditions and adjectives (see section 11.16) to subsume several conditions.

But apart from these ideas, it’s also worthwhile to try to figure out a minimal example from your code which causes the compiler problem.

Yeah… I mean you’re suffering an annoying error. I sometimes get that one if I add a bit of Inform 6 code to my Inform 7 project (I’m basically a cut-and-paste-hacker regarding Inform 6).

With luck, you have a previously saved version that did compile, that’s not too far removed from the current one. Try adding blocks of your code from the crashing version back in one at a time to a copy of the previous version until you can make it crash again. Then you’ll know where the problem is.

-Wade

I think the issue is i’m using a fairly old version of Inform too.
The About Inform tells me its version 6L02, May 2014 lol

I would update but im scared to because of extension compatibility and having a set of I6 code as well that apparently doesn’t work in later versions…so its a case of putting up with old quirks!

I will play around with To… as thats a new one to me and does sound helpful.

Just to be clear, this specific example (“pause the game”) is not something that works out of the box - it requires the extension Basic Screen Effects by Emily Short. (You said that it works on its own elsewhere, so I assume you’ve got the extension included, but I thought I’d mention it just to be sure.)

Because the rules don’t have preambles they will be sorted in a random order (or maybe source code order, but treat it as if it were random.) And because you don’t tell it to “continue the action” only one rule will be run.

There are many ways in Inform to break up large blocks of code, but not many good generalisations. It really does matter what the specific code does.

And for performance you don’t want to add a lot of instead rules if you could add check/carry out rules, because the instead rules are considered for all actions, not just the action in question.

oh yea, I use pause the game’ throughout my game.
I definately have that extension included.

I mean’t more that it works when i use it elsewhere in other actions and such, so the fact that that is whats making the compiler fail just doesn’t make any sense other than Inform struggling.

Good to know. Thankfully im not using a lot of those as of right now.
But the ones I am using are quite sizeable as they check a lot of things/do a lot of things as a result.

What I AM using a lot of in my project though is custom command prompts so…a lot of various ‘After reading a command when command prompt is “such and such”’.

Hopefully they aren’t too taxing.

Hi ManchurianMan83!

There are a few things you can try if the compile fails. Inform 7’s compiler ni (stands for natural inform) may report more specific errors on the “Progress” tab. When you see a problem report, the report opens on the “Report” tab. If you change to the Progress tab, can you tell us what Inform shows (you can copy-and-paste it)?

Take a look at some open source Inform 7 games which have lots of code for ideas. I recommend Kerkerkruip.

There are internal limits in the Inform 7 compiler which can be adjusted for large projects. Here are the settings from Kerkerkruip:

Section - Increase memory settings

Use MAX_PROP_TABLE_SIZE of 800000.
Use MAX_OBJ_PROP_COUNT of 256.
Use MAX_STATIC_DATA of 1000000.
Use MAX_OBJECTS of 1000.
Use MAX_SYMBOLS of 50000.
Use MAX_ACTIONS of 250.
Use MAX_LABELS of 20000.
Use ALLOC_CHUNK_SIZE of 32768.
Use MAX_NUM_STATIC_STRINGS of 40000.
Use MAX_DICT_ENTRIES of 2000.

You can copy-and-paste those settings into your own Inform 7 story then try to build again to see if it helps the compiler.

1 Like

To… has definately been a big help.

Not only has it allowed me to break up the Instead action that was otherwise causing the compile issue, but it’s enabled me to put certain frequent code I was otherwise reusing in various other actions into one area.

such as:


To check player dead:
     if current health of the player is less than 1:
          say "Your Adventure is over!";
          Play the sound of GameOver;
          Now GameOver is true;

Rather than having that ‘if check’ in every possible case where the player might die, I can just ‘check player dead;’ in it’s place.

I shall keep those Memory Settings in mind Zombie if I need them.
I would post my compile error report but so far, it’s not erroring right now.

If it crops up again, I will do so.

1 Like

You might want to think about going to 6L38. 6L02’s entire reign was from April to August of 2014 when 6L38 was released to fix some 150 bugs in 6L02. The changelog’s description of non-bugfix changes from 6L02 to 6L38 is very short.

6G60 to 6L02 was the big extension-breaking jump; 6L02 to 6L38 should be the easiest jump. (And you might want to throw in the Friends of I7’s 6L38 patches too.)