In addition to hockey, I really love the game Go. Anytime I get a new tablet, console, what have you, I check to see if the marketplace has a good Go app for me to while away my free time. So back in July, when I discovered Amazon was running a promotion that month to encourage developers to create new Alexa skills, and I discovered there was no Go skill on the market yet, I decided to try creating one. Of course this all happened around July 30th when there were hardly 36 hours left on the promotion. As a result, it turned into a mini-hackathon, and after about 14 hours I had successfully submitted Go Sensei to the Alexa skill marketplace. For anyone who wants to create a similar app, or who just wants to learn about Alexa skill development, here's how I did it.
Finding a Go Bot:
As much as I would like to say I could implement an effective Go bot in a single day, I'm not nearly that well versed in Monte Carlo Search Trees or Deep Learning Algorithms. Instead, I decided to find an open source alternative that I could plug into my Alexa skill. Doing so of course meant my skill would in turn need to be open source as well, but I felt winning a free Echo Dot, along with the knowledge I would gain through the process, would be reward enough. I wasn't going to try to sell it to anyone.
I began my search at Sensei's Library, an online knowledge base for all things Go. It's an incredible resource for anyone just getting started in the Go world. Scanning through their appendix of Go playing programs yielded two promising results: Fuego and GNU Go. Fuego was initially released by the Computer Go Group at the University of Alberta and is now available under the terms of the GNU Lesser General Public License. GNU Go is maintained by the Free Software Foundation and is available under the GNU General Public License. Scanning over their documentation as quickly as possible, it was a hackathon after all, gave me the impression that they were about equally suited for the job, so I decided to try GNU Go initially and see how far I could get. With a Go bot in hand, it was time to face the real question: how could GNU Go actually play inside of an Alexa Skill?
Compiling GNU Go for AWS:
I decided to break the question down into smaller chunks. First, how could a human play against GNU Go without a visual interface? Since Alexa skills only respond to voice commands any solution I came up with would first have to address this issue. I had been playing against GNU Go via the ASCII interface, which was actually rather fun but near impossible to use for my purposes. A little more digging turned up the CLI Options, specifically --infile which lets you load a board using the Smart Game Format and tells GNU Go to determine the next move for the game, and --outfile which would write the new game state to an SGF file. To allow myself to test the gameplay locally, I compiled GNU Go for my OS X machine and committed it to the repo, then wrote a simple wrapper to ensure I could execute the GNU Go binary programmatically via Node.js.
With that working, I could successfully execute the GNU Go CLI commands, but how could Alexa report the moves that were generated by the GNU Go binary to the user and vice versa? I would have to implement a translation layer that could take an in-memory board that Alexa would queue off of and turn it into an SGF file that GNU Go could understand. To handle that translation, I pulled in the sgf2go NPM module and updated my script to write a sample board to a file for consumption by GNU Go. Much to my surprise, this whole process worked like a charm.
At least it did locally. This was all using a GNU Go binary that I had compiled from source on my OS X machine. The thing is, Alexa skills use Amazon's Lambda service to process "user intents" and generate responses, so how could I get a GNU Go binary that would work in AWS? After a little more research I discovered that AWS Lambda functions execute on the Amazon Linux AMI, a special Linux image maintained by AWS. So the final step in my prep work was to compile a GNU Go binary against that architecture. I spun up a new instance in EC2 only to discover it was incredibly bare bones. In order to generate the binary and make it easily accessible to the project I ultimately decided to install Git, clone the Go Sensei repo onto the EC2 instance, compile the GNU Go source files that were checked into the repo, commit the new binary to the local repo, and finally push it back to the remote repo in GitHub. After that whole process I had everything I needed to start building the actual Alexa skill.
Handling User Intents:
In the Alexa skill world, everything the user says is considered an "intent." The skill itself elicits intents by prompting the user to say something, and then creates responses for those intents. In order to do all that from a Node.js application, the Alexa team has released an aptly named module called alexa-skills-kit-sdk-for-nodejs. I pulled that module in and used it to create a few very simple intent handlers. All I wanted at that point was the ability to start a new game and verify Go Sensei could correctly generate new moves. Once that was in place, it was time to actually start testing the skill.
To set up the actual skill, I first had to create a Lambda function for it in AWS. This required zipping all of my code together, including the GNU Go binary, and uploading it to AWS. I quickly realized I would need to iterate on my code a lot throughout the testing process, so I wrote a simple NPM script to bundle everything in preparation of deployment. With that it was trivial to rebuild my app with every change and quickly redeploy it. All that was left for me to do was register Go Sensei as a custom skill in AWS. This required me to come up with a list of sample utterances, basically every possible way I could think of a player saying "I place a stone at ___", along with a COORDINATES custom slot type, in which I enumerated every possible coordinate of a 9x9 board. That's 81 unique coordinates, and if I ever expand the app to play on a 19x19 board I'll need to expand the list to the full 361 possibilities. Hey, if the solution wasn't insane, it wouldn't be a hackathon. In any case, I finally had a skill all set up and ready to use. From there I began testing it using Amazon's Service Simulator and tweaking it until Go Sensei was successfully receiving moves from the user and responding with moves of its own. After I added a quick function to report the final game score, Go Sensei was complete and finally ready to be published!
Publishing Go Sensei:
To Amazon's credit, they don't let every Joe Developer upload potentially malicious code to their marketplace. Before they'll actually publish your skill, you have to submit it for certification. There are two things I found interesting about the certification process. The first is that it appears to be done by actual humans trying to interact with your app based on the example phrases you provide to potential users. Here is an excerpt from the certification report I received a day later:
Take a look at the Skill's response to the user trying to place a stone. That's actually an error message coming from Alexa's code itself; it's only triggered if somehow your Lambda function fails to generate a response. I'll admit that during my early testing I would see this error message if I had something misconfigured. However, at this point all of my own tests were passing, so I was surprised it was popping up again. I did some more testing and indeed everything was working for me. This is the second thing I found interesting. My only explanation was that Amazon's Lambda service had actually experienced issues during testing, but the tester had no way to identify that and chose instead to fail my certification application. This theory seems to hold true as I resubmitted Go Sensei for certification having not changed the app at all, and this time it passed certification and was published to the Alexa skill marketplace.
Final Thoughts:
Overall, this was a very interesting learning experience. Going into it I had no idea how Alexa skills were configured and hosted in Amazon's marketplace, and I only had a passing knowledge of Amazon Lambda functions as well. Now I know much more about their infrastructure, and I've got a pretty sweet Alexa skill to boot! If you agree, head on over to the GitHub repo to vote for which features get implemented next, or better yet, add some yourself!