/******************************* FILE HEADER **********************************
    Program:          Tic Tac Toe, version 1
    File:             Board.java
    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 3 by 3 grid on which players make
 * their marks in the game Tic Tac Toe.
 *
 * Bugs: none known
 **/
 
/* The following concepts are illustrated:
 *     - console output (see display)
 *     - switch statement (see markMove and cellEmpty)
 *     - nested if statements (see checkRow, checkCol, checkDiag)
 *     - private method (see move2cell)
 */

public class Board {

    private Mark cell1, cell2, cell3,       // board cells arranged as shown
                 cell4, cell5, cell6,
                 cell7, cell8, cell9;
                 
    private final Mark empty = new Mark(" ");   // space mark for empty cells
    
    /**         
    * Constructs a 3 by 3 grid  with empty cells for the playing board.
    **/
    public Board () {
        cell1 = cell2 = cell3 =
        cell4 = cell5 = cell6 =
        cell7 = cell8 = cell9 = 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) {
        switch (move2Cell(move)) {
            case 1: cell1 = mark; break;
            case 2: cell2 = mark; break;
            case 3: cell3 = mark; break;
            case 4: cell4 = mark; break;
            case 5: cell5 = mark; break;
            case 6: cell6 = mark; break;
            case 7: cell7 = mark; break;
            case 8: cell8 = mark; break;
            case 9: cell9 = mark; break;
        }
    }
    
    /**         
    * Displays the board in the console window.
    * Assumption: a player's mark is a single character.
    **/
    public void display () {
        System.out.println();
        System.out.println("   col 1:2:3\n");
        System.out.println("row 1: " + cell1 +"|"+ cell2 +"|"+ cell3);
        System.out.println("       -----");
        System.out.println("row 2: " + cell4 +"|"+ cell5 +"|"+ cell6);
        System.out.println("       -----");
        System.out.println("row 3: " + cell7 +"|"+ cell8 +"|"+ cell9);
        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) {
        switch (move2Cell(move)) {              // convert move to cell number
            case 1: return cell1.equals(empty);
            case 2: return cell2.equals(empty);
            case 3: return cell3.equals(empty);
            case 4: return cell4.equals(empty);
            case 5: return cell5.equals(empty);
            case 6: return cell6.equals(empty);
            case 7: return cell7.equals(empty);
            case 8: return cell8.equals(empty);
            case 9: return cell9.equals(empty);
            default: return false;              // defensive
        }
    }
    
    /**         
    * Checks for "three in a row", for a specified row and mark.
    *
    * @param row the row specified to be checked, must be 1, 2, or 3
    * @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) {
        if (row == 1 && mark.equals(cell1) &&
            mark.equals(cell2) && mark.equals(cell3))
            return true;
        else if (row == 2 && mark.equals(cell4) &&
            mark.equals(cell5) && mark.equals(cell6))
            return true;
        else if (row == 3 && mark.equals(cell7) &&
            mark.equals(cell8) && mark.equals(cell9))
            return true;
        else // either row number invalid or not "three in a row"
            return false;
    }
    
    /**         
    * Checks for "three in a row", for a specified column and mark.
    *
    * @param col the column specified to be checked, must be 1, 2, or 3
    * @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) {
        if (col == 1 && mark.equals(cell1) &&
            mark.equals(cell4) && mark.equals(cell7))
            return true;
        else if (col == 2 && mark.equals(cell2) &&
            mark.equals(cell5) && mark.equals(cell8))
            return true;
        else if (col == 3 && mark.equals(cell3) &&
            mark.equals(cell6) && mark.equals(cell9))
            return true;
        else // either colum number invalid or not "three in a row"
            return false;
    }
    
    /**         
    * Checks for "three in a row", for a specified diagonal and 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) {
        if (diag == 1 && mark.equals(cell1) &&
            mark.equals(cell5) && mark.equals(cell9))
            return true;
        else if (diag == 2 && mark.equals(cell3) &&
            mark.equals(cell5) && mark.equals(cell7))
            return true;
        else // either diagonal number invalid or not "three in a row"
            return false;
    }
    
    /**         
    * Coverts a move (i.e. row and column coordinates) into corresponding
    * cell number.
    **/ 
    private int move2Cell(Move move) {
        return (move.getRow() - 1) * 3 + move.getCol();
    }
}
