Goals and Outcomes
In this project, you will write a class to simulate a robot (called Karel) that gets dropped into a maze, and solves it! Be careful though! There are several ways to write this code in a really bad style. Your goal (other than writing correct code) is to write code that uses good “abstractions” to avoid unnecessary repetition or verbosity in your code. This project also uses inheritance, another form of abstraction, which allows you to specialize a version of a class you’ve written.
Setup
A repository for this project was automatically created for you when you registered for the course on Canvas. Clone that repository.
The Robot
Class
For our purposes, a Robot
is an object which is “dropped” at some location, knows which location it’s currently at, and can “step forward” in a simulation of it moving.
Notably, the Robot
does not have to specify how the stepping occurs – conceivably, the Robot
could “step” using any algorithm it wants to. Later in the project, you
will write a specific type of Robot
which solves a maze.
Choosing the fields of Robot
Unlike the previous project, where we gave you the fields to use, this time, it’s up to you to figure out what needs to be stored in a Robot
for it to do its job.
Once you choose your field(s), write the constructor to initialize them.
Before you begin writing code or finalize your choice of fields, you should take a look at MazeLocation.java
so you have an idea of how it works and how to interact with it correctly, which you will need to successfully complete the next few sections.
Implementing Core Functionality of Robot
public boolean atGoal()
Returns true
when this
Robot
’s location is the goal and false
otherwise.
One particular location in the maze is considered the “goal” for the Robot
. You can ask a MazeLocation
if it is the goal by calling location.isGoal()
.
public maze.MazeLocation getLocation()
Returns the MazeLocation
that this
Robot
is currently located at.
What does abstract
mean? Do I have to implement step
?
Robot
is an abstract
class meaning it’s an “incomplete” definition of what it means to be a Robot
. In Java, we specify this
by declaring the step
function with the abstract
keyword:
public abstract boolean step()
As discussed above, the subclasses of Robot
will specify how to “step”; so, we don’t need to define it as anything for now.
The Karel
Class
For our purposes, a Karel
is a Robot
(meaning, it’s a “subclass” of Robot
) which inherits all the properties of a Robot
as well as a “direction that it’s facing”.
In other words, Karel
knows its location in the maze, which direction it’s facing, and can move forward or turn left/right.
You can choose whichever direction you want to start Karel
facing in.
Choosing the fields of Karel
Just like with Robot
, you are responsible for choosing what field(s) to use for Karel
. Note that it inherits all the properties from Robot
; so, you should not
duplicate those fields in Karel
. Once you choose your field(s), write the constructor to initialize them.
Implementing Core Functionality of Robot
Since Karel
should be able to move and turn, we need to implement three (self-explanatory) methods to perform these actions:
public void goForward()
public void turnRight()
public void turnLeft()
The hardest part of the Karel
class is avoiding writing a ton of if
statements or the like. Make sure to carefully think about how to implement these methods cleanly!
The SolveMazeKarel
Class
Finally, we now have Karel
, which has a direction, a location, and a way of moving. Note that it still doesn’t have a way of “stepping”. This is where SolveMazeKarel
comes in.
SolveMazeKarel
is a subclass of Karel
which has a step()
method that moves through a maze one “turn” at a time – attempting to find the goal.
The step
Method
Note that the step
method returns a boolean
which indicates whether SolveMazeKarel
should continue moving or not. step
should return false
exactly when it believes it has reached the
goal, and true
if there’s more exploration to do. If it’s not at the goal, step
should move SolveMazeKarel
to a MazeLocation
adjacent to the one it’s currently at by following the
“right-hand rule”.
The Right-hand Rule for solving mazes
SolveMazeKarel
should consider three cases before choosing what direction to move in:
- The robot is NOT blocked from moving to the right.
- The robot is blocked from moving to the right, but it is NOT blocked from moving forward.
- The robot is blocked in both directions.
In case (1), where the robot can move right, it should (turn and) go right. In case (2), the robot should go forward. In case (3), it should turn left.
Choosing A Class for Functionality?
You may find yourself wishing SolveMazeKarel
had more functionality (i.e., public
methods that do useful tasks). Carefully consider whether these new methods belong in SolveMazeKarel
or Karel
.
You may add these public
methods to either location!
Checking Your Code
For this project, there are no unit tests. You’ll have to check your code by trying it on several mazes to make sure it works. There is a DRAW_WAIT
final variable in Maze.java
that you can increase or decrease to slow or speed up the visualization of the maze solving.
Committing and Pushing to the Repository
A “commit” is version control language for a chunk of changes that mean something when grouped together. Importantly, commits will only stay locally on your machine
until you push them to the gitlab
server.
To commit to the repository, click the green checkmark on the top-right of IntelliJ’s interface. A window will pop up and
ask you to type in a message. Choose some meaningful description of your feature, then click the little down arrow next to the “Commit” button on the bottom right of the dialog.
Choose “Commit and Push” in the little menu that pops up. If IntelliJ asks you if you’re sure you want to commit and push, say yes.
Turning in the Project
To turn in the project, fill out this form to notify the graders that there is a submission!