How to do it...

We will run through how we can use the tic-tac-toe game defined earlier, and how it can be improved using a subscript. Then, we will examine how this works:

  1. Let's create an instance of our TicTacToe grid:
var game = TicTacToe()
  1. For a player to make a move, we need to change the GridPosition value assigned to the relevant place in the array of arrays, which is used to store the grid positions. Player 1 will place a nought in the middle position of the grid, which would be row position 1, column position 1 (since it's a zero-based array):
// Move 1 
game.gridStorage[1][1] = .player1
print(game.gameStateString())
/*
-------------
| | | |
-------------
| | o | |
-------------
| | | |
-------------
*/
  1. Next, Player 2 places their cross in the top-right position, which is row position 0, column position 2:
// Move 2 
game.gridStorage[0][2] = .player2
print(game.gameStateString())
/*
-------------
| | | x |
-------------
| | o | |
-------------
| | | |
-------------
*/
  1. We can make moves in our game, but we are doing so by adding information directly to the gridStorage array, which isn't ideal. The player shouldn't need to know how the moves are stored, and we should be able to change how we store the game information without having to change how the moves are made. To solve this, let's create a subscript to our game object so that making a move in the game is just like assigning a value to an array.
  1. Add the following subscript method to the TicTacToe struct:
struct TicTacToe { 
var gridStorage: [[GridPosition]] = []
//...
subscript(row: Int, column: Int) -> GridPosition {
get {
return gridStorage[row][column]
}
set(newValue) {
gridStorage[row][column] = newValue
}
}
//...
}
  1. So now, we can change how each player makes their move, and finish the game:
// Move 1 
game[1, 1] = .player1
print(game.gameStateString())
/*
-------------
| | | |
-------------
| | o | |
-------------
| | | |
-------------
*/

// Move 2
game[0, 2] = .player2
print(game.gameStateString())
/*
-------------
| | | x |
-------------
| | o | |
-------------
| | | |
-------------
*/

// Move 3
game[0, 0] = .player1
print(game.gameStateString())
/*
-------------
| o | | x |
-------------
| | o | |
-------------
| | | |
-------------
*/

// Move 4
game[1, 2] = .player2
print(game.gameStateString())
/*
-------------
| o | | x |
-------------
| | o | x |
-------------
| | | |
-------------
*/

// Move 5
game[2, 2] = .player1
print(game.gameStateString())
/*
-------------
| o | | x |
-------------
| | o | x |
-------------
| | | o |
-------------
*/
  1. Just like in an array, we can use a subscript to access the value as well as assign a value to it:
let topLeft = game[0, 0] 
let middle = game[1, 1]
let bottomRight = game[2, 2]
let player1HasWon = (topLeft==.player1)&&(middle==.player1)&&(bottomRight==.player1)