
/*************************************************************
 * Plays "eight puzzle" on the screen, using the mouse.
 * Uses the EightPuzzle class to manage the moves.
 * The board is 3X3, displayed as a window containing
 * 8 "Square" objects (always with one space of the board left
 * empty). When a player makes a move, he/she clicks on a Square.
 * If the move is legal, the Square moves into the empty space.
 * The area below the board gives the state of the game (whether move
 * is legal, whether the puzzle is solved, etc.).  The user may
 * re-initialize the game via the "Click here to restart" button
 * at the top.
 * Author: F. Green
 * Last modified: 11/26/2007
 *************************************************************/

//squareSize is, well... the size of a square!
//topMargin and bottomMargin are adjusted so that there is
//room for the button at the top and text at the bottom.
//bottomTextOffset is for vertically positioning the text
//at the bottom. All these things can be adjusted for different
//fonts or square sizes.
int squareSize, topMargin, bottomMargin, bottomTextOffset;
//The row and column where the mouse is clicked:
int row, column;
//The underlying EightPuzzle class:
EightPuzzle game;
//font for the bottom text:
PFont bottomTextFont;
//The 8 Squares:
Square [] s;
//The top button ("PushBar"):
PushBar b;

//In setup() we initialize all the size variables, the EightPuzzle
//object, the array of Squares, etc.
void setup ()
{
  //Initialize various sizes and background:
  squareSize = 72;
  topMargin = 20;
  bottomMargin = 30;
  bottomTextOffset = 22;
  //size(3*squareSize, 3*squareSize + topMargin + bottomMargin);
  size(216, 267);
  background(0);

  //Initialize various objects:
  game = new EightPuzzle();
  b = new PushBar(topMargin - 1, 2);
  //Initialize 9 Squares, although we only use 8;
  //the 9th is there just to simplify the nested loops.
  s = new Square[9];
  int i = 0;
  for (int row = 0; row < 3; row++)
    for (int column = 0; column < 3; column++)
    {
      s[i] = new Square(game.numberAt(row, column), 
      squareSize, column*squareSize,
      row*squareSize + topMargin, row, column);   
      i++;
    }

  //bottom text:
  bottomTextFont = loadFont("STXihei-14.vlw");
  bottomTextMessage("Click square to move.", 25);

  frameRate(250);
  smooth();

}

//Draw loop: 
//      (a) Render the background behind the squares.
//      (b) Move (if necessary) and render all Squares.
void draw ()
{
  //black background:
  fill(0);
  //starts just below the top button and stops short of the bottom text:
  rect(0, topMargin + 3, width, height - topMargin - bottomMargin);

  //move and render all Squares:
  for (int i = 0; i < 8; i++)
  {
    s[i].move();
    s[i].render();
  }

}//draw

/******************************************************
 * Respond to a mouse click. This takes action only if the
 * mouse click is *not* over the button b. In that case the
 * state of the game is examined. Depending on whether the
 * mouse is over a moveable Square, or if the game is won,
 * appropriate action is taken.
 ******************************************************/
void mouseClicked () 
{
  if (!b.mouseOver())
  {
    int row, column;
    //Row and column are the same within a square of
    //the board. 
    //MODIFY: Find the correct row and column from mouseX and mouseY.
    //Hint: Divide by squareSize, but for the row, subtract topMargin
    //from the y-coordinate first.
    int x = mouseX;
    int y = mouseY;
    row = 0;
    column = 0;

    if (game.legalMove(row,column) && !game.gameWon())
    {
      int newRow = game.newRow();
      int newColumn = game.newColumn();
      //MODIFY: Find a square in the current row/column that can be moved.
      //Loop through the s-array, and if you find one that can move from
      //(row, column) to (newRow, newColumn), using the canMove() method
      //of Square, then break out of the loop:
      //Make a move:
      game.addAMove(row, column);
      //MODIFY: See if the puzzle is solved; if so, announce it
      //in the text field. Otherwise say how many moves it is.
      //You enter stuff in the text field like this:
      bottomTextMessage("   y = " + y + "; x = " + x, 35);
    }//if
    
    //MODIFY: Let the user know if the move is illegal, or
    //if the puzzle is solved and a new one should be started.
    //Hint: Use an "else" and "else if" here.
    	  
  }
}//mouseClicked

/******************************************************
 * If the mouse is pressed, and we're over the button,
 * then press it.
 ******************************************************/
void mousePressed ()
{
  b.press();
}

/******************************************************
 * If the mouse is released, and we're over the button,
 * then release it.
 ******************************************************/
void mouseReleased ()
{
  b.release();
}

/******************************************************
 * Print the given string at the bottom of the applet.
 * xOffset determines how much the string is indented.
 ******************************************************/
void bottomTextMessage (String message, int xOffset)
{
  //background for the message:
  fill(50);
  rect(0, 3*squareSize + topMargin + 3, width, bottomMargin);
  //the message itself:
  fill(200);
  textFont(bottomTextFont, 14);
  text(message, xOffset, 3*squareSize + topMargin + bottomTextOffset);
}
