Goals and Outcomes
In this project, you will finish a Card
class and build a Deck
class, both of which will be used to play a game of War. You should make sure to focus on
good class
design throughout this project. The placement test will also test your ability to read documentation and learn new Java features; so, this project will
help you learn that as well.
Setup
Please begin by following the setup instructions. A repository for this project will be automatically created for you within 24 hours of when you register for the course on Canvas. Wait until you get an email, and then clone that repository to start the project.
The Card
Class
We have already stated a Card
class which will be used to back the Deck
class. You should begin by trying to understand what we’ve written.
New Java Features
Card
uses a few fancy Java features you may not have seen before; so, we will begin by explaining these briefly.
Java enum
s
We have also defined Rank
and Suit
files which are not classes, but enum
s instead. An enum
is like a generalization of the boolean
type: there are finite, non-zero number
of “constants” that make up the possible values of the enum
. In our case, Rank
can be \(\{2, 3, 4, 5, \dots, 10, \text{Jack}, \text{Queen}, \text{King}, \text{Ace}\}\). That is,
there are only certain possible ranks; so, by listing them all out, we have a comprehensive set of values that Rank
can take on. We have a similar enum
for Suit
, which can take on
the four possible suits as values. Secretly, enum
s assign an integer value to each possible member (starting with 0 and assigning them in order from there). So, for example, the
“value” of “TWO
” is 0 and the value of “JACK
” is 11. To get this int
value, you can call the ordinal
method on a value of the enum
. To turn an enum
value into a String
, you can call the
name
method.
Java record
s
Relatively recently, Java introduced a new type of class called a “record
”. record
s are very useful, because they define classes with a lot of automatically generated boilerplate code that you’d have to manually write otherwise. If you look at the Card
record, you’ll see we define record Card(Rank rank, Suit suit)
at the top. As a result, the record
automatically defines a field for rank
and another for suit
which become the “identity” of the record
– meaning hashCode
, equals
, and some other annoying methods are defined automatically to be the right thing.
Implementing the rest of the Card
Class
Now that you (hopefully!) understand what the Card
class is made up of, implement the following missing methods:
public boolean ties(Card other)
Returns true
when this
and other
have the same rank and false
otherwise.
public boolean beats(Card other)
Returns true
when this
has a higher rank than other
and false
otherwise.
In “war”, Aces are considered the highest cards. So, the order goes 2, 3, …, 10, Jack, Queen, King, Ace.
private String rankToString()
For numerical ranks (2-10), it returns the number as a String
(example: Rank TWO
results in “2”). For other ranks, it’s the rank
converted to a String
where the first letter is uppercase and the rest of the letters are lowercase.
The Deck
Class
We have provided you with a “skeleton” of a Deck
class. Most notably, we’ve provided the (single) field you should use for your Deck
class (and you should not change this or add any others)!
The “backing” List
The List
is a
Java Collection
. If you’re familiar with arrays, a List
is an array that can grow to an arbitrary size.
You can’t actually instantiate a List
because it’s an interface (which means it specifies what a list is, not how it’s implemented). Thus, when you ultimately want to make a new
List
,
the line would look like:
List<Card> list = new ArrayList<>();
This uses an actual implementation of List
called ArrayList
. If you’re interested in how this is implemented or more details on interfaces, you should take CS 2!!!
Fundamentally, a Deck
is a List
of Card
s which is why we use a List
as a field to “back” the data structure.
Implementing the rest of the Deck
Class
We’ve provided “stubs” (i.e., empty method headers) for the methods you need to implement. See below for what they’re supposed to do.
public Deck()
Initializes this
to have the standard 52 card deck.
That is, the deck should contain one card for every combination of rank and suit.
private Deck(List<Card> deck)
Initializes this
to have exactly the cards that are in the argument deck
, in the exact same order, and no other cards.
Note that this constructor is private
! This means that you will likely use this constructor inside this class when implementing one of
the methods below! Keep this in mind…
public boolean hasNoCards()
Returns true
if the deck has no cards and false
otherwise.
public void bury(Card card)
Adds card
to this
Deck
at the bottom. Note: We refer to the end of the backing List
as the bottom of the Deck
.
public Card draw()
If there is at least one Card
in the deck, removes and returns the Card
at the top of the deck.
Otherwise throws
an EmptyDeckException
.
Note: We refer to the start (0th index) of the backing List
as the top of the Deck
.
public Deck draw(int numCards)
If there are at least numCards
cards in this
Deck
, returns a new Deck
made up of the top numCards
cards of this
Deck
in the same order they were originally in (i.e., the old top card of this
should be at the top of the returned Deck
). Otherwise throws
an EmptyDeckException
.
public void faroShuffle()
Re-orders the cards in this
Deck
according to the rules of a Faro Out-Shuffle.
A “faro out-shuffle” interleaves the top half of the deck with the bottom half, keeping the top card at the top. Interestingly, eight faro shuffles results in the exact same order as before the shuffles! Note that you still have to handle odd-sized decks!
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
We have provided a test suite for this project, which you can run by clicking the play button in the top right corner of IntelliJ. PLEASE make sure all of these tests are passing before turning in the project!
To turn in the project, fill out this form to notify the graders that there is a submission!