Controllable
interface that they shared), and add some new classes to the project that work with the interface.
Spencer Racca-Gwozdzik and Noah McCullough
Brendan Bell and Noah Sprenger
Bonacic Bonacic and Grey Roppolo
Asa Bonner and Devan Meyer
Liam Bradley and Cian Monaghan
Jinwoo Choi and Rohan Crossland
Brett Garon and Ethan Spence
Lucas Calaff and Ella Slattery
Jacob Endrina and Lucas Takiff
Gabriel Guinn and Noah Zimmer
Mackenzie Leibee and Stephen Rice
AdventureGame
is our old friend "Lost in the Dark". It implements the same Controllable
interface we used in lab, and can therefore be used with the graphical Controller
we worked with in lab. The only difference here is that the game gives away the top-secret location of the flashlight when the game starts. This will make it easier to test some of the new code you write. There's a Tester
class again that, at the moment, creates an AdventureGame
instance being controlled by a Controller
object. Note that the Controllable
interface helps the game and the controller "fit together". It provides the "contract" that both classes use to ensure that the controller can operate the game. To drive home this concept, we'll write two new classes — one that implements the interface (like AdventureGame
does), and another that can interact with Controllable
objects like the Controller
does.
.java
files, or open the project in BlueJ. Familiarize yourselves with the code that's there. (It should look awfully familiar, since you just worked with most of the starter code in lab.) Try running the runControllers()
method in Tester
and verify that you can play Lost in the Dark via the graphical controller.
Controllable
object.
If we wanted to find the flashlight manually, we could use the graphical controller to do a methodical search starting at position 0,0, and keep trying new positions until "You stumbled across the flashlight!!!" appeared in the display. But the text that appears in the display window of the controller comes from the Controllable
object's toString()
method, so we don't even need the graphical controller to do our search! We can call right()
, up()
, etc, on an object until its toString()
returns the appropriate results. For example, in BlueJ's codepad we could create an instance of the game and "manually" call direction methods and toString()
until we find the flashlight. The sample interactions below show me getting unreasonably lucky in finding it, but you get the picture:
> AdventureGame game = new AdventureGame(); > game.right(); > game.toString() "Nope" (String) > game.right(); > game.toString() "Not yet" (String) > game.right(); > game.toString() "Bummer" (String) > game.up(); > game.toString() "Nope" (String) > game.left(); > game.toString() "You stumbled across the flashlight!!!" (String)
Of course, we don't want to do it manually — we want to write a program to carry out those steps for us automatically. The search space is a grid, with position 0,0 at the lower left-hand corner, but our program can't just access it like an array. The only thing it can do is use right()
, up()
, left()
, and down()
to navigate through the space. To do a methodical search it'll have to do a zig-zagging path like the one shown below. The picture shows a flashlight being found at postion 5,3, using a search pattern like the one you should implement. (Note that it makes an assumption about how wide the search area is.)
Now, finally, the code-writing part! Define a new class called "Autopilot
". Inside the class, write a single static
method called find
. The find
method should take four inputs: A reference to the Controllable
object that we're going to run our search on, a String containing a search term we're looking for (e.g. "You stumbled across the flashlight!!!"), and two integers specifying the width and height of the search pattern that should be run. The method should do a methodical search like the one in the picture above, checking the toString()
results for each position. If the toString()
result contains the search term, the method should print where the string was found and then return. For full credit, your code should ensure that the object being controlled does not stray outside of the search area. If the entire search space has been investigated without success, it should print a message reporting failure as shown below. (In the interactions below, the results would be printed to the terminal window, not displayed in the codepad — I'm showing them all here for simplicity.) Since the flashlight is placed randomly, you might get different results, but if you search a small enough area you can test the case where the flashlight's not found.
> AdventureGame game = new AdventureGame(); > Autopilot.find(game, "stumbled", 9, 7); Found it at 5,3: "You stumbled across the flashlight!!!" > game = new AdventureGame(); > Autopilot.find(game, "stumbled", 2, 3); Autopilot didn't find "stumbled"
Your find
method should assume that the Controllable
object it's passed is currently at position 0,0, and that the search doesn't need to consider locations with negative coordinates. (We could write a fancier find
method if we wanted to consider negative coordinates.) Once your method is written, you can test your code by calling the testAutopilot()
method in Tester
after uncommenting the first two lines.
Controllable
ClassControllable
interface, and look for things other than flashlights. To prove the point, let's create another class for Autopilot to "drive": A Remotely Operated Vehicle that prowls around the sea floor prospecting for minerals. When you open the ROV
class you'll see that it already contains a 2D array of values to be used to supply the simulated readings on a portion of the sea floor. It's hard to read in the Java code, but it corresponds to the "map" below:
Finish implementing the ROV class, making sure that it implements the Controllable
interface. You'll want to add code that keeps track of the position of the ROV, and updates that position when up/down/left/right are called. Whenever toString() is called, it should return a simulated reading for the ROV's current position. (If there's a value at the corresponding position in the 2D array of values, use a string containing that value as the simulated reading, otherwise use 0.) It should be possible to "drive" your ROV into negative coordinates, at which point its readings should be "0"
. More detailed information on these methods is available in the documentation.
Your ROV should also keep a running total of the readings from all of positions it has visited (whether toString()
was called there or not). That'll give us a sense of how "valuable" the area it has explored is. The function()
method should print a message containing the current total. The interactions below show how your ROV should work. (Here again, the printed messages from function()
would appear in the terminal window, not the codepad, but I'm showing them here so you can see which commands would produce output.)
> ROV sub = new ROV(); > sub.toString() "4" (String) > sub.function(); Sum of all readings is 4 > sub.right(); > sub.right(); > sub.up(); > sub.toString() "3" (String) > sub.function(); Sum of all readings is 10
runControllers()
in the Tester
class. Try running the runControllers()
method and it should now create two graphical controllers — one driving the ROV, and one playing the game. This is the power of interfaces! The controller didn't know anything about the ROV class you were going to create, but it can control it since it implements the Controllable
interface. You can use the controller to further stress-test your ROV and make sure it behaves as expected.
Autopilot
's find()
should work with the ROV too! Uncomment the remaining code in testAutopilot()
in the Tester
class, and verify that it can navigate an ROV to find the 10 — and that if the search area doesn't include the 10, that it fails as expected.
find
method is implemented properly
@param
and @return
directives) above each method. When you're convinced it's ready to go, zip up your project folder and submit it via the Canvas submission tool for Assignment #2. (Please contact me if you need help with the submission process.) Only one member of the team should submit the project, but make sure all names are in the comments at the top of each class.