CPS 112: Computational Thinking with Algorithms and Data Structures Homework 3
This little guy is Mosca the fly.
Unfortunately, Mosca is lost and he needs your help getting home. The problem is that there are hungry frogs like the one below, looking to eat little Mosca.
For this assignment you will develop a simple game called “Fly Away Home.” The basic idea behind the game is to safely move Mosca around a grid to the home square before he gets eaten. The user will control the movements of the fly using arrow keys, and the frogs will move on their own. I have provided you with most of the GUI implementation. In the rest of this description are the pieces you need to implement.
I strongly urge you to write and test the pieces individually.
I have provided you with two sample files for some basic testing, world0.txt and world1.txt but you should create other files for more testing. The main method is in FlyWorldGUI.java and it requires one command-line argument, a file. Taking the code provided to you without making any changes you can compile:
javac *.java
and you can run:
java FlyWorldGUI world0.txt
You can setup VS Code to run these commands for you when you press run button. Go to Run and Debug tab on the left (click on the play button with a bug on it), a select the “create a launch.json file”. In this file, find the section where "mainClass": "FlyWorldGUI". Add a line such that "args": "world0.txt". This section of the file should now look like the following (though your projectName value will be different):
{
"type": "java",
"name": "Launch FlyWorldGUI",
"request": "launch",
"mainClass": "FlyWorldGUI",
"projectName": "solution_9a2e04b4",
"args": "world0.txt"
}
This will run the FlyWorldGUI with the argument world0.txt. If you want to run with a different argument (e.g., world1.txt), you can change it in this json file.
Since you haven’t written any code yet, the program just shows a blank white square. When you’re done with this homework, the program should look something like this when you run it:
Part 0: Orientation
Look at the source code files provided to you. You will only make changes to three of these files!
Name |
Make Changes? |
Description |
FlyWorldGUI.java |
NO |
The main method. Draws the actual game board / graphics. Takes user input (but does not fully “handle” it). Defines useful constants. |
GridLocation.java |
NO |
Class to represent a “location.” Used on the game-board, in the fly, and in the frogs. |
Fly.java |
Yes |
Represents Mosca |
Frog.java |
Yes |
Represents the frogs and other predators |
FlyWorld.java |
Yes |
Represents the world itself, keeps track of fly and frogs, moves fly and the frogs, determines if the “game” is won / lost. |
Open the html_doc/allclasses.html file with a web browser. This is documentation about all of the code. It is generated from the comments in the code. This kind of documentation is called “Javadocs” hopefully you find it helpful! You can also read the source code of any file you want.
Part 1: Initializing the Grid
The grid will be initialized from an input file. You have been given two example files, world0.txt and world1.txt. The first line in the file indicates the number of rows and the number of columns (in that order). The remainder of the file provides information regarding the layout of the game.
. anormal/blanksquare.
h the home square (RED).
f the starting location of a frog.
s the starting location of Mosca (GREEN).
In FlyWorld.java is the FlyWorld class, which has several instance variables. Implement the constructor to open, read, and parse the world file specified by fileName so that you assign values to all of the instance variables, except for frogs.
GridLocation and Fly are just objects. Use their constructors (and the new keyword) to create them.
The world instance variable is a little bit weird at first. It is a 2D array of GridLocation Objects. Every location in that 2D array will need to be instantiated with a new GridLocation object.
1. If the location is the start position, set the background color to Color.GREEN (there's a
method for this in the GridLocation class), and set the start instance variable.
◦ Also, set the mosca instance variable, since the fly starts at the start!
-
If the location is the home square, set the background color to Color.RED and set the goal instance variable.
-
If the location is a frog you can just treat it as a normal / blank square for now.
When you’re done with part 1 you should have a grid with a green square, red square, and a fly. But, there are no frogs and you cannot move. Not very fun yet...
Part 2: Adding Frogs
In Frog.java fill in the currently empty constructor for the Frog class (see the Fly constructor for help). Be sure to add comments to the code that answer the question “why?”
Now go back and update the constructor in FlyWorld so that it...
-
initializes the frog array instance variable.
-
creates a Frog and adds it to the frog array, when an f is encountered in the file.
Note: There are four frogs in these worlds. But there may not be four for other worlds. So, think carefully about how big the frog array should be.
You should now see frogs on the screen when you run the program. Make sure you see all the frogs you should see based on the contents of the file. Now let's get things moving...
Part 3: Moving Mosca
Let's get Mosca moving in the right direction. Implement the following methods:
FlyWorld.isValidLoc()
Returns true / false depending if the input row and column are a valid location in this world.
Fly.update()
Updates the location of the fly. Use FlyWorld.isValidLoc() and
GridLocation.removeFly()/setFly() methods.
FlyWorld.moveFly()
For now it only needs to call the update method for Mosca passing the direction, and check if Mosca
is on the goal location. If she is, return FlyWorldGUI.ATHOME, otherwise return
FlyWorldGUI.NOACTION. Remember, when comparing objects, use the equals() method.
The animation loop is what actually draws the characters on the board. It iterates over the entire GridLocation [][] world and draws each one. If there is a fly at that location (as a result of GridLocation.setFly()), it will draw a fly. Otherwise, it may draw a frog or a color or nothing.
Only things in world will be drawn!
If everything is working right, you should now be able to move Mosca around, and if you reach the
goal the game should end. Make sure nothing bad happens if you try to move past the edges!
Part 4: Moving Frogs
Implement the following methods in Frog.java:
generateLegalMoves()
Returns an array of all legal GridLocations in the world that the calling frog can move to.
Additional details are given in the comments for the method.
update()
Should use generateLegalMoves()and then randomly choose one of those legal moves (if there
are any). You will need to import and use Random. Finally, it should set the frog's location to the
selected location (again if there is one). If there is no possible legal move, the calling frog should not
move at all.
Finally, in FlyWorld.java fill in the movePredators method. For now, only worry about updating every frog's position. You do NOT yet need handle any frog eating Mosca (that’s the next step).
Now you should be able to see the frogs move when you play. You should check to see that frogs don't overlap or go off the screen. Is it fun yet?
Part 5: Eating the Fly
In Frog, fill in eatsFly, which determines whether the frog is in position to eat the fly or not. You will find world.getFlyLocation() useful in this method. Frogs can eat the fly only if they are on the same square or an immediately adjacent square; above, below, left, or right (but not diagonally).
Now in FlyWorld.java,
1. Update moveFly() so that after updating Mosca's location and checking if Mosca is home, go
through all the Frogs and see if any of them have eaten Mosca. If a frog has eaten Mosca return FlyWorldGUI.EATEN. If no frogs eat Mosca, return FlyWorldGUI.NOACTION. (Note: This check to eatsFly() is necessary to check if the player moves onto a Frog.)
2. Update movePredators() so that after you call update() for each frog, check if that
frog can eat Mosca. If it can, return true.
(Note: This check to eatsFly() is necessary to check if a Frog moves onto the player.)
The entire program should be working now. You should be able to move the fly around the board, get eaten by frogs, and finish the game by getting to the goal!
Part 6: Along Came a Spider
Implement a new predator called Spider. You will need to make many changes throughout the program so that Spider can do all the things Frog can do. For this part you are even allowed to edit the GridLocation class, but only to aid in your implementation of Spider. You can add a few ‘a’s into world0.txt or world1.txt to put a Spider into the world for testing.
A Spider moves differently from Frog, it always moves toward Mosca. If the spider is in the same column or row, then it should move toward Mosca along that column or row, unless that position is occupied by another predator, in which case it does not move. Otherwise the spider may randomly choose whether to move horizontally or vertically toward Mosca (unless one or both of those positions are already occupied by another predator). A Spider can only eat Mosca if they are on the same square.
Notice the many similarities between a Frog and a Spider. Use good OOP practices to minimize the amount of redundant code.