Start learning free

LESSON 415 OF 415 · PROJECTS: OBJECT-ORIENTED

Tic Tac Toe - A Two-Player Game Class in Swift

Practice

Build a TicTacToe class for two players, X and O, on a 3 by 3 board. One object is one game: it remembers the board and whose turn it is, lets the players take turns, and tells who has won.

The board: rows and columns are numbered 0, 1 and 2. Cell (0, 0) is the top-left corner, (0, 2) the top-right, (2, 0) the bottom-left and (2, 2) the bottom-right. A cell holds "X", "O" or "." when it is still empty.

Build:

  • A new game. The class has two private properties, set up when the object is created: board, a 3 by 3 array of Character filled with ".", and player: Character = "X". Every row must be its own array. All nine cells are empty and X moves first.
  • func move(_ row: Int, _ column: Int) plays one turn at the given row and column (always between 0 and 2, so you do not need to check the range).
    • If the cell is not empty, ignore the call: nothing changes and it is still the same player's turn.
    • Otherwise put the current player's mark in the cell, then give the turn to the other player (X becomes O, O becomes X).
  • func winner() -> Character returns the winner as a Character: "X", "O" or ".".
    • A player wins by having the same mark in all three cells of a row, a column, or one of the two diagonals ((0,0), (1,1), (2,2) and (0,2), (1,1), (2,0)). Three empty cells in a line are not a win.
    • If nobody has three in a row, return ".". That covers a game still in progress, an empty board and a draw.

You start with this code, which plays six games and prints the result of each one:

class Solution {
    func mainFunction() {
        var game = TicTacToe()
        game.move(0, 0)
        game.move(1, 0)
        game.move(0, 1)
        game.move(1, 1)
        game.move(0, 2)
        print("\(game.winner()) wins!")
        game = TicTacToe()
        game.move(0, 0)
        game.move(0, 1)
        game.move(0, 0)
        game.move(1, 0)
        game.move(1, 1)
        game.move(2, 2)
        game.move(2, 1)
        print("\(game.winner()) wins!")
        game = TicTacToe()
        game.move(0, 0)
        game.move(0, 1)
        game.move(1, 1)
        game.move(0, 2)
        game.move(2, 2)
        print("\(game.winner()) wins!")
        game = TicTacToe()
        game.move(0, 2)
        game.move(0, 0)
        game.move(1, 1)
        game.move(0, 1)
        game.move(2, 0)
        print("\(game.winner()) wins!")
        game = TicTacToe()
        game.move(0, 0)
        game.move(0, 1)
        game.move(0, 2)
        game.move(1, 1)
        game.move(1, 0)
        game.move(1, 2)
        game.move(2, 1)
        game.move(2, 0)
        game.move(2, 2)
        print("No winner: \(game.winner())")
        game = TicTacToe()
        print("No winner: \(game.winner())")
    }
}

Games played: X fills the top row; then a game where X tries to play on a cell that is already taken (ignored, and still X's turn) and O wins the middle column; X on the main diagonal; X on the other diagonal; a full board with no three in a row; and a brand-new game.

Expected output:

X wins!
O wins!
X wins!
X wins!
No winner: .
No winner: .

There are eight winning lines: three rows, three columns and two diagonals. A loop over i from 0 to 2 can check row i and column i together; the two diagonals come after the loop. Skip a line whose first cell is empty.

Check for a taken cell first and leave the move method before touching the board or the turn. Only a successful move passes the turn to the other player.

class TicTacToe {
    private var board = Array(repeating: Array(repeating: Character("."), count: 3), count: 3)
    private var player: Character = "X"

    func move(_ row: Int, _ column: Int) {
        if board[row][column] != "." { return }
        board[row][column] = player
        player = player == "X" ? "O" : "X"
    }

    func winner() -> Character {
        for index in 0..<3 {
            if board[index][0] != "." && board[index][0] == board[index][1] && board[index][1] == board[index][2] { return board[index][0] }
            if board[0][index] != "." && board[0][index] == board[1][index] && board[1][index] == board[2][index] { return board[0][index] }
        }
        if board[0][0] != "." && board[0][0] == board[1][1] && board[1][1] == board[2][2] { return board[0][0] }
        if board[0][2] != "." && board[0][2] == board[1][1] && board[1][1] == board[2][0] { return board[0][2] }
        return "."
    }
}

STEP 1 OF 14
    Ctrl + Enter to check

    Tic Tac Toe in Swift

    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free