PlomRogue Development Blog

7DRL 2015, Day 1

On Sunday, two minutes before midnight, I started my 7DRL project. I registered it at http://7drl.roguetemple.com/ under the title "Please the Island God". Here's the description I entered:

You're stranded on an island. 
To leave, you must please the God that rules it. 
This God sees the island's animals and plants as its children. 
So hacking and slashing through the wildlife won't do … 

Here's how I spent the first day that followed:

Optimizing!

I kept optimizing my PlomRogue engine for speed. It started out much too slow (for reasons outlined in my previous posting). Granted, I develop on a relatively weak machine (an old netbook): My engine's speed may matter less for players on state-of-the-art computers. But to develop my game, I have to test it, too. And for this, my engine was below my minimum speed requirements. So some amount of speed boost felt necessary at the start of my 7DRL work.

But that speed boost was easy to achieve. Within three hours, I sped up my engine by a factor of six. Python's cProfile (see my last posting) helped me to identify critical bottlenecks. I read its dumps with runsnakerun, which produced outputs like this:

A screenshot of the "runsnake" program analyzing a cProfile dump.

This screenshot depicts the amount of time spent in various parts of my Python code. The highlighted block is the function init_score_map(). As the mouse cursor tooltip says, it starts at line 825 of my Python code, and 16.232 seconds were spent in it during the profiled test run. As the screenshot shows, init_score_map() encloses (calls) some other functions that eat up lots of process time.

This was the stuff I hunted for. I identified large blocks in runsnakerun's cProfile visualizations, and optimized them – by refactoring the Python code, or by outsourcing it to my compiled C library, libplomrogue.so. So, for example, I replaced this Python code (a list comprehension slowing down my server heavily) …:

        ord_v = ord("v") 
        ord_0 = ord("0") 
        ord_space = ord(" ") 
        for pos in [pos for pos in range(world_db["MAP_LENGTH"] ** 2) 
                     if not ord_v == t["fovmap"][pos] 
                     if ord_0 <= t["T_MEMDEPTHMAP"][pos] 
                     if ord_9 > t["T_MEMDEPTHMAP"][pos] 
                     if not rand.next() % (2 ** 
                                           (t["T_MEMDEPTHMAP"][pos] - 48))]: 
            t["T_MEMDEPTHMAP"][pos] += 1 

… with this Python code (note the preparation necessary to pass Python bytearray pointers to C!) …:

        maptype = ctypes.c_char * len(t["T_MEMDEPTHMAP"]) 
        memdepthmap = maptype.from_buffer(t["T_MEMDEPTHMAP"]) 
        fovmap = maptype.from_buffer(t["fovmap"]) 
        libpr.age_some_memdepthmap_on_nonfov_cells(memdepthmap, fovmap) 

… and this libplomrogue.c code:

extern void age_some_memdepthmap_on_nonfov_cells(char * memdepthmap, 
                                                     char * fovmap) 
{ 
    uint32_t map_size = maplength * maplength; 
    uint16_t pos; 
    for (pos = 0; pos < map_size; pos++) 
    { 
        if ('v' != fovmap[pos]) 
        { 
            char c = memdepthmap[pos]; 
            if( '0' <= c && '9' > c && !(rrand() % (uint16_t) pow(2, c - 48))) 
            { 
                memdepthmap[pos]++; 
            } 
        } 
    } 
} 

Conceptualizing!

I also spent some hours of the night making plans for my game mechanics. I won't go into details here. Writing this posting already eats up too much of my 7DRL time as it is. And I'll (hopefully!) get to talk about my game mechanics once I implement them.

Distribution, packaging, testing

One major problem with 7DRLs seems to be this: packaging them into a form that can be distributed to the world in good conscience. They may run easily on the developer's machine, but not on others. They may come with complicated dependencies on pre-installed frameworks, libraries, etc. A beautiful game may have evolved in the 7DRL's seven days – but, due to technical difficulties, few if any people apart from the developer will have a chance to experience it.

My PlomRogue engine (on which I build my 7DRL) will easily suffer from this problem. It expects a Unix terminal environment. In part, it's a Python script that won't run with many old Python versions. In part, it's C code that needs to be compiled in certain ways: dependent on the presence of certain library header files, and maybe specific oddities of certain versions of the GNU C Compiler. The C code is expected to be built with a non-standard build system, erlehmann's implementation of djb's redo. All these things create difficulties for making my 7DRL portable to systems that are not my own.

I decided to deal with these difficulties right at the beginning, on day 1. I put various tests for dependencies into my build and start-up scripts, and hints to prospective testers/players on how to satisfy these dependencies. I hacked some portability into erlehmann's redo scripts, so that they won't crash anymore on OS X systems. And I found some helpful testers to run my engine, and report their problems. I fixed all kinds of small portability issues.

As a result, I now feel better about distributing packages of my engine. It won't build or run on every system. But I can now tell more precisely on which systems (probably unixes with a Python of version >= 3.2.3, libc6 and ncurses library headers, and a gcc of version >= 4.7.2; llvm/clang masking as gcc on OS X also seems to work). And I slightly grew the number of systems it should run on hassle-free.

You, too, can test the PlomRogue engine package I use for my 7DRL. Download this file, unpack, and build it like this:

$ tar xjf 7drl_2015_day1.tar.bz2 
$ cd 7drl/ 
$ ./redo 

Lots of green lines of redo compiling C files should follow. If all went well, this should start up the engine's boring default game (after some seconds of waiting, maybe):

$ ./roguelike 

Error reports into the comments, please!

Comments

No comments on this page.

Write your own comment

Commenting currently impossible: Captcha not set.