Showing posts with label arrays. Show all posts
Showing posts with label arrays. Show all posts

Thursday, April 4, 2013

using what I've learned

First off, hey, this is the 70th post of this blog. Not bad for something less than a year old, I think. Just goes to show how geeky I can be about taking apart an IF language!

Anyhow, I had been thinking that of all of my extensions, my NPC  pathfinding extension "findpath.h" probably had the most bad code, memory-wise, as it assigns every room two additional properties, which it clears between uses. That is not unlike my array-clearing code that caused that huge headache in Roodylib.

It's always interesting to look at code you wrote a year ago, as I found several parts of "findpath.h" useless. Among the changes:
  • Previously, before writing the directions to be taken to the applicable character's script, I stored it in a property for that character (something that I was replacing the whole character class to give each character enough open slots). Since the code only sets up one path at a time, I figured I could just store the steps in a regular array that all characters would use. I think I wrote the original code at a time that I was especially fond of property arrays.
  • The code used an included routine called PropertyCount that went through the given property array and counted how many elements had values. Now, this might still be useful somewhere, but the way my code used it, I found I could easily replace it with better usage of local variables. I also clipped some of my determining-which-exit-is-best code by using local variables better.
  • Instead of clearing the room properties, I now determine whether or not a room has been counted yet by using the already_listed attribute. I can't say for certain, but I thought there was a chance that using an attribute might leave a smaller memory footprint.
  • I replaced this finding-the-other-side-of-this-door-object code:
            if InList(a.d, between, a ) = 1
                a = (a.d).between #2
            else
                a = (a.d).between
    With this code:
            a = ((a.d).between #((a = a.d.between # 1) + 1))  
     Anyhow, that second thing, which I got off of CharMove or somewhere, might take a bit longer to read, but it does the same thing without having to call InList. Now, I don't know if calling InList really uses that much more processing power or memory or anything, but at least, when you are using the debugger, you won't have to step through those extra lines.

    So, all in all, findpath.h is a leaner, meaner machine now. It still has some of the same hang-ups. Like, it doesn't have awesome code for dealing with locked doors or anything, but even with that, I think I put it in a much more stable place (now, if there is no available path to the "prize", the code should shut down without printing anything embarrassing).

    So yeah, there's that. If you are curious about the two versions, the old version is http://roody.gerynarsabode.org/hbe/findpathold.h and the new version is http://roody.gerynarsabode.org/hbe/findpath.zip.

    Happy pathfinding!

Saturday, March 23, 2013

straight from the Hugo source

So I asked Kent Tessman about exactly what was going wrong when something like my ClearArray routine uses up all of the UNDO memory. He answered:
The way Hugo's undo currently works, it stores a stack of individual commands, and basically sticks a bookmark in where a player command would be. Sorry, but the first 'individual commands' I mean 'program statements' or 'program commands'. So when you assign a variable or -- as you discovered, a single array element -- it uses an undo slot. Now, there are lots of them, but the default (and essentially at this point standard) engine has an arbitrary limit to keep memory usage down.
So that'll be an interesting thing to keep in mind in the future. I then asked him if, memory-wise, array elements, variables, and property elements- and the setting of- are interchangeable. He answered:
For the most part.  I mean, basically what Hugo does is allocate a big chunk of bytes, and divvies it up.
 So I think the lesson to be learned from that is to not put all of your state-tracking changes in one basket but to split them up between arrays, property arrays, and variables. Whatever the case, most importantly, don't write code that sets many of these values needlessly.

Anyhow, I'll try to have a new version of Roodylib up soon.

Friday, March 22, 2013

more about what went wrong

So, let's share an example of memory-hogging code. This is the ClearArray routine that was sucking a lot of available memory out of Roodylib-using games:
routine ClearArray(array_to_be_cleared)
{
    local n,t
    for (n=0;n< array array_to_be_cleared[] ; n++ )
        {
            array array_to_be_cleared[n] = 0
        }
}

The problem was that I was using this with _temp_string every turn, and _temp_string has 256 elements, meaning that it goes through the loop 256 times. This all seems to count against the available memory.

The reason I wrote this routine in the first place was because of an instance in The Clockwork Boy 2 was because something was overwriting the end 0 bit of the current string, so the game kept printing until it got to the end of a previously-saved string. I thought, a-ha, I'll fix this by clearing _temp_string all of the time!

Of course, now I wish I had just fixed whatever was writing over that 0 bit. I can't remember what the code was like before, but in the meantime, I changed my PrintStatusLine code to not use ClearArray.

Instead of throwing ClearArray out altogether (although I might do it eventually anyway), I changed the loop to quit out as soon as the array has two empty elements in a row:

routine ClearArray(array_to_be_cleared)
{
    local n,t
    for (n=0;n< array array_to_be_cleared[] ; n++ )
        {
            if    array array_to_be_cleared[n] = 0
                t++
            else
            {
                array array_to_be_cleared[n] = 0
                t = 0
            }
            if t = 2
            {
                break
            }
        }
}

The main thing is, let this be a good lesson to not let your code loop more than it has to.

Wednesday, October 17, 2012

array utility routines

In the previous post, I talked about how, for a while, I tried to do a "multiple opportunity" version of my "windows of opportunity" opportune.h extension. The final version ended up using property arrays, but originally, I approached the problem with regular arrays. I kept on wanting to do something and would think, huh, is there a routine for that? I'd then remember there wasn't and then would write it. I had mixed success.

The Good:
routine ClearArray(array_to_be_cleared)
{
    local n
    for (n=0;n< array array_to_be_cleared[] ; n++ )
        {
        array array_to_be_cleared[n] = ""
        }

}
Sometimes, hey, I like to clear arrays. Nothing wrong with a routine that saves me some time.

The Bad:
routine AddArrayValue(arr, val)
{
    local i
    for (i=0; i< array arr[]; i++)
    {
        if array arr[i] = 0, ""
        {
            array arr[i] = val
            return i
        }
    }
}
The problem with this one is that it doesn't distinguish from successfully placing the value in element 0 or being unable to place the value in an empty slot at all. It'd be slightly more successful if I just changed it to a return-true-on-success/return-false-on-failure thing.

The Ugly:
routine InDisArray(arr, val)
{
    local i

    for (i=0; i< array arr[] ; i++)
    {
        if array arr[i] = val:  return i
    }
}
Bad pun aside ("in this array", get it?), this array-based version of InList has the same problem as AddArrayValue but is even more hampered by it, as returning-the-element-number is pretty important in such a routine. I could get around this by having element 0 return something else (like a constant called ZERO or the string "zero"), but it seems kind of dumb to make people remember this hack.

If anything, I think this all is just a good reminder why property arrays can be favorable to regular arrays in these kinds of instances, as property arrays start at element 1 and therefore avoid the element-0 problem.