0

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)
ZaksBack
  • 189
  • 3
  • 10
  • Show the stacktrace please – Jens Aug 09 '15 at 18:48
  • 2
    As with any and all NullPointerExceptions (NPE), the key piece of information is the involved line, something I'm sure you've researched before coming here -- so which line is the offending one? – Hovercraft Full Of Eels Aug 09 '15 at 18:48
  • OK, --- which line is 24 and 26? – Hovercraft Full Of Eels Aug 09 '15 at 18:50
  • You never initialize the followingMoves ArrayList. Read up on debugging NPE's as you'll run into them a lot in the future, and you'll need to learn this skill. In brief, study the involved line(s), see which variable is null, then look back in the code to see why. – Hovercraft Full Of Eels Aug 09 '15 at 18:51
  • The recursive calls in the second constructor. – ZaksBack Aug 09 '15 at 18:51
  • Thank you! I knew it was something stupid but you know how it gets when you code for a couple hours. – ZaksBack Aug 09 '15 at 18:53
  • By the way yourncode could be improved in many ways (for example, your `win` method could be much shorter) – Dici Aug 09 '15 at 19:00
  • @Dici I know that it can be shorter, that method is temporary, Im going to be using basic linear and quadratic math functions so I can look for any sort of pattern. – ZaksBack Aug 09 '15 at 19:08
  • Sounds a bit overkill ! Anyway, good luck – Dici Aug 09 '15 at 19:09
  • @Dici It is a bit, but the board size is scalable, and so math needs to be used. a simple for loop would only find so much. – ZaksBack Aug 09 '15 at 19:15
  • @user2379692 if the rules stay the same with an nxn board (n marks horizontally,vertically or diagonally to win) then a simple code with a few loops can solve this problem for any number n – Dici Aug 10 '15 at 08:37

0 Answers0