/** represents a notakto board of a given size */
public class NotaktoBoard {
    
    /** 2-dimensional array representing the board
     * coordinates are counted from top-left (0,0) to bottom-right (size-1, size-1)
     * board[x][y] == false   signifies free at position (x,y)
     * board[x][y] == true    signifies that some made a move on (x,y)
     */
    private boolean[][] board;
    
    /** size of the (quadratic) board */
    private int size;
    
    /** constructor for creating an empty board for a given number of players */
    public NotaktoBoard(int size) {
        this.size = size;
        this.board = new boolean[this.getSize()][this.getSize()];
    }
    
    /** checks whether the board is free at the given position */
    public boolean isFree(Coordinate c) {
        if (!c.checkBoundaries(this.getSize(),this.getSize())) {
            throw new IllegalArgumentException("This coordinate sucks!");
        }
        return !this.board[c.getY()][c.getX()];
    }
    
    /** record that a given player made a move at the given position
     * checks that the given positions is on the board
     * checks that the player number is valid 
     */
    public void addMove(Coordinate c) {
        if (!c.checkBoundaries(this.getSize(),this.getSize())) {
            throw new IllegalArgumentException("This coordinate sucks!");
        }
        this.board[c.getY()][c.getX()] = true;
    }

    /** returns false if no player has won (yet)
     * otherwise returns true
     */
    public boolean checkWinning() {
        for (int i = 0; i < this.getSize(); i++) {
            if (checkSequence(new XYCoordinate(0,i), 1, 0)) {
                return true;
            }
            if (checkSequence(new XYCoordinate(i,0), 0, 1)) {
                return true;
            }
            if (checkSequence(new XYCoordinate(0,i), 1, 1)) {
                return true;
            }
            if (checkSequence(new XYCoordinate(i,0), 1, 1)) {
                return true;
            }
            if (checkSequence(new XYCoordinate(0,i), 1, -1)) {
                return true;
            }
            if (checkSequence(new XYCoordinate(i,this.getSize()-1), 1, -1)) {
                return true;
            }
        }
        return false;
    }
    
    /** internal helper function checking one row, column, or diagonal */
    private boolean checkSequence(Coordinate start, int dx, int dy) {
        int num = 0;
        while (start.checkBoundaries(this.getSize(),this.getSize())) {
            if (this.isFree(start)) {
                num = 0;
            } else {
                num++;
            }
            if (num == 3) {
                return true;
            }
            start = start.shift(dx,dy);
        }
        return false;
    }
    
    /** getter for size of the board */
    public int getSize() {
        return this.size;
    }
    
    /** pretty printing of the board
     * usefule for debugging purposes
     */
    public String toString() {
        String result = "";
        for (int y = 0; y < this.size; y++) {
            for (int x = 0; x < this.size; x++) {
                result += (this.board[y][x] ? "X" : " ")+" ";
            }
            result += "\n";
        }
        return result;
    }

}
