What the code does: I am writing a class to create a binary tree of possible moves from a specified state. During the constructor of the binary tree I pass in a 2D enumerable array (Player 1, Player 2 or neutral) representing what cells are available and what cells have been claimed. Then the constructor iterates through the board and for every empty cell a recursive call is made stopping when there is a winner or there are no moves left.
Where it goes wrong: During debugging I added a toString call on line 16 to see the status of the board. I have found that the program does as intended until the first game is won. It successfully realises it has reached the point of simplicity and SHOULD move up one layer and follow the next branch of the tree (Basically depth first search) but it crashes with a Null Pointer Exception.
What I think is happening: When the program steps up one layer in the branch and I look at the state of the board it still has the same state of when it won. I think that because arrays of enums are treated like objects in java and thus they are being passed by reference. But that would be a logic problem not a Null Pointer Exception so i'm not really sure what to think. Anything I have tried based on this assumption, like cloning the array, has failed so hopefully some one with a fresh mind set can figure out what is going on.
Thanks in advance.
Object code:
import java.util.ArrayList;
public class BinaryTree {
private State[][] state; // What the Tic Tac Toe board looks like at this stage
public ArrayList<BinaryTree> followingMoves; // All the moves that could be made from this point on
public BinaryTree(State[][] state) {
this(state, State.COMPUTER); // Call second constructor
}
public BinaryTree(State[][] state, State turn) {
this.state = state;
if (win() == State.NEUTRAL && movesLeft() != 0) { // If some one has won or there are no moves left.
// Iterate through every cell
for (int x = 0; x < this.state.length; x++) {
for (int y = 0; y < this.state[x].length; y++) {
if (this.state[x][y] == State.NEUTRAL) { // If no player has claimed cell
this.state[x][y] = turn; // Take cell
// Create new object of the current state of the board and switch turns
if (turn == State.COMPUTER) {
followingMoves.add(new BinaryTree(this.state, State.PLAYER));
} else {
followingMoves.add(new BinaryTree(this.state, State.COMPUTER));
}
this.state[x][y] = State.NEUTRAL; // Undo the taking of cell
}
}
}
}
}
private State win() {
if (state[0][0] == state[1][1] && state[1][1] == state[2][2]) // Diagonal top left -> bottom right
return state[0][0];
if (state[0][2] == state[1][1] && state[1][1] == state[2][0]) // Diagonal top right -> bottom left
return state[0][2];
if (state[0][0] == state[0][1] && state[0][1] == state[0][2]) // Horizontal column 0
return state[0][0];
if (state[1][0] == state[1][1] && state[1][1] == state[1][2]) // Horizontal column 1
return state[1][0];
if (state[2][0] == state[2][1] && state[2][1] == state[2][2]) // Horizontal column 2
return state[2][0];
if (state[0][0] == state[1][0] && state[1][0] == state[2][0]) // Vertical row 0
return state[0][0];
if (state[0][1] == state[1][1] && state[1][1] == state[2][1]) // Vertical row 1
return state[0][1];
if (state[0][2] == state[1][2] && state[1][2] == state[2][2]) // Vertical row 2
return state[0][2];
return State.NEUTRAL; // Stalemate
}
private int movesLeft() {
int left = 0;
for (int x = 0; x < state.length; x++) {
for (int y = 0; y < state.length; y++) {
if (state[x][y] == State.NEUTRAL)
left++;
}
}
return left;
}
public String toString() {
String temp = "";
for (int y = 0; y < state.length; y++) {
for (int x = 0; x < state.length; x++) {
if (state[x][y] == State.COMPUTER)
temp += "O|";
else if (state[x][y] == State.PLAYER)
temp += "X|";
else
temp += " |";
}
temp = temp.substring(0, temp.length() - 1);
temp += "\n------\n";
}
temp = temp.substring(0, temp.length() - 7);
return temp;
}
}
Enum:
public enum State {
COMPUTER, PLAYER, NEUTRAL;
}
Test method:
public static void main(String[] args) {
State[][] board = { { State.NEUTRAL, State.NEUTRAL, State.NEUTRAL },
{ State.NEUTRAL, State.NEUTRAL, State.NEUTRAL }, { State.NEUTRAL, State.NEUTRAL, State.NEUTRAL } };
BinaryTree bt = new BinaryTree(board);
}
Stack Trace:
Exception in thread "main" java.lang.NullPointerException
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:24)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:26)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:24)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:26)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:24)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:26)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:24)
at com.zakscode.TTT.BinaryTree.<init>(BinaryTree.java:11)
at com.zakscode.TTT.Test.main(Test.java:9)