It's done enough!

tl;dr: Download a Runnable Jar Here

Standalone PC/OSX builds are pending.

Kudos to Peter Queckenstedt (@scutanddestroy) for doing an amazing job on the Proctor, Hillary, and Trump.

Post-Mortem:

‚ÄčThis has been a positive experience. I love games that actually have nontrivial interactions in them and completely open-ended text inputs. I'm a fan of interactive fiction, but hate that feeling when you're digging around and grasping for action words like some sort of textual pixel-hunt.

The language processing systems in DS2016 aren't particularly complicated, but they're more simple than I'd like. In the first week of the jam I started writing a recurrent neural network to parse and analyze the sentiment of the player's comments. I realized, perhaps too late, that there wasn't enough clean data for me to use to accurately gauge the sentiment and map it to social groups. Instead, I wrote a basic multinomial naive bayes classifier that takes a sentence, tokenizes it, and maps it to 'like' or 'dislike'. Each group has its own classifier and tokenizer, so I could program demographics with a base voting likelihood and give each of them a few sentences on the "agrees with" and "disagrees with" sides, then have them automatically parse and change their feelings towards the player.

A usability change that came in later than one would guess was as follows: I had originally grabbed the demographic with the largest emotional response to a comment and displayed them with the sentiment change. Unfortunately, this turned out to over-exaggerate one particularly noisy group. Another change, shortly thereafter, was masking the exact amount of the change. Instead of saying +1.05% opinion, it simply became "+Conservatives" or "-Hipsters". This was visually far easier to parse and I think helped the overall readability of the game.

There is still a call to add some more direct public opinion tracking in the game, letting players know in closer to real time how they're doing among the demographics. I may find it in myself to introduce that.

The last interesting aspect that I noticed during playtesting: I had slightly over-tuned the language models to my style of writing. Instead of opining on matters at any length, people were making enormous run-on sentences which appealed to every demographic at the same time. These statements, often self-contradictory, were not something I expected or handled well. I found the game to be rather difficult, but it looks like playtesters had a dandy time making the states go all blue.

It's time again for Little Awful Jam! The theme is 'Weird History'. Make a game about folk lore, something strange that happened in history, or some corruption of events. This is my game design doc.

Game Design Doc

The Pitch: The idea on which I've settled is Debate Simulator 2016, where you play a presidential candidate stepping up to the podium to square off against our current commander-in-chief.

The Gameplay: The gameplay consists of prompts and free responses. Your goal is to appeal to your voting base and to excite them enough to go out and vote. Alternatively, you can go 100% offensive and do nothing but verbally tear down your opponent. Your feedback will consist of your approval rating and your citizen motivation. Don't motivate people and they won't get out and vote, even if they like you. Motivate people to vote and don't get them to like you and you're sure to lose.

The Challenge: Do you know your stuff? Can you overcome the Evangelical block? How do you tacitly approve of bodily autonomy without making it seem like you approve of bodily autonomy?

Free-form Ideas:

  • Pick your alignment. Left-Democrat. Centrist-Democrat. Independent. Centrist-Republican. This will change the difficulty by having different demographic groups start with different opinions of you.
  • End of game: show the election map and the polls. Use real demographic data to show how things played out.
  • Generate realistic text for Donald Trump by randomly mashing together words.
  • Simple NLP for the player to classify sentiment and subject, including prompt text for context.

Look and Feel: 2D single-stage pixel art with largely static sprites and a camera that pans between the player and the challenger. Aiming for 640x480 resolution with 2x upscaling. No fancy particles. Minimal sprite talking animation. Animated text.

Tools: Sadly, I won't be using Godot for this. Much as I love the engine, there is so much here that requires a more robust coding language that I need to do it in libGDX with Kotlin.

Project Progression:

  • Skeleton libGDX game with Kotlin. 'Hello World'.
  • Scene stack and placeholder sprites. Basic game loop.
  • Demographic data and player input processing + scoring.
  • Opponent responses + emotional meter.
  • Minimum Viable Product

Godot is a really honkin' neat engine. If you haven't tried it, I strongly recommend playing around with it. Take a look at https://godotengine.org.

I found myself in a position where I needed to build a native library. Here's my experience doing that on Windows. I can't attest to the accuracy or repeatability of these steps, but I'm leaving them here so I can revisit them when I need to. Just remember: GDNative is a way to call into shared libraries from Godot. NativeScript is the other way -- native code that can call into Godot.

Overview:

Prerequisites and Setting Up

You will need:

  • Microsoft Visual Studio
  • Python 3 + pip (or scons installed)
  • Git
  • A really good reason to need to build a native library

Godot is built with Scons. The process is relatively painless compared to the dependency hell that you can get into when building other tools, but it's not without challenges. I'm going to assume that you've installed Microsoft Visual Studio and can run the following on the command line:

cl.exe

Your output should be this:


(scons) D:\Source\TerminusExperiment\CPU_v1>cl
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

usage: cl [ option... ] filename... [ /link linkoption... ]

If you don't see that, you'll probably need to search for a shortcut to "VS2015 x64 Native Tools Command Prompt". That will, in turn, include a script to call the following bat file: "%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64"

CHECKPOINT: Visual Studio is installed.

Next is Scons. I'm not going to go into any depth about installing and setting up Python on Windows, but I've had more luck using Chocolatey than Anaconda. Install Python 3, pip, and virtualenv.

Make a new virtual environment somewhere with python -m venv my_scons_venv (Mine is called just 'scons' and is stored in C:\Users\Jo\virtualenvs).

Activate the new virtualenv. If you're on Windows, that means calling C:\Users\Jo\virtualenvs\scons\Scripts\activate. (This is approximately equivalent to Linux or OSX's . ./scons/bin/activate)

Install scons in your virtual environment. pip install scons

CHECKPOINT: Scons is installed. You can build Godot.

Downloading and building Godot with Scons

Now we'll pull the Godot source. There may be a way to make do without this, but I've not had luck.

I keep my projects in D:\Source. I opened my command prompt and did git clone https://github.com/godotengine/godot.git

Get some coffee while the repo comes down.

Change into the Godot directory. Build Godot with scons platform=windows.

Wait.

You should see your executables in "D:\Source\godot\bin". Try double clicking on the tools.64.exe if it's built. Fun, eh?

CHECKPOINT: Godot is built from sources.

Building The CPP Shared Library

Go back to your source folder. For me, that's "D:\Source". Now we'll clone godot-cpp so we can build our .lib file. git clone https://github.com/GodotNativeTools/godot-cpp

We're going to edit the SConstruct file.

I set my "godot_headers_path" to godot_headers_path = ARGUMENTS.get("headers", os.getenv("GODOT_HEADERS", "D:\\Source\\godot\\modules\\gdnative\\include"))

Note that it might be necessary to use double backslashes because Windows uses the wrong slash direction for their paths. Note that godot_headers_path points into the Godot build we cloned and into the GDNative module's include folder.

Update the "godot_bin_path" to point to our executable. godot_bin_path = ARGUMENTS.get("godotbinpath", os.getenv("GODOT_BIN_PATH", "D:\\Source\\godot\\bin\\godot.windows.tools.64.exe"))

Invoke scons platform=windows generate-headers=yes.

There will be a short span while the lib is created. When it's all done, check your bin folder. You should see "godot_cpp_bindings.lib".

CHECKPOINT: You've got the godot_cpp_bindings library built

Make a new folder. I put it in my project directory, "D:\Source\Terminus\CPU_v1\". CPU_v1 will be my native module. My game involves doing some CPU emulation.

Into that directory, copy D:\Source\godot-cpp\include. Also make a folder called 'lib' and put "godot_cpp_bindings.lib" in it.

Your directory structure should look like this:

D:\Source\TerminusExperiment\CPU_v1
- include
 |- core
 | |- AABB.hpp
 | \- ...
 |- AcceptDialog.hpp
 |- AnimatedSprite.hpp
 \- ...
- lib
 \- godot_cpp_bindings.lib
- src
 \- init.cpp (THIS IS YOUR CPP FILE!  Get a sample one from [x].)

Finally, we can build our CPP file using this command in the root of CPU_v1: cl /Fosrc\init.obj /c src\init.cpp /TP /nologo -EHsc -D_DEBUG /MDd /I. /Iinclude /Iinclude\core /ID:\Source\godot\modules\gdnative\include

Make a good note of those trailing '/I's. The specify the include folders. If you get a message about "Missing whatever.h" then you've got one wrong.

/Fosrc\init.obj specifies the output object. /c src\init.cpp specifies our source file.

CHECKPOINT: We have our .obj file from our init.cpp!

Last step, we can link our two objects together. cl /LD lib\godot_cpp_bindings.lib src\init.obj /link /DLL /OUT:init.dll

This will take our lib and our source object and will produce init.dll -- something we can use in Godot's Native library.

Here I sit, overwhelmed at the insanity taking place in the political arena. I'm taking a moment to collect my thoughts for the same reason as anyone else that keeps a journal: so when we look back at the injustices and failures of the past we get some sense of their context. Maybe it will also remind me that we tried.

The Net Neutrality Repeal

The FCC, as chaired by Ajit Pai, has stated its intention to roll back the Title II protections afforded in 2015 under President Barack Obama. There are five members of the board, three Republicans and two Democrats. The Democrats have voiced their opposition to the changes. The three majority members favor of the repeal of the consumer protections and have given the bill the compelling title, "Restoring Internet Freedom Order." Their argument is that regulations are stifling innovation. Comcast and Verizon, in investor meetings, have both declared that Net Neutrality rules do not, in fact, hinder innovation. There have been millions of comments voiced by consumers who favor the added protections from Title II. There are some form letters. There have also been millions of automated bot comments in opposition. It seems reasonably likely that major ISPs are not expecting to get away with the fabricated comments in opposition, but hope to muddy the waters enough to make public feedback seem unusable.

It's looking like the repeal will go through, followed by a litany of confusing legal actions which will likely ALSO be muddied by telecom providers. (This can happen because only one appellate court can hear the petition and it's chosen more or less at random -- first come first serve. If a telecom files a petition against some part of the FCC order, the jurisdiction is entered into the lottery. This will allow them to change to a more favorable venue.)

Healthcare Repeal

The House and The Senate have both voted to try and dismantle key provisions of the Affordable Care Act. The ACA has insured a record number of people (in b4 smarmy individual mandate comment) and has started to restrain the growth of health care costs. It has been life saving for more than a few people and protected countless others from bankruptcy. Health care costs could be further reduced if states wouldn't refuse federal funds. (This has actually happened.) Additionally, since the president is required to basically sign checks reimbursing insurers for the high-risk pools, that adds uncertainty to the market and makes it harder for insurance providers to plan forward -- removing smaller providers and driving up costs for all participants.

Tax Reform

After a massive public outcry against the mass-repeal of healthcare, it looks like Republicans have doubled down on the, "Look, we're all about taxes," mantra. The new tax bill contains provisions to break one of the three legs of the ACA: the individual mandate. Without the individual mandate, there's no incentive for anyone to join the pool of insured until they need insurance. The addition of young, healthy, low-risk persons decreases the cost of providing care and drives down premiums. Without the individual mandate, people can refuse to acquire healthcare until they actually need it which, due to the rules on preexisting conditions, means they can't be refused service (a good thing, if coupled with the individual mandate). This makes Obamacare untenable and gives Republicans deniability. "Look, we always said it was doomed. It had nothing to do with us sabotaging it. It just fell apart due to nothing we did. All we did was pass this one unrelated tax bill and suddenly it exploded."

In Short Supply

I've been in fairly regular contact with my representatives at the House and Senate level. (Props to Jamario and Alex L. You guys rock.) It feels every day though that the best we can hope for is to throw lives at the battlefront while we retreat. Corporate profits continue to skyrocket. Dividends are paid to board members and shareholders instead of employees. The middle class' wages stagnate or shrink while the working poor's numbers grow. A fraction of a handful of a few self-serving people are setting up our country for failure to further their own personal gains and are manipulating countless thousands into believing it's for their own personal good. No hope for a better tomorrow.