/******************************* FILE HEADER **********************************
    Program:          Tic Tac Toe, version 1
    File:             Board.java (replaces original version)
    Main File:        TicTacToe1.java
    
    Author:           James D. Skrentny
                      copyright 2000, all rights reserved
    Course:           CS 302, Fall 2000, Lectures 1 & 2
    
    Compiler:         CodeWarrior IDE 4.0 (JDK 1.2)
    Platform:         Windows NT 4.0
 **************************** 80 columns wide *********************************/

/**
 * The Board class represents the N by N grid on which players make
 * their marks in the game Tic Tac Toe.
 *
 * Bugs: none known
 **/
 
/* The following concepts are illustrated:
 *     - use of a 2D array
 *     - use of char type
 *     - changing the internal structure of a class without affecting
 *       the classes that use it
 *       - changing private data members
 *       - changing public method implementations
 *       - elimination of private method (move2cell remove)
 *       - addition of new method (see second constructor)
 */

public class Board {

    private char[][] board;           // board change to a 2D array of chars
                 
    private final char EMPTY = ' ';   // space char for empty cells
    
    /**         
    * Constructs a default 3 by 3 grid with empty cells for the playing board.
    **/
    public Board () {
        board = new char[3][3];
        for (int row = 0; row < 3; row++)
            for (int col = 0; col < 3; col++)
                board[row][col] = EMPTY;
    }
    
    /**         
    * Constructs a N by N grid with empty cells for the playing board.
    **/
    public Board (int n) {
        board = new char[n][n];
        for (int row = 0; row < n; row++)
            for (int col = 0; col < n; col++)
                board[row][col] = EMPTY;
    }
    
    /**         
    * Puts a player's mark in the cell corresponding to the specified move. 
    *
    * @param move the specified move (i.e. row and column coordinates)
    * @param mark the player's mark to be made on the board, typically "X" or "O"
    **/
    public void markMove(Move move, Mark mark) {
        board[move.getRow() - 1][move.getCol() - 1] = mark.toString().charAt(0);
    }
    
    /**         
    * Displays the board in the console window.
    * Assumption: a player's mark is a single character and the board size
    * is no larger than 9 by 9.
    **/
    public void display () {

        // display the column heading
        System.out.println();
        System.out.print("   col ");
        for (int col = 0; col < board.length; col++) {
            System.out.print(col + 1);
            if (col < board.length - 1)
                System.out.print(":");
        }
        System.out.println();
        System.out.println();

        // display the board
        for (int row = 0; row < board.length; row++) {
            System.out.print("row " + (row + 1) + ": ");
            for (int col = 0; col < board.length; col++) {
                System.out.print(board[row][col]);
                if (col < board.length - 1)
                    System.out.print("|");
            }
            if (row < board.length - 1)
                System.out.println("\n       -----");
            else
                System.out.println();
        }
        System.out.println();
    }
    
    /**         
    * Checks if the cell is empty at the location of a specified move.
    *
    * @param move the specified move (i.e. row and column coordinates)
    * @return returns true if the cell is empty at the location specified by move,
    * otherwise false is returned
    **/
    public boolean cellFree (Move move) {
        return board[move.getRow() - 1][move.getCol() - 1] == EMPTY;
    }
    
    /**         
    * Checks if all marks in the specified row are the same as the specified mark.
    *
    * @param row the row specified to be checked, 1 <= row <= board size 
    * @param mark the mark specified to be matched
    * @return true if all cells in the specified row have the specified mark,
    * otherwise false is returned
    **/ 
    public boolean checkRow (int row, Mark mark) {
        // defensive: check if invalid row
        if (row < 1 || row > board.length)
            return false;
      
        // check for "N in a row"
        for (int col = 0; col < board.length; col++)
            if (board[row - 1][col] != mark.toString().charAt(0))
                return false; // a cell didn't match

        // must be "N in a row"
        return true;    
    }
    
    /**         
    * Checks if all marks in the specified col are the same as the specified mark.
    *
    * @param col the column specified to be checked, 1 <= col <= board size 
    * @param mark the mark specified to be matched
    * @return true if all cells in the specified column have the specified mark,
    * otherwise false is returned
    **/ 
    public boolean checkCol (int col, Mark mark) {
        // defensive: check if invalid col
        if (col < 1 || col > board.length)
            return false;
      
        // check for "N in a col"
        for (int row = 0; row < board.length; row++)
            if (board[row][col - 1] != mark.toString().charAt(0))
                return false; // a cell didn't match

        // must be "N in a col"
        return true;    
    }
    
    /**         
    * Checks if all marks in the specified diagonal are the same as the specified mark.
    *
    * @param diag the diagonal specified to be checked, must be 1 or 2
    *     1 is the diagonal from upper-left to lower-right
    *     2 is the diagonal from upper-right to lower-left
    * @param mark the mark specified to be matched
    * @return true if all cells in the specified diagonal have the specified mark,
    * otherwise false is returned
    **/ 
    public boolean checkDiag (int diag, Mark mark) {
        // defensive: check if invalid diag
        if (diag != 1 && diag != 2)
            return false;
      
        if (diag == 1) {  // braces required to avoid dangling else
            // check for "N in a diag 1"
            for (int diag1 = 0; diag1 < board.length; diag1++)
                if (board[diag1][diag1] != mark.toString().charAt(0))
                    return false; // a cell didn't match
        } else
            // check for "N in a diag 2"
            for (int diag2 = 0; diag2 < board.length; diag2++)
                if (board[diag2][board.length - diag2 - 1] != mark.toString().charAt(0))
                    return false; // a cell didn't match

        // must be "N in a diag"
        return true;    
    }
    
}
