⮜ Back to Blog

Games, AI, and a New Home

It's been a long time - GLaDOS

Oh yeah, I used to write posts whenever I updated this site, didn't I?

In the 18 months since I last wrote an update, a fair bit has changed, though my site doesn't look that different, to be honest. Still, it only feels right that I document these changes, both frontend and back, somewhere, so let's do this.

Domain Name

You may have noticed that I'm not on anymore. Around fall of 2018, I decided that it was time I got myself a real domain name. Unfortunately, while I distinctly remember being up for grabs when I checked back in 2004, it had unfortunately been snapped up at the time. HugeDomains was the company squatting on the domain name and they offered to sell it to me for sums of up to a thousand US dollars, which seems insane (not sure how large the market for domain names comprising of common English first names with obscure Chinese last names is, but I can't imagine it's that big). Honestly, given my reading of ACPA, it seems like this might even be illegal, since Michael Xing is my full legal name and HugeDomains was not running any business through the domain name besides offering to sell it to me, but unfortunately I'm not a lawyer and I can't afford one, so I just let it slide. Instead, I bought through Google Domains, where my site sat for a year.

However, late 2019, a friend of mine pointed out that HugeDomain's lease on had expired and the site had gone up for auction. As such, I went ahead and bid the minimum $10, which I ended up winning, and so now I own both. Given that I'd rather not have some randos squatting on my domain names in the future, I'll probably keep both domains. When registered on Cloudflare's Registrar, they total like $15 a year, which isn't that much anyways.

Tianjin Mahjong

Way back in spring of 2018, I started what may be the most ambitious project for this website I've yet undertaken - recreating the game of Tianjin Mahjong. If you're unfamiliar, Mahjong is a common card game from China, and almost every municipality in the country has its own variant on the game, so I thought I'd try coding up the one I grew up with.

This project went on for a year, on and off, before I finally finished it earlier this year. It uses Socket.IO through a Node server I'm hosting on Azure, just like all the other multiplayer games on my site. It had some fairly interesting technical challenges to solve, notably with the algorithm that determines whether a hand is a winning one or not (using a fancy recursive backtracking algorithm).

Unfortunately, there's still some bugs in the program, and a lot of the technical debt I took on back when I started this project freshman year have made trying to debug it a nightmare, so I'm just calling it more-or-less finished at this point. I may want to revisit this at some point in the future, now hopefully a bit wiser with some better design decisions, but for now, it is what it is. I haven't actually made space for it yet in the navigation menu (it's getting kind of cramped up there, isn't it?), but you can access it here.

Google Cloud

With Gwiddle very sadly shutting its doors last year, I needed a new home for my site. This was rather unfortunate because Gwiddle really was a great service for students trying to find a home on the internet, and with it gone, I had to go back to searching.

For a year, I parked myself on InterServer, which offers 12 months free to students. It worked fine (after a manual verification process because for some reason they couldn't automatically verify my student status), but wasn't a permanent solution. I was still looking for something better.

For years, I had been hosting stuff on my free Azure subscription, and it works really well. Unfortunately, Azure's free app service 1) sleeps after a period of inactivity and can take quite a few seconds to spin up, which I found to be unacceptably slow for a website, and 2) does not allow for custom domain names, which was a dealbreaker. I do still host other stuff on Azure, but I wanted to find something that at least let me use my own domain for my main site. Enter Google Cloud. I tried originally to play with their free App Engine tier, which does support PHP, but unfortunately they want an actual PHP web app that does all the routing and stuff, which isn't what my site was designed to do. Remember, I built this thing back in 2013. To this day, the site is still just a bunch of PHP files served by an Apache server. Luckily, it turns out that there's a pre-made LAMP stack that I could deploy on Google Cloud's free Compute Engine tier. The Bitnami LAMP stack is what's currently powering my site, running on a Micro Google Cloud Compute Engine instance, and it seems to work fine. Google does still bill me around 2 to 3 cents a month for outbound traffic to Cloudflare, which is apparently not counted under their free tier, but whatever. A few cents a year is close enough to free for me.


This is a small thing, but I remade the projects page. Since this site is supposed to be where I show off all I did, it only made sense for the page with all my projects to actually look a bit more presentable than a text document. I'm still not entirely happy with how the page is laid out, but it's a lot better than how it used to be.

Backend Codebase Changes

This is the type of stuff that isn't noticeable at all on the website itself, but I've made quite a few changes. First, I've consolidated the boilerplate code for a generic page on my site into a nice PHP file. I haven't updated any of the old pages to use the new file yet, but over time, hopefully I'll be able to transition stuff over to the newer, cleaner template. This also allows me to more easily add accessibility features into every page and things like that.

Second, my code is finally checked into version control. I'm hosting my backend code on a private GitHub repo (private mainly because of how bad a lot of the old 2013-era PHP is - there's literally some hard-coded database passwords still sitting around), which marks a drastic change from my old way of just copying the files over FTP to my server every time I made a change. In fact, I used to develop for the site by just setting PHPStorm to automatically copy files over FTP and then literally developing in production. With the move to Git, I finally got around to installing a local PHP server so I can test my site before deployment.

Third, I set up a continuous deployment pipeline through Azure DevOps. Now, whenever I commit or merge new changes into the master branch of my repo, the changes are automatically pulled down to my server within the span of around 10 to 15 seconds. As such, I no longer need to worry about what's happening on my server itself. I just push code to Git, and everything else happens in the background.

Ultimate Tic-Tac-Toe

And finally, I remade Ultimate Tic-Tac-Toe. Again.

If you remember back that far, the original version of Ultimate Tic-Tac-Toe was programmed back in January 2014, when I was a freshman in high school bored during finals week. If you look at the blog post I made back then, you'll see that I wrote "AI is hard to program, okay?" Fair enough, me. However, six years later, I figure we can do a bit better.

The second version was made four years later, in January 2018. Fresh off my first semester of college, inspired by all the CS stuff we were doing in school, I figured it would be a great exercise to go back and wire up my original game to be playable over the internet. I settled on WebRTC as the communication technology, wrapped by a library called PeerJS. Frankly, I'm not sure why, but it didn't work very well across browsers and seems to have fallen out of regular maintenance. This too, could be improved, and indeed, all future multiplayer projects on my site switched over to Socket.IO instead of PeerJS for this reason.

Well, two years later, let's give this another crack, shall we? First things first, learning from the Mahjong fiasco, I made sure to take advantage of all the fancy design patterns we learned in school, cleanly separating out the model, the view, and the controller into separate, narrow interfaces. With each programmed independently, setting up all the different games became quite easy. Local multiplayer was trivial, and communicating with my Socket.IO server was just a manner of serializing the game state and pushing it between two different views. The AI, however, was going to be a bit trickier.

My friend Sam, whose website is here, happened to already have made an AI for Ultimate Tic-Tac-Toe (he calls the game "Ten") on his site, so I kind of took inspiration from his implementation. He used a Monte-Carlo Tree Search, which is effectively the same algorithm that AlphaGo uses and, importantly, one that is very well-documented on the internet. Thus, I scoured an internet's worth of tutorials on implementing MCTS before coding up my own implementation for my game.

On hard mode, the AI gets five seconds to think, and is run entirely locally, so the difficulty of the AI does depend on the processing speed of your machine. I managed to beat the AI once on my phone, but never yet on my laptop. For fun, I pit my AI against Sam's, and the two of them tied. Medium difficulty drops the thinking time to one second (and easy mode just has the AI picking randomly), so it's a lot more beatable. If you just want a fun game of Ultimate Tic-Tac-Toe, medium is probably the way to go.

I think that's about it for the major changes. I'm glad I finally managed to document the stuff I've done somewhere, even if it did take a year and a half. Hopefully the next update won't take this long, but who knows. I'm pretty sure every time I say that, the gap between updates gets longer, so I guess I'll see you in 2023.

Regardless, it's been a fun decade on my site. We'll see what the 2020's have to offer.

⮜ Back to Blog