Lode Runner 4K

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…

This is an easy change you could do which hopefully will improve things a bit:

if (crazyMode> 0) { crazyMode = crazyMode - 1 find nearest ladder or edge and climb up/climb down/jump down. } else { If(player above) find nearest ladder and climb up if(player below find nearest ladder or edge to jump off if(player on same level) { if(possible to close in on X) close in on X // It is possible to come closer on the X-axis, so do it! else crazyMode = 100 + random(100) // It is not possible to come closer on the X-axis, switch to crazyMode for 100 to 199 steps. } }
It will stop the enemies from getting stuck which is the most important part. It’s not a lot to change from your current code.

You may be right the new second level is eaiser than the first. I think I may take your suggestion and switch them around.
The key to the first level is not letting the left most guards get the gold at the left bottom of the screen if he does there is no way to trap him to get the gold back. The guards alway try to follow you so stay above them untill you can safely jump down and get the gold before them. Any other guard that gets some gold can be traped. For instance if a guard falls in the hole with the gold at the top. Just dig away the block at the side of the hole and make the guard follow you into the hole (it won’t look like a hole, but he will still get traped).

Good luck.

Thanks for the suggestion. Try the new version an see if you still think it needs tweeking. I have change the AI slightly. It is now 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 (even if it means falling off a lader or edge)

So now the guards don’t get stuck. But they may look silly jumping off a short ladder only to reclimb it and jump off again in and endless loop if the player does not move. But the new levels keep you moving so this is not so noticable. I will see if I can fit you suggestion in and see if it makes an improvement. What will add some code is that since in crazyMode the guard is no longer following the player. I will have to remember if they were going up or down a ladder and to continue in the same direction. Also when they finish climbing a ladder. What will stop them from finding the same lader as it will be the closest and just climbing back down. Now that I think of it, won’t your algorithm just make them climb up and down the same lader.

Well I tried the new 1st level and got beat up bad. One problem I noticed was in the empty square closest to the start with the gold bag. I fell in it, and none of the bots were smart enough to get up to me and chase me in, and I couldn’t figure out a way to restart. So I smacked all of the keys in hoping of finding a restart key, no luck.

:slight_smile:

Btw I figured out how to do the first level now. Actually I figured it out last night, just didn’t make a post. After trying a couple strategies and not being able to win, I finally realized you could dig a hole while climbing a ladder. Big help. :slight_smile:

[quote]Now that I think of it, won’t your algorithm just make them climb up and down the same lader.
[/quote]
True, my bad. It’s not as easy as that.

Here is the latest version of lode runner 4k. http://elmkom.tripod.com/cgi-bin/l.pl

I switched around some of the levels and inserted a new one to make the difficulty build up a little more gradually. So there are now 5 levels.

See if it seams more balanced now.

PS. If the title isn’t Lode Runner4k. Just hit the link again to get the fresh copy. Does any one know why you have to try twice to get webstart to realize the jar is out of date.

Just had to add that you’ve done a great job with this one! I’ve always liked Lode Runner though. :slight_smile:

Suggestion to add some sparkle: Make the background dark blue and have pixel stars scroll from right to left in the background (easily doable if you are using double buffering and are redrawing the entire screen on the backbuffer each time.). It was something I thought about adding to my Sokoban4k game but in the end I crammed in a couple of more levels instead.

I duno Donald, I think maybe you should cut maybe 4 or 5 levels and give us that extra sparkle :slight_smile: you’d be surprised how little things like that can increase the likeability (if that’s a word) :wink:

[quote]I duno Donald, I think maybe you should cut maybe 4 or 5 levels and give us that extra sparkle Smiley you’d be surprised how little things like that can increase the likeability (if that’s a word) Wink
[/quote]
Hm, you might be right. I guess no one will be disappointed if I decrease the number of levels from 95 to 85 anyway. :slight_smile: