A Weird Imagination

Devlog: Resistance: Avalon web app

The problem#

I had been playing a lot of the social-deduction game The Resistance (and the version with more roles The Resistance: Avalon) and running into the problem that many players had trouble remembering exactly what had happened in previous rounds. Between the fact that there can be several votes throughout a game of the The Resistance and the game can sometimes take up to an hour, it can be hard to remember how the votes went a couple rounds back, especially for teams that were rejected.

The solution#

I created a web app implementation of The Resistance: Avalon (source) using Django.

Read more…

Devlog: Sprit Island helper

The problem#

The board game Spirit Island has all of players playing more or less simultaneously, especially when acting on different parts of the map, but requires some bookkeeping to be kept among all of the players. For a normal game of at most four players, this isn't difficult, but the game has rules to allow combining multiple copies to a huge game. My friend group planned a 12-player game and we wanted to figure out how to best keep the game organized. (Unfortunately, we planned this game for April 2020 and it did not happen for obvious reasons.)

The solution#

I developed a web app called fear-tracker (source), so called because the main shared information to keep track of is how much fear each player generates in order to keep track of the correct total generated by all players. It supports entering the fear generated per-spirit and the data is synchronized among any number of devices, so there does not have to be an exact correspondence between players and client devices. It also keeps track of what the current phase is as all of the players have to agree on some synchronization points for when new information is revealed by drawing cards.

The details#

Read more…

Long Polling in Django Channels

The problem#

In a web app where the display should be constantly up-to-date, the client needs some way to get up-to-date information from the server. One of the simplest ways to do so is to regularly (every few seconds) query the server asking if there is new information. This involves making a lot of requests and is wasteful of bandwidth and processor time on both the client and server (the latter can be improved with caching).

If updates are rare, it makes much more sense for the server to notify the client when they occur, but HTTP is designed around the client making requests to the server, not the other way around. And, furthermore, the Django web framework (like many web frameworks) is built around that model.

The solution#

Of course, this is a well-understood problem and there are a wide variety of APIs and libraries to solve it discussed on the Wikipedia page for Comet. The main workarounds are WebSockets which is a very flexible technology for two-way communication in a web browser and long polling which is a simpler technique which involves merely having the server not answer a request immediately and instead wait until it actually has an update to reply with.

In the rest of this blog post, I discuss the changes I made to convert a Django-based web app that I originally wrote to use a basic polling pattern and hosted using uWSGI to instead use long polling and be hosted using Gunicorn/Uvicorn. I also cover nginx configuration including hosting the app in a subdirectory.

The details#

Read more…