/************************************************************* * 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); 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); }