/*
 * 2006 Utah High School Programming Contest, University of Utah
 * Take-Home Problem
 *
 * Board.java
 *
 * This file contains the implementation of the Board class.
 */

/**
 * A <code>Board</code> represents the overall state of a Sudoku puzzle.
 *
 * <p>Basically, a board is an two-dimensional array of <code>Square</code>s.
 * The possible values of a square are represented by a <code>Square</code>
 * object within the array.  Additional constraints on the values of squares
 * are represented by "group" objects: <code>RowGroup</code>s,
 * <code>ColumnGroup</code>s, and <code>BlockGroup</code>s.  A
 * <code>Board</code> collects all of these things that describe a board, and
 * makes them available via "getter" methods.
 */
public class Board {
    /**
     * The height, in squares, of every "block" of squares on a Sudoku board.
     * The value for a traditional Sudoku puzzle is 3.
     */
    public static final int BLOCK_HEIGHT = 3;

    /**
     * The width, in squares, of every "block" of squares on a Sudoku board.
     * The value for a traditional Sudoku puzzle is 3.
     */
    public static final int BLOCK_WIDTH = 3;

    /**
     * The number of squares along all edges of a Sudoku board.  This is both
     * the height and width of the board, because Sudoku boards are square.
     */
    public static final int BOARD_SIZE = BLOCK_HEIGHT * BLOCK_WIDTH;

    /*************************************************************************/

    /**
     * The array of <code>Square</code> objects that represent the board.  The
     * width and height of this array are equal to <code>BOARD_SIZE</code>.
     * The array is index by [row,column], and the top-left square of the board
     * is at index [0,0].
     */
    private final Square[][] squares;

    /**
     * The <code>RowGroup</code> objects that track constraints within rows of
     * squares.  There are <code>BOARD_SIZE</code> rows on a board.  The
     * topmost row is number 0.
     */
    private final RowGroup[] rowGroups;

    /**
     * The <code>ColumnGroup</code> objects that track constraints within
     * columns of squares.  There are <code>BOARD_SIZE</code> columns on a
     * board.  The leftmost column is number 0.
     */
    private final ColumnGroup[] columnGroups;

    /**
     * The <code>BlockGroup</code> objects that track constraints within blocks
     * of squares.  The top-left block of the board is at index [0,0].
     *
     * <p>Note that the dimensions of this array are "swapped" with respect to
     * the dimensions of the blocks themselves.  That is, since the dimensions
     * of every block are <code>BLOCK_HEIGHT</code> rows by
     * <code>BLOCK_WIDTH</code> columns, the dimensions of the
     * <code>blockGroups</code> array are <code>BLOCK_WIDTH</code> by
     * <code>BLOCK_HEIGHT</code>.  This occurs because the overall Sudoku board
     * is square, with both height and width equal to <code>BLOCK_HEIGHT</code>
     * times <code>BLOCK_WIDTH</code>.
     */
    private final BlockGroup[][] blockGroups;

    /*************************************************************************/

    /**
     * Constructs a fresh <code>Board</code>.  The board has
     * <code>BOARD_SIZE</code> squares in each dimension (width and height).
     * Nothing is known about the values within the squares on the board.
     */
    public Board() {
        // Initialize the array of squares.
        squares = new Square[BOARD_SIZE][BOARD_SIZE];
        for (int i = 0; i < BOARD_SIZE; ++i) {
            for (int j = 0; j < BOARD_SIZE; ++j) {
                squares[i][j] = new Square(i, j);
            }
        }

        // Initialize the row groups.
        rowGroups = new RowGroup[BOARD_SIZE];
        for (int i = 0; i < BOARD_SIZE; ++i) {
            rowGroups[i] = new RowGroup(this, i);
        }

        // Initialize the column groups.
        columnGroups = new ColumnGroup[BOARD_SIZE];
        for (int i = 0; i < BOARD_SIZE; ++i) {
            columnGroups[i] = new ColumnGroup(this, i);
        }

        // Initialize the block groups.
        //
        // Note that the order of width and height are "reversed" here.  That
        // is, since the blocks are HxW arrays of squares, the complete board
        // is an WxH array of blocks.
        blockGroups = new BlockGroup[BLOCK_WIDTH][BLOCK_HEIGHT];
        for (int i = 0; i < BLOCK_WIDTH; ++i) {
            for (int j = 0; j < BLOCK_HEIGHT; ++j) {
                blockGroups[i][j]
                    = new BlockGroup(this, i*BLOCK_HEIGHT, j*BLOCK_WIDTH);
            }
        }
    }

    /**
     * Returns the <code>Square</code> at the given row and column.  Note that
     * the top-left square on the board is at coordinate [0,0].
     *
     * @param row  the row number
     * @param col  the column number
     * @return     the <code>Square</code> at the given coordinates
     */
    public Square getSquare(int row, int col) {
        return squares[row][col];
    }

    /**
     * Returns the <code>RowGroup</code> for the given row of the board.  The
     * topmost row is number 0.
     *
     * @param row  the row number
     * @return     the <code>RowGroup</code> for the given row
     */
    public RowGroup getRowGroup(int row) {
        return rowGroups[row];
    }

    /**
     * Returns the <code>ColumnGroup</code> for the given column of the board.
     * The leftmost column is number 0.
     *
     * @param col  the column number
     * @return     the <code>ColumnGroup</code> for the given column
     */
    public ColumnGroup getColumnGroup(int col) {
        return columnGroups[col];
    }

    /**
     * Returns the <code>BlockGroup</code> the contains the square at the given
     * board coordinates.  In particular, the row and column coordinates are in
     * terms of board squares, not in terms of the blocks themselves.
     *
     * @param row  the row number
     * @param col  the column number
     * @return     the <code>BlockGroup</code> the encompasses the coordinates
     */
    public BlockGroup getBlockGroup(int row, int col) {
        int blockRow = row / BLOCK_HEIGHT;
        int blockCol = col / BLOCK_WIDTH;
        return blockGroups[blockRow][blockCol];
    }
}

// End of file.

