Created
January 1, 2021 19:52
-
-
Save johnoyegbite/b40dba3abb0f6875712908eae2b1aedf to your computer and use it in GitHub Desktop.
N by N Find Winner on a Tic Tac Toe Game
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
import java.lang.Math; | |
class Solution { | |
public int countOnesIn(String str) { | |
int count = 0; | |
for(int i = 0; i < str.length(); i++) { | |
char c = str.charAt(i); | |
if(c == '1') { | |
count += 1; | |
} | |
} | |
return count; | |
} | |
public Boolean didPlayerWin(ArrayList<int[]> moves, int boardDim) { | |
/** Say boardDim is 3. | |
[0,0] [0,1] [0,2] | |
[1,0] [1,1] [1,2] | |
[2,0] [2,1] [2,2] | |
Ap are the combinations of A moves that won. | |
Ap B Ap B A B Ap | |
[[1,2],[2,1],[1,0],[0,0],[0,1],[2,0],[1,1]] | |
[B] [A] [ ] | |
[A] [A] [A] | |
[B] [B] [ ] | |
*/ | |
int[] moveStart = moves.get(0); | |
// Check if all moves are on the same row. | |
Boolean onSameRow = true; | |
// Check if all moves are on the same column | |
Boolean onSameCol = true; | |
// Check if all moves are on the leading diagonal | |
Boolean onLeadingDiagonal = true; | |
// Check if all moves are on the opposite leading diagonal | |
Boolean onOppLeadingDiagonal = true; | |
for(int i = 0; i < moves.size(); i++) { | |
int[] curr = moves.get(i); | |
if(curr[0] != moveStart[0]){ | |
onSameRow = false; | |
} | |
if(curr[1] != moveStart[1]){ | |
onSameCol = false; | |
} | |
if(curr[0] != curr[1]){ | |
onLeadingDiagonal = false; | |
} | |
if(curr[0] + curr[1] != boardDim - 1){ | |
onOppLeadingDiagonal = false; | |
} | |
} | |
if(onSameRow || onSameCol || onLeadingDiagonal || onOppLeadingDiagonal){ | |
return true; | |
} | |
return false; | |
} | |
public ArrayList<int[]> winMoves(ArrayList<int[]> playerMoves, int boardDim) { | |
// Check all possible boardDim combinations in playerMoves. | |
int totalMoves = playerMoves.size(); | |
int power = (int) Math.pow(2, totalMoves); // size of all possible subsets | |
for(int n = 1; n < power; n++) { | |
String binString = Integer.toBinaryString(n); | |
// I only want only the subset whose length is equal to boardDim | |
if(countOnesIn(binString) == boardDim) { | |
// using the knowledge of binary conversion to the advantage here | |
// if s = "abcd" => power = 2^len(s) = 16 | |
// say n = 2; 2 == 0010 base 2. | |
// hence pick the item at index 3 | |
// say n = 7; 7 == 0111 base 2. | |
// hence pick only the last 3 items | |
ArrayList<int[]> moves = new ArrayList<int[]>(); | |
int idx = totalMoves - 1; // index to pick the item from | |
int num = n; | |
while(num > 0){ | |
int rem = num % 2; | |
if(rem == 1){ | |
moves.add(playerMoves.get(idx)); | |
} | |
idx -= 1; | |
num /= 2; | |
} | |
if(didPlayerWin(moves, boardDim)) { | |
return moves; | |
} | |
} | |
} | |
return new ArrayList<int[]>(); | |
} | |
public String tictactoe(int[][] moves) { | |
// Minimum number of play (or minimum length of moves) to have a win | |
// 5 (2 x 3 - 1) = A B A B A = 3 X 3 (for a 3 by 3 board) | |
// 7 (2 x 4 - 1) = A B A B A B A = 4 X 4 (for a 4 by 4 board) | |
// 9 (2 x 5 - 1) = A B A B A B A B A = 5 X 5 (for a 5 by 5 board) | |
// 11 (2 x 6 - 1) = A B A B A B A B A B A = 6 X 6 (for a 6 by 6 board) | |
// ... = ... | |
int boardDim = 3; // Dimension of the board | |
int minLenToGetAWin = 2 * boardDim - 1; | |
if(moves.length < minLenToGetAWin){ | |
return "Pending"; | |
} | |
ArrayList<int[]> playerAMoves = new ArrayList<int[]>(); | |
ArrayList<int[]> playerBMoves = new ArrayList<int[]>(); | |
// Get all the moves for player A and B | |
for(int i = 0; i < moves.length; i++) { | |
if(i % 2 == 0) { // moves for player A | |
playerAMoves.add(moves[i]); | |
}else{ // moves for player B | |
playerBMoves.add(moves[i]); | |
} | |
} | |
// Check if player A wins (from all possible "boardDim" combinations) | |
ArrayList<int[]> playerA = winMoves(playerAMoves, boardDim); | |
if(playerA.size() > 0) { | |
return "A"; | |
} | |
// Check if player B wins (from all possible "boardDim" combinations) | |
ArrayList<int[]> playerB = winMoves(playerBMoves, boardDim); | |
if(playerB.size() > 0) { | |
return "B"; | |
} | |
// If we can't find a winner and | |
// 1. both players hasn't exhausted all moves then it is Pending. | |
// 2. both players hasn exhausted all moves then it is a Draw. | |
return moves.length != boardDim * boardDim ? "Pending" : "Draw"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment