COMP11 Project (HW11): Splendor
In this assignment, you will implement the board game Splendor as a C++ program. Your implementation will be submitted in two parts (neither part of this assignment has a written portion):
• Part I is due by midnight on Tuesday, November 26th. You will use the script submit-hw11p1 for this submission.
• Part II is due by midnight on Monday, December 9th. You will use the script submit-hw11p2 for this submission.
Due to the scope of this project, it will be weighted higher (by 50%) than your other homeworks when calculating your final grade. The purpose of this project is to:
• Practice building and integrating more classes into a large program
• Design your own classes from scratch
• Complete a large-scale project using all the knowledge you’ve gained from COMP11
• Implement a real-world board game with a C++ program
As per usual, start by pulling the starter code:
You’ll notice that, apart from the utility files that allow us to control the terminal (termfuncs.cpp and termfuncs.h) and a C++ file that drives the program (splendor.cpp), there are only two C++ files being provided to you (game.h and game.cpp), neither of which is fully complete. A major goal of this final project is to test your ability to take a larger-scale problem, break it down into manageable parts, implement solutions to those parts, and test the individual solutions as you go. To meet this goal, you will be designing and implementing multiple classes and functions across multiple files; it is imperative that you follow the COMP11 axioms written on the front page of the course website to stay on pace and avoid getting overwhelmed.
Like many board games, the rules for this project may seem complex at first, but will quickly become intuitive. We strongly suggest you approach this project by performing the following steps:
1. Read the entire spec in one sitting without trying to understand everything. Put down the spec and go do something else.
2. Come back, try reading it again, and take notes about what you’re being asked to do and what you don’t understand.
3. Run the demo program a few times, seeing how the demo realizes the various aspects of the game described in the game overview section of this spec.
4. Ask questions in office hours or on piazza if you still do not understand an aspect of the game after completing the previous three steps.
5. Read over the C++ code we have provided for you; it contains many design hints (both in terms of what classes you might want to implement, and some of the functionality that they might provide).
6. Design, implement, and test the parts of the game in the order suggested in the Programming section.
1 Game overview
Your final project is to implement the board game Splendor in C++. You will be implementing a 2-player variant where some of the rules will be realized as \extra credit" (official Splendor rules).
In Splendor, you are a savvy, Renaissance merchant. To maintain your social status, you will use all your resources to purchase mines, transportation methods, and vendors that together will let you turn raw gems into gorgeous jewels. Your goal is to finish the game with more \prestige points" than your opponent, proving that you are the greatest merchant in the land! You and your opponent will take turns until one of you reaches 15 prestige points, which signals the end of the game (if the first player wins, the second player gets one more turn). When all final turns are completed, whoever has the most points wins.
The rest of this section outlines the components of the game, the turn-by-turn rules, and the conditions for ending and winning the game. When we refer to a \board", we are talking about the main play space printed out to the screen while your program is running.
1.1 Game ComponentsThere are three components in this game: gems, cards, and nobles.
Gems are your currency; they are used to purchase cards. There are 6 different types of gems, each of a different color. There are 4 gems of each normal color (white, red, pink, blue, and green), and 5 of the gold \wildcard" gems.
Cards represent the mines, transportation methods, and vendors that your business relies upon. You will purchase cards over the course of the game to both obtain more prestige points and earn discounts that make future purchases cheaper. Each category of card has its own deck (3 decks in total): there are 40 mine cards, 30 transportation cards, and 20 vendor cards. Every card has three pieces of information:
1. A prestige point value. This is how many prestige points you gain if you buy the card.
2. A colored discount. If you own this card (by buying it), you get a discount on future card purchases.
3. A gem cost. This specifies how many gems (and of which colors) are required to purchase the card.
In our visualization of the game, a card’s prestige point value is in the top left corner, its discount is indicated in the top right corner, and its cost is in the lower left corner.
Nobles are members of high society who are watching your progress. If you meet certain conditions during the game, you will gain the loyal patronage (and the associated prestige) of one or more of the 3 nobles on the board. Including nobles in your submission will constitute extra credit (details explained below); you may ignore any mention of nobles if you do not wish to tackle the extra credit.
1.2 Game SetupAt the start of the game, all the gems are on the board and available for either player. The three card decks are placed in a column, and the top four cards of each deck are revealed in a row (giving you three rows of 4 cards each, flanked by the decks to the left of each row). Finally, three nobles are placed on the board.
1.3 Game Rules
Splendor is played with two players alternating turns, starting with Player 1. On their turn, a player must perform exactly one of the following 4 actions:
1. Take 3 gem tokens, each of a different color, from the board and into your private collection. Gold gems cannot be taken.
2. Take 2 gem tokens of the same color from the board and into your private collection. Gold gems cannot be taken. You may only perform this action if all 4 gems of the desired color are on the board. For example, if there are 3 red gems left on the board, you cannot take 2 red gems as your action.
3. \Reserve" 1 visible card on the board and take 1 gold gem from the board (this is the only way you can get gold during the game). The reserved card is put in your \hand" (which may hold up to 3 reserved cards) and cannot be discarded; the only way to remove it from your hand is to purchase it on a later turn (described below). If there is no more gold on the board, you can still reserve a card (if you have space in your hand); you simply don’t receive any gold.
4. \Purchase" 1 visible card, either from the board or from your hand of reserved cards. To purchase a card, you must spend the gems matching the card’s cost; the spent gems are returned to the board from your private collection. A gold gem can replace a gem of any color, e.g., if a card costs 4 red gems but you only have 3 red gems and 1 gold gem, the gold gem can act as the 4th red gem so you can purchase the card. Purchasing a card grants you a discount (described below) and the number of prestige points indicated on the card.A player cannot have more than 10 gems in their private collection at the end of a turn. If they do, they must return gems to the board until they only have 10.
Each card you buy during the game grants you a discount of a given color (indicated on the card). This discount applies to future purchases: each discount of a given color is equal to a gem of that color. For example, if a player has 2 blue discounts and wants to purchase a card that costs 2 blue gems and 1 green gem, they only have to spend 1 green gem to get the card. Due to this rule, it’s possible to eventually own enough cards such that you could purchase a card for free (all the gem costs being covered by your purchased cards’ discounts).
If nobles are included in your game (i.e., you’re tackling the extra credit of this assignment), then a player might gain their loyal patronage at the end of their turn. Each noble displays a list of gem discounts (colors and quantities) that impress them; if a player has at least the quantity and color of the discounts displayed on a noble at the end of their turn, the noble will become a loyal patron of that player, adding 3 prestige points to their tally. That noble is then removed from the board.
1.4 End of Game
When a player gains at least 15 prestige points, the game ending is triggered. If Player 1 is the first to 15 prestige points, then Player 2 gets one more turn before the game is over. If Player 2 is the first to 15 prestige points, the game is simply over. The player with the most prestige points is the victor! In case of a tie, the player who has purchased the fewest cards is the winner.
2.1 Demo ProgramAs with the previous assignment, the best way to understand the rules of Splendor is to run the demo program and try playing the game (make sure to do pull-code11 first so you have the necessary splendor.data file)! Feel free to play the demo with another student:
splendor demo splendor.data trueTo play the game, you must type out commands for the program to execute. Our demo supports the following commands, each of which follows the game rules outlined earlier in the spec (see what happens if you try to issue an illegal command, like trying to take gems that aren’t on the table or buy cards you cannot afford):
(the first argument indicates the data filename, the second argument indicates whether or not you’d like to play with nobles)
• q - Quit the game.
• p3 - Take 3 gems from the table, each of a different color. You specify the colors after the command, e.g., p3 red white blue would put a red, white, and blue gem into your private collection.
• p2 - Take 2 gems of the same color (only possible if there are 4 gems of that color on the table). You specify the color after the command, e.g., p2 red would put 2 red gems into your private collection.
• r - Reserve a visible card from the table. You specify the row by the first letter of its name (m - Mines, t - Transport, v - Vendors) and then the index of the card in that row (using 1-indexing), e.g, r m 4 would reserve the 4th card from the mine row. A gold gem is automatically put in your private collection if any gold gems are left on the board.
• b - Purchase a visible card from the table. You use the same specification as above, e.g., b t 2. The gems necessary to purchase the card (including gold \wildcard" gems) are automatically spent, and any applicable discounts are applied automatically.
• br - Purchase a reserved card. You specify the index of the card in your hand (using 1-indexing), e.g., br 2 would purchase the second reserved card in your hand. Gems are automatically spent and discounts are automatically applied as done in the previous command.
2.2 Starter Code and Other Provided Files
2.2.1 Starter C++ code
You are provided with five C++ files when you run pull-code11 hw11: termfuncs.h and termfuncs.cpp (which simply hijack your terminal screen; these should not be modified at all), splendor.cpp (which creates a Game object and runs the game; this should not be modified at all), and game.h and game.cpp.
The game files implement a partially completed Game class, which represents a game of Splendor. The clearBoard() function and any function whose name starts with draw are completed, and they provide a number of hints of what classes you might want to define, what public functions they should provide, and what helper functions you should define in the game class (recall how you used these files to help design an appropriate Card class in lab). The constructor and playGame() functions are not complete, but you will only need to modify the constructor to complete Part I of the assignment.
2.2.2 Testing files
The following files are provided for testing:
• splendor.data: The data file containing all the card and noble information for a Splendor game. This file should not be modified in any way.
• test[1-3].in and test[1-3].gt: Three pairs of input and ground truth files to diff against for Part I, Part II, and the extra credit of this assignment, respectively.
Even though this program is visual, you can still use the exact same testing framework you’ve been using all semester (and our autograder will be using it too), i.e., with your compiled splendor executable run:
./splendor splendor.data false < test1.in > test1.out
(produces an output file called test1.out)
diff test1.out test1.gt
(produces output if any visual aspect of your game implementation differs from the ground truth)
You should create additional test input files to make sure all aspects of your game are working properly for each submission. Due to the visual nature of this program, any output generated will look like nonsense if you try to look at it with Atom. Rely on the cat and diff commands to inspect and compare your output.
We have also implemented a program that can shuffle the cards and nobles in the provided data file to provide a new data file. Specifically, if you are in the same directory as splendor.data and run
you will have a new file called shuffled.data that can be used instead of splendor.data if you want a more randomized game setup.
2.3 Part I: Quit before you start (30 Points Total; DUE EARLY)
For your first submission, you are tasked with displaying the initial configuration of the game and allowing the user to quit by typing ‘q’ at the turn prompt. To accomplish this, you will first need to design the classes and methods used in game.cpp to get everything to compile. We suggest focusing on one class at a time and testing it with a main() function in the class’s .cpp file, which will let you compile just that .cpp file by itself (remember to remove this main() when you’re ready to compile this class with your other .cpp files).
You already started designing and implementing a Card class in lab and a partial Game class is provided; our solution only requires two other classes, one of which is a slight variant of a class live coded in lecture and provided on the course website (only one line of code was modified). The vast majority of methods you need to implement for this part are simple getters and setters. Hints about these classes and their methods are peppered throughout the provided game.h and game.cpp files. You will also need to augment the Game class’s constructor and write a few helper functions in the Game class.
2.4 Part II: Play! (50 Points Total)For your second submission you will be implementing the remaining turn commands. The more complex commands rely on the simpler ones (as does our testing), thus we recommend that you implement the commands in the following order and (initially) without any error checking for queries that violate the game rules.
1. Gems (10 points): Implement the two commands that take gems from the table, p2 and p3.
2. Reserving Cards (10 Points): Implement the command for reserving cards, r.
3. Purchasing Cards (20 Points): Implement the two commands for purchasing cards, b and br.
When the above queries are working as specified, finish the implementation by adding in Error Checking (10 points) to ensure that a query cannot violate the game rules.
2.5 Extra Credit: Nobles (+10 points)Add the nobles and their \loyalty" functionality to the game.
3 Submitting your work
You will perform two submissions for this assignment. The first submission will comprise all the files that realize Part I of the program. Since you have the freedom of naming the .cpp and .h files that together
implement this part, it is up to you to make sure that all necessary files are in the same directory, i.e., the submit11 script will not know what file names to look for. Once you’re sure that all the necessary files are in the same directory, go into that directory and enter the following command:
Your second submission will comprise all the files that implement the full game of Splendor. Again, make sure all the needed files for compilation are in the same directory, go into that directory, and enter the following command:
In this assignment, you will implement the board game Splendor as a C++ program.