Update 2: Making the Cutthroat Game

This post was originally published on Quora on January 1st, 2018.

Since my last update, a lot has changed. Almost immediately after I finished creating my little command line text game, I realized that this wasn’t what I had envisioned. It was playable, yes, but it was a single player game. I could play against a bot, but the bot was either too easy or too hard, and I couldn’t change the difficulty without going into the actual code and tweaking the numbers.

I changed gears a little and determined that the best path to proceed down was that of making a web application that allowed multiple players to connect and play a game. My plan was to have the server running, and once a player connected, a thread would be spun off, which would handle all the messaging between the game and the player through web sockets. The shared state would be the game instance. Before I dove in and began coding up this multithreaded game server, I came across another, newer way of creating a server — using asynchronous programming.

In Python3.5, asyncio was introduced as Python’s asynchronous programming library, Guido’s own version of twisted, or gevent. Using event-driven programming eliminated any need to design a multithreaded server — I wouldn’t have to think about race conditions or locks. I had never heard about asyncio before I decided to do this project, and I didn’t understand much of it even after I completed a working version of my asynchronous server. I felt a little underwhelmed because I really wanted to understand how it worked. I watched David Beazley’s talk on concurrent programming, as well as Raymond Hettinger’s talk on threading vs asynchronous, read many online articles on the subject, and after all that, I still don’t fully understand it. In a grossly oversimplified sentence, asyncio allows you to mimic concurrency by yielding control to another generator whenever you are waiting on a blocking call to finish. When the blocking call is ready, which is determined by select, control can shift back to that generator when the next yield is hit. So essentially, it’s like threading, but you get to choose when the context switches. And you aren’t actually using two threads; everything happens in one thread.

Okay.

So I decided to use asynchronous programming to create my server. How does it work? I use aiohttp, a great library that provides an asynchronous web server framework. When someone goes to the website, the static web page is rendered. Then, they enter their name and click “connect”. When they click “connect”, the client establishes a web socket connection with the server. The server acknowledges that a player has connected, and updates their client will all of the relevant information. Then, they have the option of joining an existing game or starting a new game. If they start a new game, a game instance is created and an asynchronous game loop is started. If they join an existing game, they get added to the game instance. Once the player is in the game, all communication is handled by the web socket asynchronously. Here’s a video of some gameplay:

The UI sucks!!!!!! I’m terrible at CSS and cool Javascript tricks, so please help me if you’re good at making websites look pretty!

I had some doubts about asynchronous programming, but they were pretty much all dispelled after I finished this version of Cutthroat. I tried up to 5 players connecting in 3 different games, and changes were pretty much instantaneous. Perhaps when there are more players, I’ll start to notice a performance hit. The tough thing about asynchronous programming is that you have to go all in. You can’t have any blocking calls, or else your program will hang. That means you can’t mix async and threading easily, because creating and joining threads is blocking. I’m honestly not really sure how this could scale.

During testing, I encountered a really puzzling bug. I used ngrok to expose my localhost port to the web, so that I could play with my other friends. The web socket was established, and their clients could send messages to my server, but my server couldn’t send messages back. This meant that their web page wasn’t updating, and they weren’t able to play. I switched to using localtunnel as an alternative to ngrok, and tried again. Everything worked for some strange reason. localtunnel and ngrok do exactly the same thing, so I’m not sure why the web sockets work with localtunnel and not ngrok.

Next Steps

  • Deploy this on heroku at some point. I’m not sure how to do that yet.
  • Update the UI…..
  • Make it possible to leave a game and join another game, or restart a game with the consent of the other players
  • Create a chat service so that players can chat with each other during the game or in the lobby
  • Institute the “turn” system where players take turns flipping over tiles.

Again, everything is open source — you can see my code on my Github!

Leave a comment

Design a site like this with WordPress.com
Get started