I thought that all I needed to resolve was dealing with the old algorithms. However, because running computer programs reveal only one error at a time, I found out that the dungeon-building code crashed the game because the code apparently tried to index a nil value. That burned me so much; I did not want to deal with the game until late at night, even though I fixed the previous problems early in the same day.
Because the dungeon-building code is based on my own implementation of the Recursive Backtracking algorithm, I decided to pick someone else’s implementation, instead. I ended up getting one from Rosetta Code. I then took my time adapting the code closer to my code style and integrating the code into my game. Subsequently, I brought the imported code to a separate cartridge because I wanted to make sure I understood the algorithm and got the algorithm right. I took this time in changing the all() iterator to ipairs() because all() is very slow, from what I have read at Lexaloffle. all() guarantees order in iteration, but this is a randomly-generated dungeon; the risk of iteration out-of-order would only add to the randomness in generation.
From what I expected, the adapted code broke, too. After doing more adaptions in light of the pico-8 environment, the pico-8 still got problems with nil values. Turned out that a constant table that had the corners needed to be renamed.
After the algorithm ran without a problem, I decided to try to get a dungeon preview. The problem is that trying to print only one character at a time led to the pico-8 printing one newline after character, which meant that my preview was just a column of wall characters. I could concatenate the characters, but, because the dungeon is generated, I would not be able to know what character goes next. Though I could put the characters in an array, I also found that the pico-8 does not print a newline after a character if I specify the screen position, which I can calculate from the sentinel values the algorithm uses when iterating over the rows and columns the dungeon structure has. After adjusting the positions, I got the preview.
However, that used an all-wall dungeon. Once I started using an actually-generated dungeon, the nil error returned. I decided to comment out all of the code, write a few lines of debugging code that mentioned the values certain variables had, then uncomment the code one piece at a time. I found that, because I used pico-8’s random-number generator instead of the one in the table library, I risked getting a value of 0, even though arrays in Lua start at 1 by default. Adding 1 to that value solved that problem.
I ran the generation algorithm, which ran without a hitch. However, the dungeon seemed to not have a wall perimeter despite there being code that specifically printed some. After inspecting and testing that the code ran correctly, I wrote new debugging code that printed the variables of any factor that could affect this mistake. I started by printing the dungeon’s dimensions then adjusting them accordingly. There was no correlation. I then tested the arguments that were fed to the walk() submodule, that is, the part that actually generated the dungeon’s path. (A positive side effect of this technique was that I separated into their own variables the complex calculations that went into walk(). ) After going through 20 test cases, I found that the dungeon had the wall perimeter only when the values were fed into walk() were both even. After writing code that made those values even, the generated dungeon now has a proper perimeter every time.
These changes did not work even when fed back into the main one. I tried hard to check how the code was different, even switching between the ipairs() and all() iterators, but to no avail. Turns out that, while copying the algorithm to the actual game, I forgot again about renaming the constant that had corners, since the game put all of the constants at the top of the source code… away from the algorithm which was closer to the middle.
The game now stopped whining about nil values.
What comes next… the game fails to switch from the title screen to the intermission screen, failing to set the variable that activates the intermission phase.
I want to take a break from this, too, until I figure out how to even define the problem.