/* Maze.java */

import java.io.*;

/**
 *  Maze:  Two-dimensional grid.
 *  Each cell of the maze grid is said to be either
 *  "empty" (no wall), "blocked" (wall), or "marked"
 *  (visited).
 */

public class Maze {
  /** Creates a new empty maze  */
  public Maze() throws IOException {
    read();
  }

  /** Reinitializes this maze to a grid of dimensions (size x size) with
   *   all empty points.
   */
  private void init( int s ) {
    size = s;
    size2 = size*size;
    points = new boolean [size2];
    marks = new boolean [size2];
  }
  
  /** Returns a Point corresponding to the maze's starting point.
   */
  public Point startPoint() {
    return new Point( 0, 0 );
  }

  /** Returns a Point corresponding to the maze's finish point/
   */
  public Point endPoint() {
    return new Point(size-1, size-1);
  }

  /** Sets all points of the maze to be empty.
   */
  public void clearMarks() {
    int i;
    for( i = 0; i < size2; i++ )
      marks[i] = false;
  }

  /**  Returns true <==> pt refers to an empty cell
   *   in the maze.
   */
  public boolean validPoint( Point pt ) {
    return (pt.row() >= 0 && pt.row() < size &&
	    pt.column() >= 0 && pt.column() < size &&
	    points[ptIndex(pt)]);
  }

  /** Assumes: validPoint(pt) == true
   *  Rturns true <==> pt has been marked (i.e., visited)
   */
  public boolean pointMarked( Point pt ) {
    return marks[ptIndex(pt)];
  }

  /** Assumes:  validPoint(pt) == true
   *  Marks the point pt as having been visited
   */
  void markPoint( Point pt ) {
    marks[ptIndex(pt)] = true;
  }

  /** Maze initialized from user input
   */
  private void read() throws IOException {
    // initialize for reading input
    StandardInput input = new StandardInput();

    System.out.println( "Enter the length of one side of the maze." );
    System.out.println( "(The maze is assumed to be square.)" );
    System.out.print( "\n> " );

    int s = input.readInt();
    init(s);

    System.out.println( "\nNow enter each row, followed by a <CR>" );
    System.out.println( "Use a . for open points, + for blocked" );
    System.out.println( "with a space between each.\n" );

    char c;
    int  i = 0;

    int  row;
    for( row = 0; row < size; row++ ) {
      int col;
      for( col = 0; col < size; col++ ) {
	c = input.readByte();
	points[i++] = (c == '.');
      }
    }
  }


  /** Returns a String corresponding to a text picture
   *          of the maze
   */
  public String toString()
  {
    String result = "";

    int i = 0;
    int row;
    for( row = 0; row < size; row++ ) {
      int col;
      for( col = 0; col < size; col++ ) {
	if( points[i++] ) {
	  result = result + ".";
	} else {
	  result = result + "+";
	}
	result = result + " ";
      }
      result = result + "\n";
    }
    return result;
  }


  /** Assumes:  validPoint(pt) == true
   *  Returns an index i such that points[i] and marks[i]
   *         corresponds to the point pt
   */
  private int ptIndex( Point pt ) {
    return (pt.row()*size + pt.column());
  }

  /*  Data fields */
  private int size;            // length of a side of the grid
  private int size2;           // size * size
  private boolean[] points;   // grid cells; true <==> empty
  private boolean[] marks;
  /* invariants: 
   *  size*size == size2
   *  points.length == size  && marks.length == size
   *  for all i, 0 <= i <= size, points[i].length == size
   *  for all i, 0 <= i <= size, marks[i].length == size
   */
};