Last Updated: 26 Feb, 2021

Tic-Tac-Toe Winner

Easy
Asked in companies
IntuitFacebookApple

Problem statement

Two players, named ‘player1’ and ‘player2’, play a tic-tac-toe game on a grid of size ‘3 x 3’. Given an array ‘moves’ of size ‘n’, where each element of the array is a tuple of the form (row, column) representing a position on the grid. Players place their characters alternatively in the sequence of positions given in ‘moves’. Consider that ‘player1’ makes the first move. Your task is to return the winner of the game, i.e., the winning player’s name. If there is no winner and some positions remain unmarked, return ‘uncertain’. Otherwise, the game ends in a draw, i.e., when all positions are marked without any winner, return ‘draw’.

The rules of tic-tac-toe are as follows :

1. At the start of the game, all grid positions are empty.

2. The players take turns to place their characters alternatively into empty positions. ‘player1’ always places character ‘X’ and ‘player2’ always places character ‘O’.

3. A player will never place characters into filled positions.

4. The game ends when all the positions are filled.

5. The game also ends when any row, column, or diagonal contains three same characters (i.e., either ‘X’ or ‘O’). In this case, the winner is the player whose character occupies these three positions.

6. Once the game ends, no more moves are played.

Example :

n = 5, moves = {{0,2}, {0,0}, {1,1}, {2,2}, {2,0}}

example1

First, an ‘X’ is placed at (0,2) by ‘player1’, then an ‘O’ at (0,0) by ‘player2’ and so on. After performing the given five moves, the grid contains three ‘X’s along a diagonal; hence the winner is ‘player1’. So the answer is ‘player1’.

Note :

1. The array ‘moves’ doesn’t contain any repeating positions, and all positions are valid.
2. The array ‘moves’ follows all the rules of tic-tac-toe.
3. You do not need to print anything; it has already been taken care of. Just implement the function

Input format :

The first line of input contains an integer ‘T’ denoting the number of test cases.

The first line of each test case contains an integer ‘N’ denoting the size of the array ‘moves’.

The next ‘N’ lines of each test case contain two space-separated integers denoting a tuple of the array ‘moves’.

Output format :

For each test case, if there is a winner, print their name, i.e., ‘player1’ or ‘player2’. Otherwise, depending on the grid’s final state, print ‘uncertain’ or ‘draw’ (without quotes).

Constraints :

1 <= T <= 1000
1 <= N <= 9
| moves[i] | = 2
0 <= moves[i][j] <= 2

Where ‘moves[i][j]’ represents elements in the array ‘moves’.

Time limit: 1 second

Approaches

01 Approach

Create a 2-D array ‘grid’ of size ‘3 x 3’ with each element set to 0. Use this array ‘grid’ to store the state of the actual grid. We know that  ‘player1’ makes all the even moves (0-based indexing), and ‘player2’ makes all the odd moves because ‘player1’ always plays first, and the players take alternate turns. For a move by ‘player1’, mark the ‘grid’ position as 1. For a move by ‘player2’, mark the ‘grid’ position as 4. Check if any row, column, or diagonal has three same characters and return the appropriate answer.

 

  • Create a 2-D array ‘grid[3][3]’. Set all elements of ‘grid’ to 0.
  • Run a loop where ‘i’ ranges from 0 to ‘n-1’ and ‘i’ increments by 2 after each iteration. Set ‘grid[ moves[i][0] ][ moves[i][1] ] = 1’.
  • Run a loop where ‘i’ ranges from 1 to ‘n-1’ and ‘i’ increments by 2 after each iteration. Set ‘grid[ moves[i][0]][ moves[i][1]] = 4’.
  • Initialize ‘diagOneSum’ and ‘diagTwoSum’ with the value 0. Use these two variables for the sum of the first and second diagonal, respectively.
  • Run a loop where ‘i’ ranges from 0 to 2.
    • Initialize ‘rowSum’ and ‘colSum’ with the value 0. Use these two variables for the sum of the ‘i-th’ row and column, respectively.
    • Run a loop where ‘j’ ranges from 0 to 2.
      • Compute ‘rowSum += grid[i][j]’.
      • Compute ‘colSum += grid[j][i]’.
    • If (‘rowSum’ equals 3 or ‘colSum’ equals 3) return ‘player1’ .
    • If (‘rowSum’ equals 12 or ‘colSum’ equals 12) return ‘player2’.
    • Compute ‘diagOneSum += grid[i][i]’ and ‘diagTwoSum[1] += grid[i][2-i]’.
  • If (‘diagOneSum’ equals 3 or ‘diagTwoSum’ equals 3) return ‘player1’.
  • If (‘diagOneSum’ equals 12 or ‘diagTwoSum’ equals 12) return ‘player2’.
  • At this step, we know that there is no winner. So, if n equals 9, return ‘draw’ else return ‘uncertain’.

02 Approach

We don’t need to simulate the actual grid state. The sums of each row, column, and diagonal of the grid are enough to decide the winner. After each move, modify the sums of the corresponding row, column, and diagonal. For ‘player1’, increase the sum by 1, and for ‘player2’, increase the sum by 4. If any of the computed sums is 3, ‘player1’ wins, and if it is 16, ‘player2’ wins.

 

  • Initialize ‘rowSum[3]’, ‘colSum[3]’, and ‘diagSum[2]’ with all their elements set to 0. Use ‘rowSum[i]’ for the sum of row ‘i’, ‘colSum[i]’ for the sum of column ‘i’ and ‘diagSum[i]’ for the sum of first and second diagonal.
  • Run a for loop where ‘i’ ranges from 0 to ‘n-1’.
    • If ‘i’ is even then ‘curMove = 1’, else ‘curMove = 4’. Use ‘curMove’ to identify the player who makes the current move.
    • Compute ‘rowSum[moves[i][0]] += curMove’.
    • Compute ‘colSum[moves[i][1]] += curMove’.
    • If ‘moves[i][0]’ is equal to ‘moves[i][1]’.
      • Compute ‘diagSum[0] += curMove’. This position belongs to the diagonal from top-left to bottom right.
    • If ‘moves[i][0]’ is equal to ‘2 - moves[i][1]’.
      • Compute ‘diagSum[1] += curMove’. This position belongs to the diagonal from top-right to bottom-left.
    • If (‘rowSum[moves[i][0]]’ is 3 or ‘colSum[moves[i][1]] is 3’ or ‘diagSum[0]’ is 3 or ‘diagSum[1]’ is 3) return ‘player1’.
    • If (‘rowSum[moves[i][0]]’ is 12 or ‘colSum[moves[i][1]] is 12’ or ‘diagSum[0]’ is 12 or ‘diagSum[1]’ is 12) return ‘player2’.
  • At this step, we know that there is no winner. So, if n equals 9, return ‘draw’ else return ‘uncertain’.