X’s and Os can be represented as a multidimentional array:
0,0 | 0,1 | 0,2 |
1,0 | 1,1 | 1,2 |
2,0 | 2,1 | 2,2 |
Rather than pass in 9 parameters, make each coordinate a field in a Game object. Instead of using X and O in the program, use integers as this is easier to handle. Account for empty spaces with another integer. Use statics for these values to avoid ‘magic numbers’. A game needs to be passed in a required board of size 9. This required board can include X, O and Empty markers.
Assumptions
Assume we are passed a multidimensional int array (int[][]). Assume the conversion (from Empty to 0, X to 1, O to 2) has been completed in another part of the code. Assume we are passed an int[][] of size 3 x 3. Assume play will continue until there is a winner or until all spaces are used.
States
We are accounting for four states our game can be in – Winner with no Empty Spaces, Winner with Empty Spaces, No Winner with no Empty Spaces, No Winner Yet. As the game can have a Winner and contain Empty Spaces therefore for efficiency check for a Winner first. Thereafter if there’s No Winner check if the game has Empty Spaces. If this is the case the game is in state No Winner Yet.
Ways to win
8 ways to win (diagrams below – X placed in diagram but can be X or O). As the winning horizontal/vertical/diagonal line must have 3 X or O markers to win, to fail fast check the markers against X or O first (variable xOrO used for this). If the marker is Empty that line will not be a winning line.
Tests
I tested the ‘happy path’ –
completeGameWithWinner_shouldReturnWinner
completeGameWithNoWinner_shouldReturnNoWinner
incompleteGameWithWinner_shouldReturnWinner
incompleteGameWithNoWinnerYet_shouldReturnNoWinnerYet
More exception handling and tests could be added to check for non-happy path scenarios like if the gameState passed is larger or smaller than 3 X 3, and so forth.
Ways to win – diagrams
Horizontal:
X | X | X |
X | X | X |
X | X | X |
Vertical:
X | ||
X | ||
X |
X | ||
X | ||
X |
X | ||
X | ||
X |
Diagonal:
X | ||
X | ||
X |
X | ||
X | ||
X |
I hope this is helpful, my GitHub is linked below with the problem we’ve just discussed.
In Part 2 I’ll discuss more in detail how to implement the solution discussed above.