Lab 8: Imperative Worlds ► Fundamentals II Introduction to Class-based Program Design General Texts Lectures Syllabus Lab Materials Assignments Code style Documentation ▼ Lab Materials Lab 1: Introduction to Eclipse and Simple Data Definitions Lab 2: Working with Self-Referential Data Lab 3: Working with Self-Referential Data Lab 4: Working with Abstract Classes, Problem Solving Lab 5: Higher-order functions Lab 6: Working with Cyclic Data Lab 7: Working with Array Lists Lab 8: Imperative Worlds Lab 9: Stress Tests and Big-O behavior Lab 10: An Introduction to the JUnit testing library ► Lab 8: Imperative Worlds Problem 1: The 15 Puzzle using impworld On this page: Problem 1: The 15 Puzzle using impworld 8.1 ← prev up next → Lab 8: Imperative Worlds Goals: We’re going to implement the 15 Puzzle using the Impworld library — short for imperative, in this case meaning uses mutation. Submission: There is no submission for this lab. You will need to know how to work with this library for the next assignment. Problem 1: The 15 Puzzle using impworld Start a new project, called FifteenGame, and add to it the two libraries above. Add a new file to the project, and add the following include directives: import java.util.ArrayList; import tester.*; import javalib.impworld.*; import javalib.worldimages.*; import java.awt.Color; The funworld library used methods (like onTick or onKeyEvent) that returned new World objects, which made testing easier: you could compare the old World to the new one. You could also return objects that were instances of different subclasses of World, as you might have done on Assignment 5: Space Invaders Game, to represent different “phases” of your gameplay. That’s not quite so easy to do with impworld... The impworld library uses methods that return void, and you must use side effects to change the current world to update it between ticks and on key events...but you still need to figure out how to test it! The 15 puzzle consists of four rows of four tiles, with one tile missing. Each tile has a number, and tiles can move into the hole if they are adjacent to it. Represent this information as follows: // Represents an individual tile class Tile { // The number on the tile. Use 0 to represent the hole int value; ... // Draws this tile onto the background at the specified logical coordinates WorldImage drawAt(int col, int row, WorldImage background) { ... } } class FifteenGame extends World { // represents the rows of tiles ArrayList
> tiles; ... // draws the game public WorldScene makeScene() { ... } // handles keystrokes public void onKeyEvent(String k) { // needs to handle up, down, left, right to move the hole // extra: handle "u" to undo moves ... } } To construct the tiles, you’ll need to construct 4 rows of 4 tiles each. Which loop structure (for-each or counted-for) do you think will be most appropriate here? (Hint: you’ll need two loops, one nested inside the other.) Implement swapping two tiles by their indices — how will this have to change from the swap method we did in class? To handle moving the tiles, you’ll need to determine whether a given move direction is currently possible: for example, if the hole is in the top-left corner, then you cannot move the hole any further up or left. It is up to you to interpret a keystroke of e.g. "left" as either “move the hole 1 cell left” or “move the tile to the right of the hole left to fill the hole”, and similarly for the other keys. You may find that one interpretation is more intuitive than the other, but it is a rather subjective choice. Be sure to document in you code which interpretation you chose! To start the game, create a Run configuration as usual, set the main class to tester.Main, and set the arguments to ExampleFifteenGame. Then create the ExampleFifteenGame class with at least this method: class ExampleFifteenGame { void testGame(Tester t) { FifteenGame g = new FifteenGame(); g.bigBang(120, 120); } } Obviously, you’ll need to write tests, too! To handle undoing moves: create another field in the FifteenGame class that is an ArrayList, which you’ll update on each keystroke by adding the key that was just pressed to the front of the list. When the "u" key is pressed, the most recent move (if any) will then be stored at the front of the list — you just have to figure out how to undo it! Reminder: read the The Image Library for documentation on how the image library works. ← prev up next →