Tic Tac Toe: Game State Setup

One concept that I find interesting about game development is the concept of state. When I first got interested in OpenGL, someone told me that OpenGL is simply a “state machine.” I didn’t really grasp what he meant by that, so it’s something I wanted to make sure I had a good handle on by working through these projects.

It’s a concept that I am sure is fairly straightforward but I have never heard it explained super well. Basically, in games there are aspects of the game that change. A simple example of state is if you’re playing a multiplayer game. It can only be one player’s turn at a time. That means that if you are programming a game where people take turns, you need a way to keep track of whose turn it is at any given point in time. That is your state. Additionally, it’s possible that it’s no one’s turn if the game is over. You don’t want someone to take a turn when the game has concluded. So your game has a few different states it can be at at any given point in time.

Since tic tac toe is a two-player game, I need a way to track which player is the current active player. I also need a way to indicate is the game is in a state where no one is the active player. Back in the dark ages (pre-Swift), there wasn’t a good way of tracking state, so Apple introduced GKState in their GameplayKit framework. This allowed you to build state machines to track state in your game. However, with the advent of more powerful Swift enums, it’s far simpler to just create an enum to contain and switch your state.

Creating state machines in Swift is easy and powerful. Enums are an “or” type, which means that a Swift enum can only have one and only one value at a time. Which means if you need to keep track of state, they work very well. Let’s look at the example of keeping track of the current state of the game. We’ve already determined that the game can have three different states:

  • No Game Active
  • Player A’s Turn
  • Player B’s Turn

These conditions can be directly mapped to an enum:

enum GameState {
    case notPlaying
    case playerA
    case playerB

This enum is named GameState, making it easy to remember what it is tracking. You can initialize this game state as a variable in your main program:

var currentPlayer:GameState = .NotPlaying

You initialize currentPlayer as not playing because this is the default state you will find yourself in until you initialize a game. Once a game begins, the currentPlayer state will change to either currentPlayer.PlayerA or currentPlayer.PlayerB. There will never be a situation where this state is blank or where there will be more than one valid case. It is exclusive.

The only other state I have to track in this simple game involves the state that any individual tile is in. The tiles can have three possible states:

  • Not Selected
  • Player A’s Tile
  • Player B’s Tile

This again maps very easily to an enum:

enum TileState {
    case notSelected
    case playerA
    case playerB

This takes care of all of the state I need in the game. It isn’t much, but it’s a solid start to the foundation of our game. Most of the non-UI code I need will revolve around checking and transitioning this state. You can check the code so far here. Next, I need to set up the conditional logic and rules of the game.