CompSci 308 Spring 2024 |
Advanced Software Design and Implementation |
In this lab, you will refactor a working game of Hangman to remove code duplication. Refactoring is the process of changing the implementation of a piece of code without changing the functionality. The result of this lab will be a Hangman game that functions the same as the initial game, but has less duplication and is easier to read and update.
The lab has the following steps:
Please complete each step before moving onto the next.
Labs in this course expect you to work either in pairs or with your project team.
Professionally, this practice is called Pair Programming. When Pair Programming, you will:
Follow these steps to setup your Pair Programming environment:
lab_hangman
to their repository to allow pushing your pair's changes.
Project Information → Members
(in the upper left corner) to add your partner so both people in the group can access the same repositoryMaintainer
role in the project and choose Add to Project
git clone
to copy the forked repository to the local machine.DISCUSSION.md
.Note: When pair programming, it is a good idea for the non-coding partner to have a copy of the code in front of them for reference. This will also help in the next section.
Before Moving On: Add your names to the DISCUSSION.md file, thenadd
, commit
the file, and push
to your forked lab_hangman
repository..
In the game of Hangman, one player tries to guess a secret word that another player has chosen by guessing a letter at a time. To simulate this in lab, there are two similar versions of the game that include four different kinds of players (based on assignments given in CompSci 101). A player is either a guesser or secret keeper.
HangmanInteractiveGame.java
: An interactive guesser versus a secret keeper that chooses a random secret
word.HangmanAutoGame.java
: An auto guesser that
chooses letters based on frequency versus a sneaky secret
keeper that changes the secret word after each guess to
maximize the remaining possible words.In this section, you will read over the two classes above and discuss
it with your partner. Then, you add short
summaries of your discussion to the Original Code section of DISCUSSION.md
file.
Note: you only need to consider the code in the game
package, not the util
package.
To guide your discussion, consider the following questions:
To help identify candidate code within each game that could be turned into methods to represent a player's behavior, describe how would you make the following new game using the current design:
For this discussion, do not worry about the exact Java code needed to implement these players, just identifying what lines in either one of the game classes needs to be changed to implement two new players described above.
To guide your discussion, consider what parts of the code do the two game classes have in common and what parts are different (note, use can use Window → Editor Tabs → Split Right
to view the two classes side by side):
play()
is composed of several steps. Which
ones are always the same for every game and
which ones depend on what kind of player is
playing?handleGuess()
is composed of several steps.
Which ones are always the same for every game and which ones depend on what kind of player is
playing?Before Moving On: Write short summaries of
your discussion in the DISCUSSION.md file, then add
, commit
the file, and
push
to your forked lab_hangman
repository.
Refactoring is the practice of updating a program to improve its design and maintainability without changing its current functionality. For example, creating a single method from two similar code blocks to reduce duplicate code.
In this section, you will plan several refactoring steps to change two classes with heavily duplicated code with no clear intentionality into the following classes:
HangmanGame
Guesser
SecretKeeper
The main objective of this refactoring is to ensure these classes have no duplicated code. You will also separate the game rules from the player logic so that they can be changed independently.
Update
the Refactoring Plan section of the DISCUSSION.md
file.
Write down the methods you will create for each of the
three classes, HangmanGame
, Guesser
, and SecretKeeper
. For each method, specify
You can do this using standard Java syntax followed by a comment. For instance,
public String sayHello(String name)
// creates a greeting in the format "Hello, {name}"
The goal of this step is not to get all the implementation details exactly correct, but rather to develop an understanding of how the classes need to interact with each other to remove duplication.
To help you in this process, consider the following:
HangmanGame
, Guesser
, or SecretKeeper
) should be responsible for these instance
variables (and why): mySecretWord
, myNumGuessesLeft
, myDisplayWord
, and myLettersLeftToGuess
?Your pair may create any new methods or classes you want to help improve the program. However, because the functionality of the program should not change in this refactoring, you should focus primarily on moving existing code rather than creating any new code.
Before Moving On: Write short summaries of
your discussion in the DISCUSSION.md file, then add
, commit
the file, and push
to your forked lab_hangman
repository.
Using pair programming in 15 minute increments (or after each change described below), perform the refactoring your planned above.
First, rename InteractiveHangmanGame
to HangmanGame
. For the rest of your refactoring, you will
gradually extract functionality out of HangmanGame
into Guesser
and SecretKeeper
classes. Below, an
ordering of steps is provided, but not the changes themselves. You will
need to implement the methods you defined your Refactoring Plan. It’s
fine if you need to alter the methods from what you originally planned
to make things work.
Note: Please leave at least 20 minutes at the end of lab to Debrief and Submit your Work. It is okay if you are not finished with your refactoring by then. Just find a stopping place (ideally with working code), commit your changes, and move on to Debrief.
Guesser
class that implements the interactive
guessing using the methods from your planMain
class to create the Guesser
and pass it to the HangmanGame
HangmanGame
class to call methods on the Guesser
in place of its own methodsMake sure you can play an interactive game using your new Guesser
.
Add
and commit
your changes to the source
code before moving on.
SecretKeeper
class that implements choosing a random secret word using the methods from your planMain
class to create the SecretKeeper
and pass it to the HangmanGame
HangmanGame
class to call methods on the SecretKeeper
in place of its own methodsMake sure you can play an interactive game using both the Guesser
and your new SecretKeeper
.
Add
and commit
your changes to the source
code before moving on.
Guesser
class to implement choosing letters
automatically by adding the logic from the original AutoHangmanGame
.No changes should need to be made to the HangmanGame
or Main
classes. For now,
just comment out the interactive implementation. We will see a
better way to handle this next week.
Make sure you can run an auto game using both the Guesser
and your new SecretKeeper
.
Add
and commit
your changes to the source
code before moving on.
SecretKeeper
class to implement changing
the secret word after each guess by adding the logic from the original AutoHangmanGame
.No changes should need to be made to the HangmanGame
or Main
classes. For now,
just comment out the random implementation. We will see a
better way to handle this next week.
Make sure you can run an auto game using both the Guesser
and the sneaky version of the SecretKeeper
.
Before Moving On: Add
and commit
your changes to the source
code and push
them to your forked lab_hangman
repository.
In this section, review your changes (or planned changes if you did not get to implement everything). Then, you add short
summaries of your discussion to the Debrief section of DISCUSSION.md
file.
Discuss with your partner, as concretely as you can, how to implement these changes using this new version of the code:
HangmanGame
class.main()
method, not copying any
existing classes.Taking the totality of the lab in mind, discuss the following with your partner:
At the end of lab, use Gitlab's Merge
Request from your forked repository's main
branch back
to the original organization repository's main
branch to
submit your group's answers to the discussion questions and your
refactored code.
Make the Title of your Merge Request is of the form "lab_hangman - everyone's NetIDs".
You only need to create one Merge Request, no matter how many commits you make, and you do not worry about potential conflicts since your request will not be approved (it is just an easy way for us to see what changes you made).
If you are using two machines for Pair Programming, then both lab partners need to clone the environment (as instructed above).
You have two options for synchronizing across machines:
commit
and push
changes to Gitlab after each partner
codes. Then, the other partner will need to pull
the changes.