Discussion 5: Object-Oriented Programming
The goal of today’s discussion is to practice some of the principles of object-oriented design and development. Object-oriented programming is a powerful tool for structuring code which enables readability, maintainability, and extensibility. Today you’ll get a start on assignment A5, a simple text-based battle game (think a super pared-down version of D&D combat, if you’re familiar with that). The task for this discussion is to get familiar with the structure of the assignment code and implement the main combat loop; the assignment will focus on extending and adding new functionality to the activity you’re completing today.
Learning Outcomes
- Compare and contrast static types and dynamic types.
- Draw object diagrams to visualize reference types.
- Identify the invariant of a class and write code that maintains this invariant and/or asserts that it is satisfied.
- Explain the benefits of leveraging polymorphism in object-oriented code.
- Describe the principle of dynamic dispatch and the compile-time reference rule.
Reminder: Discussion Guidelines
The work that you complete in discussion serves as a formative assessment tool, meaning it offers the opportunity to assess your understanding of the material and for our course staff to get a “pulse” on how things are going so we can make adjustments in future classes. Your grade in discussion is based entirely on attendance and participation; if you show up and you are actively engaged with the activity (working on the activity on your computer, discussing the activity with your group, asking and answering questions, etc.) for the entire 50-minute section period, you will earn full credit. If you complete the activity early, helping other students is a great way to further your own understanding. You do not need to submit any of the work that you complete during discussion.
Since discussion activities are not graded for correctness, we do not place any restrictions on resources that you may use to complete them, which include notes, books, unrestricted conversations with other students, internet searches, and the use of large language models or other generative AI. We advise you to be pragmatic about your use of these resources and think critically about whether they are enhancing your learning. Discussion activities are intended to serve as “strength training” for programming tasks we will expect on assignments and exams (and that you will encounter in future courses and careers), and their main benefit comes from critically thinking to “puzzle” them out.
Working together in small groups is encouraged during discussion!
Background
In Assignment 5, you’ll be implementing a text-based combat simulator for a simple tabletop roleplaying game. Today’s discussion is meant to get you started on this. We’ll be working with the diagram shown below; you’ll be adding more components to this later as you work on A5, but we’ll confine today’s activity to the given classes and interface.
Imagine you and some friends are playing D&D. If you’ve never done this, don’t worry; the details of the actual game are not important (and will be vastly oversimplified for our purposes anyway), and we’ll tell you everything you need to know. Essentially, you and your friends form an adventure party; you are the Player
s in this situation. Your objective is to defeat the Monster
s you encounter in combat, subject to some system of rules. In the process of translating this to code, we might come up with something like the following diagram.

There is a GameEngine
class whose objects are responsible for running a game. Its behaviors include processing user input, maintaining the state of the Player
s and Monster
s in the current battle, and managing turn order and advancement. Both Player
s and Monster
s (which implement the Actor
interface) are able to take some actions on their turn. For now, let’s assume the following about the actions that Player
s and Monster
s can take:
- On its turn, a
Monster
selects a random livingPlayer
andattack()
s thisPlayer
. The damage dealt is randomized and dependent on theMonster
’s power level. - On their turn, a
Player
selects oneMonster
toattack()
. The damage dealt is randomized and dependent on thePlayer
’s power level. - When a
Player
or aMonster
isattack()
ed, they are given the opportunity todefend()
, which can succeed or fail. If their defense succeeds, they will not take damage; if it fails, they will take damage from the successfulattack()
. - All
Actor
s start with a certain number of health points. As soon as theirhealth()
reaches 0, they “die”, so they are no longer able to take actions.
Take a look at the JavaDoc pages for our game’s classes. The JavaDoc provides more information (the complete method specifications) than our class diagram shown above, so it is written at a later stage of the development process.
Written Questions
gameSnippet1()
method:
|
|
|
|
Draw a memory diagram that depicts the state of the gameSnippet1()
call frame (and all heap objects that can be reached from this call frame by following one or more references) just after line 5 finishes executing. You can fill in any valid value for each Actor
’s power.
To simplify your diagram a bit, you can visualize the GameEngine
as an empty rounded rectangle (omitting its fields). Draw all fields of any other objects.
What is the static type of the variable actor1
? What is the dynamic type of the object that it references?
When line 7 executes, which method body do we enter? How does Java figure this out?
gameSnippet2()
method:
|
|
|
|
Programming Tasks
Download and look through the starter code for this game. You have been given complete implementations of our basic Monster
and Player
classes (along with the Actor
interface that they implement) and a partial implementation of the GameEngine
class. For the rest of this discussion, you’ll add additional functionality to the GameEngine
class.
Before we start coding, open the GameEngine
class and read the documentation of its fields to understand its class invariant. As an implementer of the GameEngine
class, it will be your responsibility to restore this class invariant at the end of every (non-private
) method that you write.
processMonsterDeath()
and processPlayerDeath()
Complete the definitions of the processMonsterDeath()
(TODO 1
) and processPlayerDeath()
(TODO 2
) methods to conform to its specifications. Where do you think that these methods would be called within the other classes? Take a look at the rest of the code to check if you were correct.
The Main Game Loop
Implement the main game loop method in GameEngine.java
according to its specification (TODOs 3-6
).
|
|
|
|
Think carefully about how to do this part so that, if we were to add new types of Players (which you’ll do in the assignment), we would not have to add additional cases/logic to the implementation of this function. This is possible, and showcases polymorphism and dynamic dispatch; this is really neat, since this modular design allows us to easily support new features.