Design Tic-Tac-Toe Game - Google Low Level Design Interview Question

This is system design question asked in interview for low level design implementation of Tic-tac-toe.

tictactoe.png

Design a Tic-tac-toe game that is played between two players on a n x n grid.

A move is guaranteed to be valid, and a valid move is one placed on an empty block in the grid. A player who succeeds in placing n of their marks in a horizontal, diagonal, or vertical row wins the game. Once a winning condition is reached, the game ends and no more moves are allowed. Below is an example game which ends in a winning condition.

Form the design perspective it is very broad question. before we look at solution, first understand game conditions:

Given n = 3, assume that player 1 is "X" and player 2 is "O" 
board = TicTacToe(3);

board.move(0, 0, 1); -> Returns 0 (no one wins)
|X| | |
| | | |    // Player 1 makes a move at (0, 0).
| | | |

board.move(0, 2, 2); -> Returns 0 (no one wins)
|X| |O|
| | | |    // Player 2 makes a move at (0, 2).
| | | |

board.move(2, 2, 1); -> Returns 0 (no one wins)
|X| |O|
| | | |    // Player 1 makes a move at (2, 2).
| | |X|

board.move(1, 1, 2); -> Returns 0 (no one wins)
|X| |O|
| |O| |    // Player 2 makes a move at (1, 1).
| | |X|

board.move(2, 0, 1); -> Returns 0 (no one wins)
|X| |O|
| |O| |    // Player 1 makes a move at (2, 0).
|X| |X|

board.move(1, 0, 2); -> Returns 0 (no one wins)
|X| |O|
|O|O| |    // Player 2 makes a move at (1, 0).
|X| |X|

board.move(2, 1, 1); -> Returns 1 (player 1 wins)
|X| |O|
|O|O| |    // Player 1 makes a move at (2, 1).
|X|X|X|

I have covered coding part for design & it' not the best description for this problem but i try my best here so that it can be helpful to someone.

So basic solution is to :

Construct an n*n grid, and check whether the row/column/diagonal line of the chess pieces are connected to a line each time a chess is played. The condition of the check is to calculate whether the number of row/column/diagonal piece marks is equal to n.

class TicTacToe(object):
    def __init__(self, n):
        self.grid = [[' '] * n for i in range(n)]

    def move(self, row, col, player):
        # Player {player} makes a move at ({row}, {col}).
        if player == 1:
            mark = 'X'
        else:
            mark = 'O'

        self.grid[row][col] = mark
        # check winnign condition
        # check if row has the same mark
        n = len(self.grid)
        sumOfRow = sum([self.grid[row][c] == mark for c in range(n)])
        sumOfCol = sum([self.grid[r][col] == mark for r in range(n)])
        sumOfLeftDiagonal = sum([self.grid[i][i] == mark for i in range(n)])
        sumOfRightDiagonal = sum(
            [self.grid[i][n - 1 - i] == mark for i in range(n)])

        if sumOfCol == n or sumOfRow == n or sumOfRightDiagonal == n or sumOfLeftDiagonal == n:
            return player
        else:
            return 0

# Driver code

board = TicTacToe(3)        # Given n = 3
board.move(0, 0, 1)
board.move(0, 2, 2)
board.move(2, 2, 1)
board.move(1, 1, 2)
board.move(2, 0, 1)
board.move(1, 0, 2)
print(board.move(2, 1, 1))
# 1  Result 1 as a winner

Here we can improved over solution 1 given above without creating a grid.

No need to create a grid, just record the value of each row, column and two diagonals. For each chess game, the chess assignment for player 1 is 1, and the chess assignment for player 2 is -1. Then we only need to check whether the value of the current row/column/diagonal is equal to n or -n.

# Solution 2  (Without creating a grid):

class TicTacToe(object):
    def __init__(self, n):
        self.row = [0] * n
        self.col = [0] * n
        self.diag = 0
        self.xdiag = 0
        self.n = n

# function to check moves of player 1 & player 2
    def move(self, row, col, player):
        if player == 1:
            count = 1
        else:
            count = -1

# Record the value of each row, column and two diagonals.
        self.row[row] += count
        self.col[col] += count
        if row == col:
            self.diag += count
        if row + col == self.n - 1:
            self.xdiag += count

        if self.n in [self.row[row], self.col[col], self.diag, self.xdiag]:
            return 1
        if -self.n in [self.row[row], self.col[col], self.diag, self.xdiag]:
            return 2
        return 0

# Driver code

board = TicTacToe(3)        # Given n = 3
board.move(0, 0, 1)
board.move(0, 2, 2)
board.move(2, 2, 1)
board.move(1, 1, 2)
board.move(2, 0, 1)
board.move(1, 0, 2)
print(board.move(2, 1, 1))
# 1  Result 1 as a winner

If you like this article then please share this...