Adventures in Writing Othello Software for iOS and macOS2021-06-20
Since late 2020, I’ve been spending many a weekend working on my own software implementation of Othello, a well-known Japanese board game. This post will attempt to go into significant detail regarding how this weekend curiosity ballooned to become the #1 game on the Japanese Mac App Store for April, May and June 2021 — dethroning Asphalt 9: Legends and Steam Link, both of which I assume are multi-million dollar initiatives — and being downloaded roughly 500 times a day worldwide.
If you want to check out the app without going through this whole post, here’s the App Store link:
One fair warning: nothing in this post discusses achievements that should be considered technically impressive or potentially even interesting. This is a tale of a nice and rewarding personal adventure that I embarked upon, nothing more.
August 2020: Exploration Stage
On a Saturday morning in August 2020, I suddenly wondered how come I had never written any meaningful software that employed AI. I had written a toy Connect Four webpage in college, but I wanted to program something that could surprise me the way that Stockfish and other good chess engines pull off strategies never conceived by human players. I chose Othello because of its simple rules, its clean aesthetic, and the fact that I had been playing it on and off since my teenage years, and set about learning the basics of AI algorithms in order to make an Othello AI that was respectable in its own right.
The first thing I had to do was learn the standard algorithm for AI decision-making in board games, which turned out to be the Minimax algorithm. This YouTube video was the most useful explanation and the one that made things click in my head enough for me to implement minimax with alpha-beta pruning (an optimization), which I did in Go. Optimizing the implementation required improving my discipline when dealing with Go structures, pointers and arrays to a high level. Sadly, I couldn’t employ Go’s excellent concurrency features because parallelizing Minimax is arguably more trouble than it’s worth.
Once I had the Minimax decision tree search algorithm all implemented, it was time to pair it with a set of tactics that the AI could use in order to judge the strategic worth of each board, thereby allowing it to evaluate the worth of each move it (or its opponent) could potentially make. This Carnegie-Mellon University paper from 1982 was the best starting point I could find for understanding how to look at that problem and to this day remains probably the nicest paper I’ve read on the topic, despite its age. I also took a look at a bunch of existing AIs: the most impressive of those was definitely Edax, both in terms of it strength and the incredibly impressive low-level optimizations that its author wrote for speed. Some of its board evaluation functions are in pure assembly, and it’s able to represent entire Othello boards as an integer.
I decided to call the AI Piccolo, because of my penchant towards naming my project after Dragon Ball characters and elements, and because in Othello, the color of the board is green, much like the green skin of my software’s Namekian namesake.
Here’s Piccolo in August 2020. I used emojis to give the AI a quickly concocted terminal interface, which allowed me to play against it:
Can you beat Piccolo, my new, experimental Othello AI?— Nadim Kobeissi (@kaepora) August 15, 2020
It seems to stand a chance even against the most powerful AIs available!
Tweet at me your screenshots!
Windows/Linux/macOS binaries: https://t.co/kIzvx0OZGw pic.twitter.com/qgN1sPkEsf
Later in August, I used Ebiten, a Go 2D game framework in order to give Piccolo a user interface, compiled everything into a WebAssembly module, and hosted the result on a webpage, piccolo.click. I then invited my Twitter followers to try it out:
This week was my summer vacation, and I spent all of it working on Piccolo, an Othello AI.— Nadim Kobeissi (@kaepora) August 22, 2020
This was an incredibly fun software to work on. I‘ve capped it off by making a nice website for it, where you can download a version of Piccolo with a nice UI that I designed. pic.twitter.com/tnQqzBCybm
WASM webpage Piccolo wasn’t that great. It was slow, the AI made inexplicable decisions at times, and there were general quality of service bugs everywhere (for example, genuinely funny memory usage at times and frequent crashes on mobile platforms).
But that’s how Piccolo remained, quasi-forgotten by me for months, except for the occasional curiosity and subsequent AI tactics improvements or user interface bug fix, with a notable spike in November 2020.
April 2021: Craftsmanship Stage
In April 2021, my partner remarked that she wished she could play Piccolo on mobile without the experience being so subpar. Not wanting to be left with a veiled accusation of designing shoddy software, I decided to pick the project back up on weekends and to polish it all the way into a genuine, native, high quality iPhone game. “Yes,” I thought, “I’ll make the best Othello app on the App Store, knock those other ad-ridden, shoddy apps off the search rankings, and become the reference Othello app for all others!” In retrospect, this was a strange obsession to suddenly adopt for my self, but that’s how my brain decided to process things at the time.
Transforming Piccolo into dignified, complete software presented me with a series of challenges, which I’ll discuss here.
First, I couldn’t solve the problem of making high quality iOS software by compiling my Go/Ebiten software to the iOS target. Strictly speaking, that would work and produce usable software, but Ebiten ran at a constant 60 frames per second, making it incredibly inefficient for strategy board games where movement was rare and meant that my board game app would have the same battery consumption profile of an action-packed game with constant movement on the screen. The resulting experience was far from “native-feeling”, and I ended up with something that felt like one of those Java games that shipped with old Nokia phones. No cigar.
The solution I ended up going with was the following: I’d isolate Piccolo’s AI engine into a Go module, compile that into an iOS target using gomobile and then link it as an Xcode Framework into the application itself, which I would rewrite from scratch in pure Swift in order to obtain that high quality, “iOS-native” feel.
- Why didn’t I rewrite the AI in Swift? I did! But Swift’s lack of support for references (without
unsafe) or even for fixed-length arrays meant that my Swift implementation, which I completed and even attempted to optimize, was six to eight times slower than my Go code because I couldn’t implement the same optimizations in Swift without feeling like the compiler was giving me the stink-eye. That being said, I enjoyed working with Swift as a language and am optimistic about its future.
- Why didn’t I rewrite the AI in Rust? I did! But I wanted use Mac Catalyst to automagically port my iOS app to a macOS app,
and Rust didn’t seem to have reliable support for the Mac Catalyst LLVM target (Googling for this will contradict what I say here, but I couldn’t get those solutions to work for me on the latest version of Rust or the latest Nightly, either. If your mileage varies, please let me know).— Update (January 28th, 2021): Piccolo’s engine was eventually completely rewritten in Rust, and the Go engine has been permanently retired.
That said, the Rust version was about three times faster than my Go version. However — and this is subjective — I personally preferred maintaining and experimenting with my Go codebase. Gomobile also didn’t support Mac Catalyst as a target out of the box, and I had to use code from this pull request to make things work.
Rewriting the AI engine in Swift and Rust helped me improve my knowledge of both languages, and made writing the application itself in Swift easier. The initial plan was to use a combination of SwiftUI for the interface and SpriteKit for the game’s board graphics and animations. SwiftUI worked out, barely; the entire framework is young and missing essential features. SpriteKit was unusable to me and I ended up using HTML5 Canvas for the board, rendered via a WKWebView. I’d later discover that Swift itself has a Canvas implementation that is almost identical to HTML5 Canvas (and that Apple had invented HTML5 Canvas!); but it was too late to switch and it didn’t matter at that point.
HTML5 Canvas gave me trouble to the extent that the rendering mechanism would sometimes not be reliable, resulting in flickering and other quality issues. Even using
requestAnimationFrame didn’t solve the issue, and I had to resort to implementing double-buffering to obtain a silky smooth rendering experience for the user. One nice detail is that the disc flip animation is programmatic and doesn’t depend on sprites. A Bezier curve is used to make it progress naturally.
To summarize, Piccolo ended up being structured as follows:
PiccoloEngine.xcframework, the AI engine written in Go and compiled as an Apple binary framework targeting
- A Swift program responsible for the game state, user preferences, and the general front-end and user experience of the software, written in SwiftUI.
In addition to the above, I was asked by friends overseas to create an online play feature so that we could play together. My first instinct was to be a good boy and conform to the Apple ecosystem by employing GameKit’s online multiplayer framework for turn-based games. It doesn’t bring me any pleasure or any sense of edginess to say this, but the truth is that GameKit is a contender for the worst framework I’ve ever tried to work with. And I tried, three times over. I couldn’t do it. It’s a terribly unintuitive mess. I hope that Apple improves it, and I apologize to any engineer who worked on it if my opinion appears unfair. It’s possible that I did not understand the framework properly.
I instead switched to writing my own server code. This is one of Go’s strengths, and I consider myself proficient at Go, thus I was able to write a reliable, secure, performant Othello server (using the nice Gin Web Framework) in a few hours and with 291 lines of code. Making sure that the online experience was reliable on the client-side took longer, and I had to issue a number of bug-fix updates over the weeks to deal with issues such as recovering the connection in case the user’s device momentarily lost access to the Internet.
Piccolo ended up shipping with a collection of nine themes, all of which I designed. They’re nice and add to the sense of quality and personality that I wanted the software to have. Here are a few:
The themes were designed using Affinity Designer. I used high-resolution textures for the discs and for the board in order to ensure that everything had that high quality skeuomorphic feel, without clashing with the “flat” look of the rest of the interface. Thanks to SwiftUI, I managed to accomplish the native feel I wanted on iOS and macOS, as you can further see here in the settings, How to Play tutorial and online lobby:
In addition to the above UI elements, I fitted nice sounds into the user experience, and on iPhone, the app uses Haptic Engine to make it feel like you’re placing a disc on the board when you do, and that discs are being flipped when they are. The level of control developers have over how haptics feel on iPhone is cool and it was nice to be able to use that to create a minor but appreciated immersion detail.
Finally, Piccolo was translated into 19 languages, with the help of the many (much-appreciated) friends I know from around the world, and, sadly, in some instances with the help of Google Translate, although I tried my best to move away from that as soon as I could for one language or the other (I may have received confused emails from Russian and Swedish players at a point).
Here’s where Piccolo’s landed in the three months since its release (and the twenty nine subsequent software updates):
- 🏆 #1 Best-Selling Game (All Categories) on the Japan Mac App Store for April, May and June 2021!
- 🥳 Featured in Apple’s “Games We Love”, 2021!
- 🇫🇷 Featured in Apple’s “Best Games Made in France”, 2021!
Hurray! I worked hard on a thing, and people are appreciating it!
One lesson that’s stuck with me throughout this experience is that, at least for me, this wasn’t an easy, simple software to pull off. In addition to everything I’ve talked about here, there were tons of things I had to deal with: SwiftUI bugs, iOS bugs, rendering consistencies between different iPhone and iPad screen sizes, AI bugs, AI tactic optimizations, rendering bugs, sound bugs… it goes on and on.
I’m saying this because I have a suspicion that a lot of rock star programmers out there may look at a well-executed board game and think that it’s a laid back project in a sense that surpasses the reality of the matter. This took effort, despite the fact that in the end, it’s “just an Othello board game app” and not, I don’t know, mission-critical airplane firmware. I think I prefer it to that.
Last week, I worked with artist and illustrator Erica Li in order to design and add an iMessage Sticker Pack for Piccolo! We designed an anime-style mascot together, and the result is incredibly adorable:
What you see above isn’t the entire sticker pack! At the time of writing, there are 24 stickers, and we’re expanding that number to 36 by the end of June.
That sticker pack, I hope, is a good symbolic example of what I’ve tried to do with this hobby project, which is to go the extra mile.
Another thing that I’m proud of is Piccolo’s App Privacy rating on the App Store, given that regular old mobile game apps seem to have transformed into insidious data collection moles in the interim since I last meaningfully engaged with mobile gaming:
I hope you’ll give Piccolo: Othello a try, and that you’ll have a fun time playing with it.