CS 0 (Summer 2024) Beep Boop, Robot! And a Maze!

This project is centered around good programming habits around abstraction and “code duplication”.

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.

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:

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:

  1. The robot is NOT blocked from moving to the right.
  2. The robot is blocked from moving to the right, but it is NOT blocked from moving forward.
  3. 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!