Mines Ahoy is now playable and pretty much done. It was a fun journey. Ironically, a month and a half ago, I chose this project because I thought it would be quick and easy. I was cloning an existing, relatively simple game, Minesweeper. Of course, I haven’t been working nonstop on this. More like three or so concentrated chunks of time. Some interesting problems came up, and there was plenty of the usual debugging frustration. Yet, somehow I am just completely sure that it was worth it. Which is sort of a different experience for me. Very enjoyable.

Updates related to ironing out bugs and other topics appear after the break.

Update 8/29/08

Added a timer. In the process, I finally did something with protoypes (not the library, the Javascript language feature). I had been avoiding that. I think should add a lot to the game. Next up on the agenda is writing some php to keep track of high scores, which is a somewhat more ambitious task. I hope the high scores won’t all be people cheating with firebug or something similar. Then again, who would actually care enough to do that?

Update 8/24/08

I feel compelled to say something more about the performance advantage in Opera for my particular application over FF. As I noted before, Opera is much better at generating obscenely large boards, ones that no one would ever play (hmm, maybe I should do one just because I said that), such as 30×30, 50×50, and 100×100. Now I have also noticed a large gap in how much quicker the revealing behavior is on Opera. It flies through a 50×50 with a smaller number of mines (150). On a 100×100, the algorithm proceeds to the point where the browser complains about “too much recursion” in a much shorter length of time on Opera (for both, they throw in the towel after revealing somewhere around 3000 or 4000 tiles).

However, it would be a hard sell for me to convince to switch to Opera on this basis, since almost no one wants to play a game that big anyway, and one rarely encounters javascript this resource-intensive on the internet. I was about to switch myself, except that I like Firebug better than the developer tools in Opera and I couldn’t find the equivalent of FireFTP for Opera (this was really the killer — quality FTP client built into the browser).

Update 8/23/08

I rewrote the whole thing with the jQuery javascript library, to try something different from Prototype. jQuery is advertised as light-weight, and I can tell. It feels like there are many fewer methods than in Prototype. But it makes the code much more compact by combining a lot of tasks that would normally span multiple lines (if one had any intention of writing readable code) on to one line through “chaining.” The idea is that you grab some DOM objects from the page and put them into a jQuery object, which has a bunch of methods for altering the objects, navigating the DOM tree, etc. Every time you call a method of the jQuery object, a new jQuery object is usually returned, and then you can call a method of that object, and so on. Thus you start with a group of DOM objects and perform several tasks with them, all on one line. The downside is that you’re working at such a high level that sometimes it is inconvenient when you need to do so something that jQuery doesn’t have built-in.

One concern I have is whether jQuery is less efficient than Prototype. However, performance is acceptable on both my desktop and my iphone, and there may have been a little boost in performance when I switched from the readable version of jQuery to the minified version, which appparently runs more quickly.

The code is also just improved all around, I think, and more readable. Everything is pretty well commented. You can look at the code here.

Update 8/17/08

I realized using a “testing” class was redundant with the “reveal” class I already employ to change the background of the tiles to a lighter grey. Now “reveal” does both jobs. John informed me that the control key, which I was using as the shortcut for flags, is apparently reserved for something else in a Mac environment, so now the shortcut is the shift key. Nic alerted me to the fact that at a more typical resolution than the one I’m using (1024×768 vs 1680×1050), it’s inconvenient having to scroll back and forth from the controls to the game. Thus I made a simple change, floating the two parts of the page to the left so they appear side-by-side, but I’m not sure how much of an improvement this is. I think I might try something fancy with Scriptaculous. I should mention I played two games on medium on my Iphone, though I guess on that platform the user’s expectation is to have to do a bit of scrolling.

The larger problem is that this still doesn’t work with IE. I took a first step in redoing things with Prototype methods by using the getValue method to see which difficulty the user has selected. Alas, IE reports that input elements do not have this method. So even with the aid of Prototype, it seems like I’ll need to spend some time to get this game working in IE. I’m leaning toward not bothering, since almost everyone I know uses something other than IE (primarily FF).

I would also like to mention what I discovered when I tested on Opera. It flew! I was under the impression that Opera and Firefox 3 weren’t so far off in performance with javascript and rendering pages, but in the case of this web app Opera was a very clear winner. The biggest difference is in the extreme cases. Using my trusty Iphone as a stopwatch, I found that FF3 took about 12 seconds on my machine to generate a 100×100 game with 1500 mines (with a previously generated game of the same size needing to be cleared first), verus about 4 seconds and change on Opera. In case the Firebug extension was slowing things down, I had the developer tools open in Opera during the test. I repeated the test several times, and the results were fairly consistent. My system: Intel Conroe 2.4 ghz quad-core, 4 gb of ram, and Vista 64-bit. Both FF3 and Opera are 32-bit. Maybe I should start using Opera. At first glance, the developer tools do everything that Firebug does, except for highlighting the parts of elements’ layouts on the page when you mouse over them in the layout tab.

Update to the update: I’ve opted for the shotgun method, allowing the user a choice of any of three keyboard shortcuts, in the hope that at least one will work well on a given system.

Update 8/16/08

Problem solved! (I think.) I’m referring to the incorrect revealing behavior in FF/Safari, not the arduous task of getting the game to work at all in IE/Opera . This bug was a pretty intriguing one because sometimes the behavior was correct. It didn’t completely fail every time.

Here’s roughly what’s happening in the code:

A variable "safeTiles" keeps track of how many mine-free tiles
remain shrouded.
The user clicks a tile "x" without holding ctrl or being in
"flag mode."
If x is shrouded, is not flagged, and is free of mines:
Function safeTileClick(x) {
        Subtract 1 from safeTiles.
        If safeTiles = 0:
            End the game.
        Reveal tile.
        Count how many mines are in the eight adjacent tiles
        around this tile.
        If number of adjacent mines ≠ 0:
            Write number of mines in tile.
        Else:            <= (the case where adjacent mines = 0)
            For each adjacent tile x:
                safeTileClick(x)
}

In programming, this last line is what’s called recursion. If the user clicks a tile with no adjacent mines, then the function calls itself on each of the adjacent tiles in turn. A problem that arises is that two adjacent tiles, where both have no adjacent mines, will cause the function to endlessly call itself, which is undesirable.  To solve this, I add a css class “tested” to the tile the function is acting on, so that I can then have the function only call itself on adjacent tiles that lack this class (in other words, I leave a trail of bread crumbs so that I know where I have already been).

The bug that was causing the odd behavior was that I added the class “tested” if the tile had no adjacent mines but not if the tile had adjacent mines. I guess at the time this seemed reasonable to me, but what ended up happening was that the function called itself on the same tile multiple times. For example, when several tiles with no adjacent mines were adjacent to a tile that did have adjacent mines, the function got called on the latter tile once for each of the former tiles. With each call to the function, safeTiles decreases by one, so its value began to diverge from the actual number of mine-free tiles left to be revealed and the game would end prematurely.

Now I have changed the code (just copying and pasting a line) so that the “tested” class gets added to every tile that the function is called on. This way safeTiles does not go to 0 too quickly. It also should boost performance a bit, since there are fewer recursive calls.

Update 8/15/08

So a day of my friends testing it out has illuminated some problems. Apparently, the process of revealing tiles that starts when you click a tile with no adjacent mines is slightly off. Somehow I missed this issue in my excitement that it works most of the time. (It isn’t just with FF on Mac, John.) Also, I realized that I need to replace as many of the methods and such as I can with equivalents from the Prototype javascript library, which I had previously been using for just a few specific things (DOM interaction, $ and $$, etc.).  Before, for the purposes of of the web programming course I took back in spring, Prototype was nice because it made web programming easier. All our projects assumed a Firefox environment. Now I need to start using Prototype a lot more for the sake of compatibility. For example, you don’t even get a board in IE7 or, I’ve been told, Opera. It does work on Safari on my Iphone (although using that button is a pain — fixed positioning doesn’t work on the Iphone).