pa02 : Linked-list implementation of a card game
num | ready? | description | assigned | due |
---|---|---|---|---|
pa02 | true | Linked-list implementation of a card game | Mon 01/28 09:00AM | Fri 02/15 11:59PM |
This assignment may be done solo or in pairs.
Introduction
- Create a github repo following the correct naming convention.
- If you have a partner, add you partner as a collaborator to the repo. Partner should accept the invitations to complete this process
- Get the starter code for this lab by doing a git pull in your starter-code repo and copying the files from the pa02 folder in this git repo: https://github.com/ucsb-cs24-w19-mirza/cs24-w19-starter-code.git
Goal of this assignment
- Practice using linked lists
- Learn to organize a project’s code structure on your own (not just filling in a template)
- Learn to design classes using good OOP design principles discussed in class
Instructions
The game
Alice and Bob are playing a game a bit like Go Fish, although neither of them is very good at it. Rather than randomly guessing what card the other person has, they take turns to find a matching card. Each player goes through their list of cards in order and asks the other player to list all of their cards in order until a match is found. The game ends once they do not have any cards in common. Note that they do not draw any new cards during this process.
You have pointed out to Alice and Bob that this game is completely deterministic. They’re not sure what you mean, so you decide to demonstrate by showing that a computer can predict how a game will play out. To do this, you’ll be using a linked list!
Approach Overview
At the start of the program, you will read in Alice and Bob’s starting
hands from two files. The names of these files are provided as command
line arguments with Alice’s file in argv[1]
and Bob’s in
argv[2]
. The starter code opens the files for you as ifstream
objects, which you can treat much like cin
. You should read Alice
and Bob’s cards into two linked lists, making sure to maintain the
order in the file, that is the first card in the file should be at the
head of the list.
Once you have the lists of cards, the game begins. Alice goes first
(Important! Alice’s file is in argv[1]
) and iterates over each card
in her hand, checking whether Bob has that card. Once a matching card
is found, you should print the line “Alice picked matching card
The process then repeats, except this time, Bob looks through his cards for the first one that Alice also has. Each player should begin their search where they left off in a previous round. Once there are no matching cards, you should print out the final hands of both players with the matching cards removed.
You should write your own Makefile for this lab so that running make
builds an executable called game
.
Example
Contents of alice_cards.txt
:
h 3
s 2
c a
c 3
h 9
s a
Contents of bob_cards.txt
:
c 2
s a
d j
h 9
c 3
Correct output after running make && ./game alice_cards.txt bob_cards.txt
:
Alice picked matching card c 3
Bob picked matching card s a
Alice picked matching card h 9
Alice's cards:
h 3
s 2
c a
Bob's cards:
c 2
d j
Note: 0=10, a=ace, k=king, q=queen, j=jack
Requirements
For this lab, you will have a lot of flexibility on your implementation (which just means we won’t be providing a code framework for you to fill in). However, there are a few requirements that your mentor will check for when they look at your code. Keep these in mind as you think about your solution:
- You must use a linked list to store the sequence of cards for each player, not another data structure or a linked list in the standard library.
- You must unittest your classes, and include all your test code in testcards.cpp
- Your solution must include at least two overloaded operators. These will probably be the operator on your Card class to check if two cards match i.e. they have the same suit and value, and the operator on your Card class to output stream i.e. operator ‘«’ used in print statements like “std::cout « some_str”. (More details provided below)
- Your linked list must implement a constructor, a destructor and other other methods as needed
- You must define clear interfaces (public functions for the linked-list), so that implementation details are hidden from the code that uses the linked-list, which is the checkpoint for this assignment.
- Your program must properly free all memory it allocates, including your linked list nodes and any dynamically allocated data stored inside them. You must run valgrind on your code and get a clean report
- Your code should be readable, which means reasonable comment and good formating like indentation.
- Star points: Appropriate use of recursion to write concise and elegant code without compromising on performance.
Detail Approach
- Spend time thinking through your design before implementing it.
- Run your initial design by your mentor to get some initial feedback (as in pa01 this step is 20% of your grade)
- Identify the objects in your game as well as their behaviors (public functions):
- card, which represents a specific card. (Think about node in linked list)
- hand, which represents a sequence, or a list, of cards dealt to each player. What does it do? i.e. It might let you know what the first card is. It can traverse all cards in this hand. It can tell if it contains a specific card. It can throw a card away given what that card is.
- player, which represents a person who has a hand of cards! Can you let it have a name?
- etc. You might create less than or more than three classes, which is totally OK, as long as they are meanful and helpful for object-oriented programming!
- Create appropriate classes - to do this you have to identify the behaviors and attributes of the different objects in your game.
-
While you have flexibility in terms of designing your classes in general, we require that you represent each player’s hand (aka list of cards) as a linked-list where each node stores a Card object instead of a simple integer value. In your design you may represent a Card as a class or as a struct.
-
To design the class that represents the list of cards (let’s call this
CardList
), think about how other parts of your program interact with this class. For example, in the algorithm for the game you have to repeatedly insert cards into yourCardList
, so your class should definitely have an insert method – what should be the parameter to insert? -
Here are some other ways a player may interact with their list of cards:
- search: Let’s say Alice starts the game - one of the first things she needs to do is to check if her first card (h 3) is in Bob’s card list. So Bob, at this moment, should call a function to search this card (h 3) in his list of cards. Obiviously, (h 3) is not in Bob’s list. So Alice goes to her next card (s 2) and asks Bob to search for (s 2). Still failed. … (many failures here) until Alice asks Bob to search for (c 3), Bob finds it! The main point here is that your CardList class should implement a search function, and any player should be able to ‘ask’ another player to find a matching card by calling some appropriate method of a class.
- delete: Once Alice and Bob have found a matching card (in this case (c 3)), they should throw their (c 3) cards away. Both of them should call a ‘delete’ function to delete the card (c 3) in their lists of cards – what should be the parameter to the delete function, what should be the return value?
Overload operator “«”
Overloading operator “«” is a useful feature in C++. It enables objects of various classes to customize their stream extraction behavior. (“«” is for output. “»” is for input with similar usage but not discussed here.) To specificly illuatrate how to overload operator “«”, here is an example.
#include <iostream> // including std::ostream
#include <string>
class Person {
public:
Person() { name = "I have no name"; }
void setName(std::string hereisyourname) { name = hereisyourname; }
friend std::ostream& operator<< (std::ostream& os, const Person& random) {
os << "My name is: " << random.name;
return os; // !!!!! Don't forget this return !!!!!
}
private:
std::string name;
};
int main()
{
Person random;
std::cout << random << std::endl;
random.setName("Barbara");
std::cout << random << std::endl;
}
A class Person is defined, and it has an overload insertion “«” function as a friend non-member function. Inside this overloading function, people can freely specify what information would be printed out when operator “«” is applied to this class, Person. Here we want it to print its name.
With overloading function, we can directly print Person like how we print those built-in data types i.e. int, double.
Here is the output.
My name is: I have no name
My name is: Barbara
Submission instructions
Checkpoint (20 points)
Read the instructions on the checkpoint here: https://ucsb-cs24.github.io/w19/pa/pa02-checkpoint/
Files to submit for final submission
You must organize your program in four files: main.cpp cards.cpp and cards.h testcards.cpp. In addition you must create a Makefile that compiles your program to an executable called game
You must submit exactly five files with the names: Makefile, main.cpp, cards.cpp, cards.h, testcards.cpp
Submit the files for PA2 on gradescope and push them to github with the message “FINAL SUBMISSION”. Be sure to wait for the results of all tests. If you score 60/60, and you’ve followed all of the other rules, then you’ll earn 60/60. The additional 40 points will be given by the mentor for good style and for showing off your initial design of the class
- 20 pts for meeting the checkpoint requirements
- 20 points for style and overall design following the guidelines in the requirements (above)
Created by Jack Alexander, Jinjin Shao, and Diba Mirza