Civ Challenge Game Board (2020-)

Quick note: This article has a ton of passive voice and isn’t written incredibly well. I also wrote this article at 1 AM, so expect a solid amount of grammatical issues and text that doesn’t flow. You’ve been warned!

Another quick note: I’ll get some photos for this project up when I can. I wanted to get the actual writing done. When I add this project to my visual portfolio, that’s when I’ll likely insert the photos here.

The Civ Challenge Game Board is a real-time game board, made in Python & JavaScript using the Flask & Socket.IO framework. It was created to augment a civilization challenge game that my middle-school social studies teacher (Mr. S for the rest of this article) does at the end of every year.

Just as the 2019-2020 school year was coming to an end, schools were shuttered due to the COVID-19 pandemic. Remote learning became the new norm that we all had to adjust to.

 

I was contacted by Mr. S about what to do with his capstone project at the end of the year. The capstone project is a week-long civilization project, where students need to build up an empire and learn about how civilization works. Students go through different scenarios, trade with other nations, acquire technology achieved (there’s a MASSIVE tech tree in this game), and invest in their civilization with civ chips.

In person, this game has a ton of moving parts. Given the timing of when I got in touch with Mr. S (~7 weeks before the civ project began), we’d have to make some sacrifices.

 

Figuring out priorities

Immediately on the first call, I had two objectives in mind. One, get reacquainted with a game I last played six years ago. Two, figure out which parts of the civilization game we could move online. The entire thing couldn’t be moved online in just under two months.

After a bit of talking, the most important thing that could go online is the game board used by students. The game board is the center of the game, it’s where each student allocates their civ chips, population chips, and writes down any imports & technology acquired over 5 days. This was very much the most important thing that could go online.

After getting enough details to get going on the project, I asked myself…

 

Alright, so how’s this gonna work?

A real-time game, well goodness me I think we should use some Socket.IO! And off I went trying to figure out how socket.io works.

Socket.IO is actually pretty cool – it runs on the HTTP WebSocket protocol (or, at least it does…more on this later), it’s all real time, and it’s as extensible as you want it. There’s built in rooms & all that good stuff, but at the heart of it all, you just transmit on a certain “channel” with a message. That’s literally it.

I started fiddling with socket.io so that I could get a primitive game board working, especially with Socket.IO syncing between client & server. If I increased a chip in a category by one, the server would note that down, and push it out to other clients on the same game board. Every change is saved on the server using a local JSON dictionary (that got written to disk every 15 seconds…more on this later)

Kids would log in to their game boards with a game code (a call to uuid.uuid4() in Python stripped down to the first 8 characters, shhh don’t spoil the magic!) generated when their board is created on the admin console (more about this in a bit). If the game code exists and authentication is successful (along with some checks to make sure the game is running), initial data is pushed down to the user, and everything is ready to rumble.

Now, the push out to other clients part is useless (but I’m still happy I implemented it). The civilization game is one person per board. So I could have saved a lot of time by writing a RESTful API, you ask.

Nah, I say back. Because there’s also situations in this civilization game.

 

Here’s where Socket.IO comes in handy

At the start of every civilization day, each kid plays what I can basically call “Situation Jeopardy”. A card is chosen from a grid (B2, A4, etc), and then something happens. Whether you lose a chip, gain a chip, it’s all dependent on the situation. We’d need some way to push out these chip updates during the game from an admin console (because you can’t trust kids, but I can happily report that nobody tried any XSS!), and this is where Socket.IO came into real good use.

With a RESTful API, each game board would need to constantly ping a server to see if the game board got any server-side chip changes, which would increase server bandwidth. Socket.IO just doesn’t have this issue.

Neeeext!

 

Adding an admin console

Another super important part of the civilization game is an admin console. This is where the teacher would administer the game. Very cool, right!

For the admin console side of things, I fell back on implementing a normal API. I added calls for adding & deleting game boards, updating chip counts for game boards, along with automatic updates for the game boards every 10-15 seconds.

The admin console is powered by extremely hacky jQuery that adds & deletes HTML elements for each game board. This is where some solid object oriented programming (and a framework like React) would come in real handy. Time was of the essence though, so in this case, I mostly cared if it worked properly.

One other functionality of the admin console was the ability to start & stop the civilization game. This was present so that kids couldn’t modify their game boards outside of their period, and limit when the game boards could be modified. Mr. S also added some creativity to this by opening up the game boards a few hours early to sort everything out. Kids are gonna be kids, and kids won’t listen.

 

Don’t mind 4 different periods

Because schools are schools, there’s different periods (sections) for my middle-school teacher, which means four separate civilization games, with four different sets of game boards. As I was implementing the admin console, adding the different periods was, of course, very key in making sure this whole thing ran successfully.

The solution to the different period problems was only troublesome with the admin console side of things, where I wanted the console to only show game boards in a certain period. This meant that each unique game board code had to be associated with a period, and some calls to the API (like changing days, more about this in a sec) needed the context of which period it needed to be attached to.

Otherwise, because of the UUID each board got, most admin-side API calls just needed a game board’s UUID for context (changing the chip count, deleting a board, etc).

 

Enhancements and other quality of life improvements

At this point, we’re about 2 weeks out until the game gets started. During development of the civilization game, I also had an internship making iOS apps and doing authentication stuff with oAuth/SAML (that was very cool, I’d love to write more about it, NDAs exist, sorry), and so the civilization project got the short end of the stick when it came to development time.

A few weeks before the game was finished, I did most of the styling to the main game board, and I also made sure to style the admin console as well. I spent the final week before release doing lots of touch ups, implementing vast amounts of functionality mentioned above (don’t do this), tested the game some, you know, usual stuff.

Something I did implement was a day counter in the game. This isn’t purely cosmetic – after each day (20 years in the civ game), every civilization gets 1 civilization & population chip. In the admin console, I added a readout of the day counter, along with a button to increment the day, and add the 1 civ & pop chip to every game board.

 

Oops, time’s up! What couldn’t get implemented?

I wanted to try really badly to integrate more parts of the game into the game board. Trading was something I was considering – but this would require a 7-step process that would take too much time to implement.

Another thing I wanted to try and put into the game were the situations. Instead of picking something from a PowerPoint, wouldn’t it be cool to do it in game, and have the effects of the situation be immediately applied?

Yes, this would be incredibly cool. Just don’t mind that there’s around 200 situations I’d need to digitize, and add metadata regarding how many civilization chips and/or population chips are gained and lost. Additionally, most situations are conditional – usually with a threshold of chips in a certain category for different outcomes.

What about having the tech tree built into the game? Super cool idea, but the tech tree is massive and is super conditional as well. For this, I just put a text box where kids could type their tech achieved (same for imports). I added a bit of code so that if “Sailing vessels” was present in the tech achieved box, and if the day was 3A or greater (as that’s when sailing vessels is available on the tech tree), the location of the civilization is switched to Global.

 

On the Sunday night before the game, Mr. S entered all the civilization names & player names were entered into the admin console, the game codes were generated, and everything was set to go for Day 1 of the civilization challenge. I was also given the Zoom links to the calls so that I could be there if any tech issues occurred.

Well, that at least was the plan.

 

Day 1 of the game – it didn’t work

During development of the backend server, the saving every 15 seconds thing didn’t work. It would put the right data sometimes into the file, but then put another dictionary with the initial values right after that. Because I’m a stupid idiot, I turned off this functionality.

The issue turned out to be that the Flask debugger does something weird with Python and starts up 2 threads, with 2 schedulers trying to save 2 separate JSON objects. Don’t ask why.

 

This issue was compounded by the fact that at 6:03 AM, apache2 on my web server just reloads. Again, don’t ask. So, when 9 AM rolled around and the first game got started, nothing was working! This was a certified bruh moment, because holy smokes everything was stored in memory!

I hopped into the Zoom call at 9:10 AM and realized the massive fuck-up that had occurred.

The game board was unusable for the first day, but not all hope was lost. When creating all the game boards, the teacher also saved the unique game code generated for each board. Later in the day, I added the ability to manually set the UUID for a game board, just so that codes could be carried over. I also added back that automatic saving functionality (super important!).

After some emails back & forth so that I could get the full list of game codes, names & civilization names for each period, I spent an hour and a half adding back all the game boards. It was my fault at the end of the day, might as well take responsibility and do it myself. Later that night, the civilization chips were synced up for each board, with the day counter being incremented to 2A.

 

Socket.IO on Apache = HTTPS for transport?

After getting all the game boards back up and running, I quickly realized that every time I changed game board values too much, or tried typing in stuff in the imports box, I’d get banned by Apache. It was thinking that I was DoSing the site.

I then quickly realized that Apache WSGI cannot do WebSocket support without doing some reverse proxy stuff I couldn’t never figure out how to do. The solution was to basically increase the maximum hits/second that the Apache DoS module supported, and everything was working normally.

 

Day 2 of the game – she worked (and these subheadings are getting so uncreative!)

Day 2 rolled around and everything worked great. Even though one day of running was knocked out, the game board was running as smooth as butter. Butter is smooth. Did you know that?

 

Day 3 of the game – code is still running

Code went brrrrrr, everything worked

 

Day 4 of the game – hmm something is up

So Day 4 of the game rolled around, and after Period 2 was pretty successful, something happened during Period 3. Everything was lagging hard.

During each game, I had netdata on a second monitor just to make sure everything was working. During each game, about 4-6 apache requests came through each second throughout the entire game. However, during Period 3’s game during Day 4, I was seeing sudden spikes of 60 requests after a minute or so. It seemed as if requests got caught into this backlog, then processed every minute.

Since I had monitoring open & was on the Zoom call, I got right to work figuring out a solution, and notified that the game board was not going to work. I tried a ton of solutions to get this to work. In the end, increasing the process & thread count for the Civ Game WSGI configuration fixed the issue. The game was back online during Period 4’s playthrough, and Period 5 wasn’t affected by this issue.

 

Day 5 of the game – that’s all folks

As the final day of the civilization game came, everything worked smoothly as it did before. No hiccups, no issues. Of course, this was the last day of the civilization challenge, so I was a little sad that it was coming to an end.

 

After Day 5 was complete, I lowered the automatic saving interval to 7 hours. This means there’s a gap between 3 AM – 6 AM where any changes might not get saved. I don’t know if Apache reloading kicks in the “holy balls the script is stopping” code to dump the in-memory JSON to disk (I believe this catch was present before Day 1 and that didn’t work…not sure). Maybe having 8 hour saving time won’t interfere with the apache reloading (the logic is that 8 * 3 = 24, apache server reloads every 24 hours, when the scheduler is scheduled for when the server reloads the save might not occur & 8 hours of changes lost)…i don’t know.

(now that’s the tech talk you come to expect from this website)

 

And that’s the story of the civilization game I made because COVID-19 happened. On the upside, Mr. S did say he’ll likely use this gameboard going forward, since it would make his life a lot easier in a pre-COVID world. It might also be super useful in a postish-COVID world where there’s social distancing, and things need to be done electronically. Trading in the game board itself would excel here.

 

I do want to continue to build out the game board in my spare time by adding new features & making sure everything runs well. It was super cool to get my first exposure into the world of educational software, and to try and build something that the kids could hopefully enjoy.

 

The best part about educational software?

Kids don’t care about the design of the software. We’re all so used to educational software looking like bland crap! The plain Bootstrap 4 framework for styling did a bang-on job and nobody complained!

 

The worst part about educational software?

When I write about it, Yoast SEO says that 25% of the sentences contain passive voice. Then Yoast SEO gets sad and marks the readability as OK.

(and of course, the 27% of sentences that contain more than 20 words. Fun fact, sometimes when writing about projects things need to be chained in 1 sentence)


Right now, the Civ Challenge Game Board is not open-source. I’m aiming to get the source code online by the end of 2020. There’s some polishing I’d like to do before open-sourcing, along with the usual work of removing hard-coded stuff, writing documentation, etc. That all does take time.

License for this project (when it does go open-source) is TBD.