Your goal is to create a human-playable 15-puzzle game. For an added challenge, make the run button solve the puzzle automatically!! The goal of this exercise is to give you more experience working with a multi-class program and reading the GridWorld API. You’ll work in pairs.
We will use GridWorld as a foundation since it so nicely displays items in a grid. We will NOT use actors but instead will create a new class called Tile. A Tile has two methods: getText() and getColor(). It turns out that when items are displayed in a Grid, if they have no image, the result of those two methods will be used to display them (read more in the rendering occupants section here).
Because we aren’t using Actors, we will not be using an ActorWorld, either. It turns out that a World is just a container for a Grid of a particular type of items so you will create your own World to contain tiles. An ActorWorld extends World<Actor> and your World will extend World<Tile>.
Begin by writing the constructor for your new World. What should happen when a puzzle is created? You may want to use the setMessage method to give instructions to the user. You will also need to set the grid to be bounded and 4×4. Review the API to learn more about World methods. Most importantly, you’ll need to create tiles labeled A through O and place them in the world in order using add. There are many ways to do this. Think of a Grid as a 2-D ArrayList and Locations as a way to index into the list.
For testing, create a PuzzleRunner class with a main that just creates your World class and calls its show method.
When a location on the Grid is clicked, the locationClicked method of the World that contains the Grid is called. You can thus use that method to react to user input. The method is automatically passed the Location that was clicked. Write a locationClicked method that checks to see if the location clicked is a Tile (instead of the blank). If it’s a tile, figure out where it can move to. You should write a private method for this that returns a Location that the tile can move to or null if it can’t move. If the tile can move, move it. You will want to use the Grid remove and put methods.
At this point, you should have tiles that you can move around. Test this thoroughly to make sure you haven’t forgotten anything. For example, when I was first writing this, I used getEmptyAdjacentLocations (a Grid method) to figure out where the tile could move to so my tiles were moving diagonally (recall that there are 8 adjacent locations including the diagonals)!
Now would be a good time to make sure that the puzzle is shuffled at the beginning. Think of different strategies for this. One is to randomly pick tiles a few hundred times and slide them if you can. You do not want to swap tiles because this could make your game unbeatable. Write a private method to shuffle your tiles and call it from the end of your constructor.
The last step is to see whether the user has won. You will need to loop over every Location in the Grid and see whether letters are in increasing order. Write a private method that returns a boolean to do this. You will want to call your method at the end of locationClicked and show a message box like you did in Snake to tell the user that they have won.