Lode Runner 4K

Here is a new entry http://elmkom.tripod.com/cgi-bin/l.pl it is a Lode Runner clone (first 4 levels).
Use the arrow keys to move. Use , and . to dig. Escape to exit.
Collect all the gold and reach the top to advance to the next level.
Avoid the guards.

Plays great! Though I couldn’t move up the ladder to switch from level 2 to 3 even though I had taken all the gold on the map. I also found it to be a tad bit to easy. Your AI would probably be harder if the enemies kept going up/down if they were on the same y-coordinate as you but couldn’t close in on their x-coordinate.

Really nice! Plays great. =)

Nice game!
Some notes about it:

  • You need to collect all the gold to pass level?, but you must collect 1+gold_view_in_screen to pass level. Maybe by design but it’s confuse.
  • If you are trapped in a dig you make you must diw when the wall reappears but the game hangs.
  • If you make 2 digs one after the other, a bad-boy fall in one of the digs and you fall in the other the game throws a java.lang.ArrayIndexOutOfBoundsException: 433.

Yes I should kill the player if they fall in a hole. (why are you falling in holes :)) I will try to squeeze it in.
If you reach the top and can’t go to the next level it means that one the of the bad guys has some gold. You must trap him in a hole to make him give up the gold.
Yes I had to keep the AI simple to get it in 4K. The algorithm is like this.

If(player above) find nearest lader
if(player below find nearest lader or edge to jump off
if(player on same level) try to close X

As you pointed out the try to close X is not smart. Do you have any suggestions on how to make it a bit smarter with out adding too much code.

I think carefully in the question:

  • The most effective way is to add some backtraking to search the best ladder to reach player. Probably from player so you solve all the directions of all the enemies in “one step”. But, yes, this add some code.
  • Other solution: remember last lader used by each enemy and check if the level of the enemy continue bellow/above the level of player for some amount of time/ticks (or distance of player, or some sort of this). Then use another lader when search for the nearest lader. Not sure if this works.
  • One more solution: add areas to the map definition.Imagine you add 8 bits x cell. Each bit indicates an area in the map. So, you check the player cell and determines he is in the area 3 (3th bit set). Then you known the emeny must go to the lader that have a 3th bit in its cell to reach the player. This reduces the number of levels (but compression must do its job and finally the bytes diff must be minimal).
    Good luck :wink:

Thanks for the ideas. I have fixed the exception and now kill the player if he gets stuck in a hole. I have not yet had a chance to see if I can rework the AI. I would still appreciate if any one familiar with maze games has a good path finding algorithm for the enemy to find the player.

I also got stuck trying to go from level 1 to 2. I got all the gold, walked up the ladder, but my character wouldn’t go up high enough aparantly and I couldn’t advance to level 2.

Are you sure you got all the gold. There are 6 sacs of gold on the first level. The top right guard normally picks up one of the sacs at the start of the game. You must trap him in a hole for him to give up the gold. An easy check is that your score if you have not been killed should be 600 to advance to the next level.

Ahhh now I see! Ooo that makes the game much more fun taking advantage of the digging. I played through the levels a few times. I’m very pleased!

Cool. One of my most favourite games at Commodore 64. :slight_smile:

Yes it was one of my old favorites too. I actually have all 140 levels I just can’t fit them all in. It takes about 70 bytes per level. I have tried many ways to compress the levels. But the best I have found is to not do any compression just store the level data as a string, one character per tile and let the compression do the work. This is a 416 byte string (26*16) that gets compressed to ~ 70 bytes. There are 10 unique characters in the string. So for example a level would look like this.




level[1]=
         "                 H        "+
         "    G            H        "+
         "XXXXXXHXXXXXXX   H        "+
         "      H----------H    G   "+
         "      H    XXH   XXXXXXHXX"+
         "      H    XXH         H  "+
         "     EH    XXH       GEH  "+
         "XXHXXXX    XXXXXXXXHXXXXXX"+
         "  H                H      "+
         "  H          E     H      "+
         "XXXXXXXXHXXXXXXXXXXH      "+
         "        H          H      "+
         "      G H----------H  G   "+
         "    HXXXXX         XXXXXXH"+
         "    H        P  G        H"+
         "XXXXXXXXXXXXXXXXXXXXXXXXXX";


If any one has any good ideas on how I could get better that 70 bytes per level I would love to hear.

you could store the levels as compressed PNGs and parse those. I know I keep pointing to this example and need to update it, but it would be something similiar to this: http://woogley.net/misc/RisseN/ - yes, the code is very old :wink:

anyway just save the levels as PNGs, load them via ImageIO, and read each pixel on the image to get your level data. i.e. a red pixel (0xffff0000) could be a ladder piece, a blue pixel (0xff0000ff) could be a floor piece, etc …

I haven’t tested this method on a 4K game but it’s worth a try. It might not work because I have heard inline Strings compress pretty decently, so it’s a bit of a toss-up. If you don’t mind me seeing the source I could help you write the method to do it. (woogley[at]gmail.com).

btw nice game so far :slight_smile:

[quote=“woogley,post:13,topic:25898”]
That would probably be far worse than the string method. Not only do you have the overhead of the PNG header, but you’ll also be storing a lot more bits per value than is necessary. And the fact that the file will already be compressed will negatively impact the ZIP compression of the JAR file. Not to mention all the extra code that would be needed for decoding.

I think the solution he has right now is probably best. The only other possibility is to bit-pack the level, but I don’t know if that wouldn’t again defeat the compression.

A quick analysis suggests the following unique values in the map: "EGHX-P "

That’s 7 possible values, meaning that the board could be packed into 26x16x3 bits. (1,248 bits total) Dividing by 8, we arrive at 156 bytes per level. Since he has so much empty space, the bit packed version may be highly compressable. Someone would have to run some tests to find out.

One optimization that can be done with both the String and the Bit Packed versions is to eliminate the arrays. Since you know that the level data is always 26x16, there’s no reason to create a separate string for each level. Just pack all the data into a single super-string, then compute the offset for the level you wish to load. You should see decent savings uncompressed (fewer constant pool entries, less string string overhead, fewer array accesses, etc.), and even better savings compressed (the unbroken stream should be easier for the compressor to work with).

before you read this reply, just know I’m not familiar with bitpacking :stuck_out_tongue:

anyway I read one of your posts (or maybe it was the wiki) about inline Strings compressing decently, so I tried it.

I’ve been these clouds as a background for my 4K game:

http://woogley.net/misc/4K/clouds.gif

I figured I’d try the whole String thing, so I compressed it to this one String

however I found that just keeping the GIF instead saved more bytes than trying to inline the data inside the class file (17 bytes to be precise, so it was close). I have 3 image files and I tried inlining them all into my one class file - though it did compress pretty well, the JAR that simply used GIFs turned out to be smaller.

so, in my particular case, using images is smaller. it just goes to show you should try all possibilities.

something to note though, as I said before, I’m not familiar with bitpacking, so it is very possible that the String I made just isnt small enough. Do you know a better method to inline that image? do you have a tutorial for bitpacking? Im always open to learning something new :wink:

I’m getting a 404 on those links. Are they uploaded yet?

[quote]however I found that just keeping the GIF instead saved more bytes than trying to inline the data inside the class file (17 bytes to be precise, so it was close). I have 3 image files and I tried inlining them all into my one class file - though it did compress pretty well, the JAR that simply used GIFs turned out to be smaller.
[/quote]
It’s hard to say without knowing what data you’re packing, but there are a few things I can say:

  1. You’re probably not reducing your information in any significant fashion. Just changing the format is no guarantee of better results.

  2. Whenever you change your compression method, it’s always important to include the decoder into the computations. When I use SuperPackME, I’m accepting a fairly hefty cost in the code for the image decoder, but I more than make up for it in the space saved in the images. I did some tests with oNyx’s JetPack game last year and found that the low number of images he used combined with the low number of colors meant that SuperPack (not the ME version) would actually be larger.

Keep in mind that you’re wrestling with the theory of information. If you don’t fully understand how your data is stored, it can be difficult to further reduce it.

[quote]something to note though, as I said before, I’m not familiar with bitpacking, so it is very possible that the String I made just isnt small enough. Do you know a better method to inline that image? do you have a tutorial for bitpacking? Im always open to learning something new :wink:
[/quote]
Bitpacking is a simple concept. There are 8 bits in a byte, right? So let’s say you have an image that only has two colors. If you store it as a PNG, the PNG will store 4 bytes (32 bits) per pixel. That’s a lot of wasted space for only two values! But if you look at each bit as a color, then you can pack the image into 1 bit per pixel. Here’s the results for a 320x200 pixel image:

PNG: 320x200x32 = 2,048,000 bits = 256,000 bytes
Bitpacked: 320x200x1 = 64,000 bits = 8,000 bytes

Does that help explain the concept? :slight_smile:

since we’re kinda hijacking this thread, could you continue the bitpack discussion here :stuck_out_tongue:

Thanks for the input. I have already tried the bit packing route. But the added cost of the decode and the lose in the compresion ratio (once packed it no longer compresses as well) makes it worse off. The suggestion to put all the strings together is a good on. It could save a few bytes I will give it a try. It just looks like I can’t beat the default compression. I also looked at trying to represent the data as a set of sparse arrays. For example the P character only apears once per level and the E and G only 4 to 5 times. So I thought I could just store there x y locations instead. But this also was not any better than the simple string method.

I have just uploaded a newer version of lode runner 4k. http://elmkom.tripod.com/cgi-bin/l.pl

I have changed the levels to more challenging ones. You now need to think a bit more to solve the level. If you get stuck the ‘a’ key can be used to abort the player and start the level over. There is now also status at the bottom on how many bags of gold have been collected and how many remain. The guards feathers also change color if they have a bag of gold.

Let me know how the new version plays.

Ps. If java webstart does not load the new version just hit the link again. It needs two load attempts for me to get the new version.

Well I had a lot of fun with the other levels, and I was looking for something a little more challenging, but I think you went a bit far on “making you think” more. I can’t get past the first level. That one should be the second or third, it’s very difficult and it’s easy to mess up such that the only option is to start over. If the other levels are like that it’s ok, but the first should still be something of an introductory level. My opinion-ish anyway.

I’ve only been trying for about 5-10 minutes though, I’ll see if I can figure this out…