CS 0 (Summer 2024) Cards, Decks, and War

This project is centered around Object-Oriented programming. Since OOP is a pre-requisite for CS 2, it will be necessary for you to understand it to pass the placement test.

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 enums

We have also defined Rank and Suit files which are not classes, but enums 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, enums 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 records

Relatively recently, Java introduced a new type of class called a “record”. records 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 Cards 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!