import java.io.*;

/*
 *  Class Name:     HexGrid
 *  Description:    Hex Grid test class
 *  Author:         Ng Woon Liam William
 *  Language:       Java
 *  Date:           23/8/1999
 *  Public functions: HexGrid(String fileName)
 *                    void showGrid()
 *                    int occupied()
 *                    boolean contiguous()
 *                    int units()
 *                    int largest()
 *  Private functions: StartWhere
 *                     Chained
 *                     origGrid
 */
class HexGrid {

    // initialisation of variables
    int row = 0, col = 0, rowLength = -1, colLength = -1;  
    int startRow = 0, startCol = 0;
    int diff_charCount = 0, ascii_value = 0;
    char hGrid [][], origGrid[][];

    /*
     *  Function name:  HexGrid
     *  Purpose:        accepts input from a text file 
     */ 
    public HexGrid(String fileName) throws IOException, FileNotFoundException{

       int chr;
       String rowCol = "";

       FileReader theFile;
       BufferedReader fileIn = null;
       theFile = new FileReader (fileName);
       fileIn  = new BufferedReader( theFile );

       try {
          while (true) {
             chr = fileIn.read();
             if (colLength != -1) {
                //   create array dimension
                hGrid = new char [rowLength][colLength];
                origGrid = new char [rowLength][colLength];
                break;
             }
             if (Character.isWhitespace((char)chr)) {
                if (rowLength == -1)
                   rowLength = Integer.parseInt(rowCol);
                else
                   colLength = Integer.parseInt(rowCol);
                rowCol = "";
             }
             else
                rowCol += (char)chr;
          }  //while loop      

          row = 0;   //initialise values     
          col = -1;
          for (int total = 0; (chr = fileIn.read()) != -1; total++) {
             if ( ! (Character.isWhitespace((char)chr)) ) {
                col++;
                hGrid[row][col] = (char)chr;
                origGrid[row][col] = hGrid[row][col];

                if (col == (colLength-1)) {   //last column reached
                   row++;
                   col = -1;
                }
             }
          }
       }
       catch( Exception e ) {
          System.out.println( e );
       }

       // Close the stream
       try {
          if(fileIn != null )
             fileIn.close( );
       }
       catch( IOException e ) {
       }
    }

    /*
     *  Function name:  showGrid
     *  Purpose:        display hexagonal grid 
     */ 
    public void showGrid() {

       for (row = 0; row < hGrid.length; row++) {
          if (row%2 == 1)    //odd rows
             System.out.print(" ");

          for (col = 0; col < hGrid[row].length; col++) {
             if (col == (colLength-1))   //last column reached
                System.out.println(hGrid[row][col]);
             else
                System.out.print(hGrid[row][col] + " ");
          }
       }
    }

    public int occupied() {

       int hexes = 0;
       for (row = 0; row < hGrid.length; row++) {
          for (col = 0; col < hGrid[row].length; col++) {
             if (hGrid[row][col] == '#')
                hexes++;
          }
       }
       return hexes;
    }

    public boolean contiguous() {

       boolean contig;
       StartWhere();
       origGrid();
       diff_charCount = (Character.getNumericValue((char)ascii_value));
       if (diff_charCount == 1)    //confirm 1 contiguous group
          contig = true;
       else
          contig = false;
       return contig;
    }

    public int units() {

       StartWhere();
       origGrid();
           // this gives the number of separate contiguous groups
       diff_charCount = (Character.getNumericValue((char)ascii_value));
       return diff_charCount;
    }

    public int largest() {

       int biggest = 0, tempCount = 0; 
       StartWhere();
       diff_charCount = Character.getNumericValue((char)ascii_value);

       for (int chars = 1; chars <= diff_charCount; chars++) {
          tempCount = 0;
          for (row = 0; row < hGrid.length; row++) {
             for (col = 0; col < hGrid[row].length; col++) {
                if ( Character.getNumericValue(hGrid[row][col]) == chars )
                   tempCount++;
             }
          }
          if (biggest < tempCount)  //store largest contiguous occupied cells
             biggest = tempCount;
       }

       origGrid();
       return biggest;
    }

    /*
     *  Function name:  StartWhere
     *  Purpose:        search for start position of '#'
     */ 
    private void StartWhere() {
       
       boolean hexFound = false;
       ascii_value = (int)'0';

       do {
          hexFound = false;
          for (col = 0; col < colLength; col++) {     //start from column
             for (row = 0; row < rowLength; row++) {
                if (hGrid[row][col] == '#') {
                   startRow = row;
                   startCol = col;
                   hexFound = true;
                   break;
                }
             }
             if (hexFound)
                break;
          }
          if (hexFound == false)
             break;
          ascii_value = ascii_value + 1;
          Chained(startRow, startCol, (char)ascii_value);

       } while (hexFound == true);
       return;
    }

    /*
     *  Function name:  Chained
     *  Purpose:        to recursively visit all cells and count them
     */ 
    private void Chained(int startRow, int startCol, char asciicode) {

       if (hGrid[startRow][startCol] == '#') {

          hGrid[startRow][startCol] = asciicode;  //change '#' to '1', '2'

          if (startRow%2 == 1) {      //test for odd rows
             if (startRow - 1 >= 0)   //test for NOT out of boundary
                Chained(startRow - 1, startCol, (char)ascii_value);      //odd & NW
          }
          else {
             if ( (startRow - 1 >= 0) && (startCol - 1 >= 0) )
                Chained(startRow - 1, startCol - 1, (char)ascii_value);  //even & NW
          }

          if (startRow%2 == 1) {  
             if ( (startRow - 1 >= 0) && (startCol + 1 < colLength) )
                Chained(startRow - 1, startCol + 1, (char)ascii_value);  //odd & NE
          }
          else {
             if (startRow - 1 >= 0) 
                Chained(startRow - 1, startCol, (char)ascii_value);      //even & NE
          }

          if (startCol + 1 < colLength)  //test for NOT out of boundary
             Chained(startRow, startCol + 1, (char)ascii_value);         //(odd or even) & E

          if (startRow%2 == 1) {
             if ( (startRow + 1 < rowLength) && (startCol + 1 < colLength) )
                Chained(startRow + 1, startCol + 1, (char)ascii_value);  //odd & SE
          }
          else {
             if (startRow + 1 < rowLength) 
                Chained(startRow + 1, startCol, (char)ascii_value);      //even & SE
          }

          if (startRow%2 == 1) {   
             if (startRow + 1 < rowLength) 
                Chained(startRow + 1, startCol, (char)ascii_value);      //odd & SW
          }
          else {
             if ( (startRow + 1 < rowLength) && (startCol - 1 >= 0) )
                Chained(startRow + 1, startCol - 1, (char)ascii_value);  //even & SW
          }

          if (startCol - 1 >= 0)   //test for NOT out of boundary
             Chained(startRow, startCol - 1, (char)ascii_value);         //(odd or even) & W
       }
    }

    /*
     *  Function name:  origGrid
     *  Purpose:        to restore cell array back to its original chars
     */ 
    private void origGrid() {

       for (row = 0; row < hGrid.length; row++) {
          for (col = 0; col < hGrid[row].length; col++) {
             hGrid[row][col] = origGrid[row][col]; 
          }
       }
    }

}
