LoCo Day 23

Today I finished the core server-side game logic, at least to the point of it passing the set of test cases I prepared earlier. Now the next big task is to connect the game to the web interface, so that it’s possible to actually play and see what’s going on.

Comments Off

LoCo Day 22

Today I implemented generation of the starting configurations of games. For now, all initial player positions are aligned along an invisible grid across the play area. It’d be nice to have more randomness in there, but that complicates things a bit more, since I still want to ensure players don’t start off too close to each other.

QuickCheck is great, but sometimes you have to be a bit careful with the set of function inputs you let it generate. In this case, I had to make the dimensions and grid spacing sized to prevent them from getting obnoxiously, impractically huge. I’m never going to try to create play areas measured in millions or billions of pixels on a side, or that have a grid spacing of similar magnitude. My starting configuration generator doesn’t work well in those extremes (by which I mean, it runs in to integer overflow problems), so it’s not worth testing them, especially if I’d have to contort my code to deal with those kinds of inputs.

Comments Off

LoCo Day 21

Almost no progress today; I neglected to set aside enough time from doing other things. I wrote a little more code to satisfy the tests I was working on earlier, but that’s about it.

If I were doing NaNo this year, and allotting the same amount of time I have been to this, I bet I’d be several thousand words behind at this point.

Comments Off

LoCo Day 20

Today I cleaned up the test cases I created yesterday. I simplified some of the things I was checking for, and as a result most of the tests had common functionality that I was able to pull out into separate top-level functions, which makes the testing code a lot more readable and helps prevent the type checker from going too far down the garden path if there’s a type error somewhere.

That done, I then started implementing some of the actual game-related code. Well, OK, mostly the JSON conversion code, but tomorrow I’ll tackle the real game stuff. The first thing I’ll need to figure out is how to properly generate a starting configuration for a game, making sure players are reasonably spaced out. I don’t know offhand what the generally accepted algorithms are for that, but I bet I’ll be able to find out after a brief bit of searching.

Comments Off

LoCo Day 19

More work on the actual game part of the game. Actually, most of that work was on coming up with good QuickCheck tests to check the yet-to-be-written implementations of the functions that process player input and step the state of the game through time. The fact that most of the game operations live in the STM monad complicates things a little, but I’ve (mostly) gotten the hang of writing monadic QuickCheck properties.

Comments Off

LoCo Day 18

Today I implemented the fundamental movement and collision detection logic for the game. It’s fairly simple, but I shouldn’t need to elaborate on it too much more when I implement the actual game on top of it. I also implemented a transactional queue to hold a player’s moves before the game processes them; if a player sends multiple moves in rapid succession, it’s possible they’ll arrive at the server faster than the game can consume them, one move per time step. Using a TChan doesn’t work, since it would retry the transaction if the queue were empty, whereas a player not having a move queued up is perfectly valid, and in fact would be the normal situation. My transactional queue (implemented as a queue wrapped in a TVar) simply returns Nothing if the queue is empty, which the game will then interpret as being no change in the player’s movement direction.

Comments Off

LoCo Day 17

Today I started implementing the core types for the game itself. They’re not yet connected to the rest of the program yet, so they’re only being exercised by the QuickCheck test cases for them. It is nice to be working in the realm of pure code again, at least until I get to the point where I need to start worrying about user interaction again.

Comments Off

LoCo Day 16

Today I got starting and ending games working. Each member of a room can signal when they’re ready to begin playing. Once everyone in a room is ready (whether it be because the last non-ready member became ready, or the last non-ready member left), and the room isn’t empty (in which case the first condition would be vacuously true), a new game starts. When it’s over, everyone becomes not-ready and the cycle begins anew.

Granted, the “game” that’s currently implemented amount to “wait five seconds for the game to end”. Woo. Sure, it’s more like a hole where an actual game can be put, which is sort of the point.

Since the game I have in mind is real-time and not turn-based, starting a new game requires starting a new thread, which will be responsible for periodically advancing the game state and sending messages to the room if anything interesting happens. Right now that thread just sleeps for a few seconds before ending the game, but it’s there. During a real game, players would affect the game state by asynchronously POSTing their moves, which the game thread would then be able to read at the next time step.

For a program being written in Haskell, I sure do have an awful lot of code living in the IO monad. I don’t think there’s really a way around this, though, since the multicast channels underlying my long polling implementation are based on TChans (so that requests have something to block on while waiting for messages), and the list of rooms is carried around inside an MVar (so multiple server threads can access it simultaneously). Most of the code I’ve been writing lately is directly tied to sending messages and/or manipulating a room, which pretty much forces IO. The game itself will have a bit of IO when it comes to queueing players’ moves, but it ought to be possible to make most of the game logic pure.

Comments Off

LoCo Day 15

Another day where I didn’t set aside enough time to get much accomplished. I addressed the problem of a user inadvertently getting unsubscribed from a room’s messages upon reloading the page by always (re-)subscribing them whenever they try to fetch messages. At worst, they’ll miss out on messages sent while the reload was taking place, but that’s reasonable.

I then started adding hooks for actually running a game out of a room. I got mostly through the code for letting members of a room signal when they’re ready to play. Right now, since there’s no actual game implemented, there’ll be a game-started message immediately followed by a game-over message once everyone is ready.

At some point I should write test cases for all the code that implements room-related stuff, but since it’s almost entirely within the IO monad, that makes coming up with good QuickCheck properties a nontrivial exercise. Doable, certainly — I did it for the multicast channel code, since there’d be all kinds of problems if that didn’t work correctly — but not nearly as easy as coming up with properties for pure code.

Comments Off

LoCo Day 14

Essentially no progress today, other than a little refactoring of the code I was working on yesterday. Clearly I failed to set aside enough time to work on things today.

Comments Off

LoCo Day 13

The overhaul of the room code is done, at least for now. Instead of there being only one room on the server, now any number of them can exist. Woo.

I think the subscribe/unsubscribe logic is going to need a change at some point, since even with the light amount of testing so far, I’ve uncovered some design problems:

  • If you reload the room page, there’s a race condition between the unsubscribe request sent by the unload handler, and the request for the actual page. Whether or not the browser gets re-subscribed for messages or not depends on the order the server processes the messages. Worse, since a non-subscribed session trying to fetch a room’s message always returns an empty list immediately (since there’s nothing to wait on), the browser starts hammering the server with long-poll requests. Subscribing needs to be made more robust; perhaps the act of trying to fetch a room’s messages should count as a subscription request too.
  • On Chromium, the page’s unload handler either doesn’t fire or doesn’t manage to send the unsubscribe request in time. Either way, the unsubscribe never happens. Presumably there’s a flaw in my JavaScript code that does this, but even then I need to automatically unsubscribe sessions from rooms if there isn’t any activity after a little while, which will be needed anyway in case a client’s browser drops off the net one way or another.

I’ll need to fix all that eventually, but for now I think I ought to work on the actual game part of this game I’m supposed to be writing.

Comments Off

LoCo Day 12

I restored the functionality I had before reworking the room code. The problem I mentioned yesterday was because I mistyped an identifier in the JavaScript code, and apparently using an undeclared and undefined identifier isn’t a problem as far as Firefox and Firebug are concerned. Contrast that with GHC, which not only flags that sort of thing as an error, but even offers suggestions as to which identifier you might have meant, sort of like suggestions in a word processor’s spell checker. Actually, it’s kind of surprising that GHC is the only compiler I’ve seen with that suggestion feature for undeclared identifiers. It seems rather obvious in hindsight.

I also fixed displaying of timestamps; now instead of showing an ugly complete UTC timestamp, the chat window just shows the time, converted to the browser’s time zone. Now that the polling fetches JSON objects instead of HTML fragments, that sort of thing is possible to do.

Now I’m working on adding support for having more than one room on the server. I expect this to occupy most of tomorrow’s effort too.

Comments Off

LoCo Day 11

I’ve almost got things working again in the current refactoring. The current sticking point is how the server now sends JSON-encoded messages to the browser instead of HTML fragments. This will be needed for implementing a game since there will be things sent during a game other than bits of webpage to display. However, my JavaScript-fu is pretty weak, so it’ll take a little more effort to figure out why things aren’t working on the browser’s side of things.

Comments Off

LoCo Day 10

Today’s roadblock came courtesy of the aeson package, or one of its recursive dependencies. I wanted to try using it instead of json to generate JSON, since the programmatic interface seemed a bit simpler and more elegant. Alas, one of aeson’s dependencies doesn’t work due to a bug in GHC. Also, possibly as a result of that same bug, the act of installing the package screwed up the rest of GHC’s package repository to the point where it could no longer find all the other packages that had been installed, and reinstalling them mysteriously broke other unrelated packages too. I finally had to nuke the whole thing and install all the packages I’m interested in from scratch.

Then, of course, I tried installing aeson again to see if maybe the repository corruption was a weird fluke. It wasn’t.

So, I sunk a lot of today’s development time messing with that. Needless to say, I’ve kicked aeson aside and went back to using json.

A third of the way into November, I must say I’m much farther behind than I expected I would be. I still haven’t worked on the actual game part of this game; it’s all been setup and infrastructure stuff. Sigh.

LoCo Day 9

Only incremental progress to report today. Shrinking the long-polling timeout from 60 seconds to 30 seconds seemed to solve the problem of Happstack killing handlers prematurely, and some of the Internals stuff in the Happstack documentation hints at being able to have some control over whether Happstack thinks a long-running handler needs to be killed or not. Worth looking into in the long run, but shortening my timeout is good enough for now.

Aside from that, most of today’s work was in formalizing the very hackish chat room code, converting it into a more general “room” concept that will better support layering a game on top of. The new code will also support having more than one room on the server. I hope to have that working tomorrow; the types are (mostly) implemented, but I still need to generate HTML from it and hook it into the handler logic.

Comments Off