Rack-O®
- Summary
- You build a program to support playing a simple strategy game.
- Objectives
-
- Practice using list-backed stacks
- Contrast list, stack, and array suitability
- Reinforce memory-management knowledge
- Verify user input
Introduction
Game Overview
The board game Rack-O is a simple game requiring players to sort a fixed-length rack of cards through replacements from a randomized sequence. With gameplay for 2–4 players, it debuted in 1956 and remains fun and popular today.
Game play involves a deck of 60 cards (we'll number them 0–59). To begin, these cards are randomly shuffled. Each player has a rack in which ten cards are placed into slots. At the start of the game, the cards are dealt from the shuffled deck to alternating players' racks in increasing slot order. The remaining undealt cards get placed into a stock pile. The top card from the stock pile is turned over so it is visible and placed into the discard pile
The object of the game is to be the first player to obtain a rack with all ten cards appearing in increasing sorted order.
The game is played by alternating turns. A player chooses a card from either the stock or discard pile. If the player chooses from the discard pile, they must use it to replace an existing card in their rack: the card removed from the rack then goes on the top of the discard pile and the new card is inserted in its place. If the play instead chooses from the stock pile, they may either return that card to the discard pile or use it to replace a card in their rack.
In the full game, this play constitutes a round, with subsequent
scoring based on the card placement in the rack. However, in our
dimunition of the game, such play will alternate until one player has
simply Gone Rack-O!
(achieved a sorted rack).
Program Structure
The astute reader will have noticed the opportunities for use of the following data structures:- Stacks:
- Only the top-most card is accessible from the stock and discard piles, and the length is variable. Therefore, these collections will be represented in your program with stacks backed by linked lists.
- Racks:
- The racks have a fixed length and are accessed by an arbitrary index (rather than sequentially). This precisely fits the usage pattern of arrays.
Your game play will only support two players, and will not involve any sort of intelligent computer player. Instead the program will keep track of the piles and racks, asking the players for their choices and displaying the relevant information as it arises.
Assignment
As one might imagine, correctly using these ideas requires attention to a number of practical details.
Card Stacks
To support the two card piles, you will need to implement and test a simple stack.
Implementation
Place the following declarations (with documentation, include guards,
and any necessary headers) into cardstack.h and
implement the corresponding procedures in cardstack.c.
typedef struct node {
int card;
struct node * next;
} node_t;
void
cardstack_init (node_t ** p_stack);
bool
cardstack_empty (const node_t * stack);
void
cardstack_push (int card, node_t ** p_stack);
int
cardstack_pop (node_t ** p_stack);
int
cardstack_top (const node_t * stack);
void
cardstack_clear (node_t ** p_stack); // Empty the stack, freeing all memory
Your documentation should clearly identify necessary preconditions, and your implementation should verify those preconditions with assertions whenever possible.
If any standard library routine fails, use perror to
print a contextualized error message and exit the
program from within your library.
Testing
Contruct a simple, but comprehensive test suite for your stack (i.e., use preprocessor macros).
The stack library cardstack.c will eventually be compiled
separately and linked with your game program. However, rather than
create a separate driver program (that is, a C file with
a main procedure), add a main to the bottom
of cardstack.c with a conditional inclusion dependent on the
STACKTEST symbol to indicate testing. For example:
#ifdef STACKTEST
// Test helper macros and procedures here
int
main (void)
{
// Test program here
} // main
#endif
One would then be able to test your stack by compiling with something like the following:
clang -Wall -DSTACKTEST -o stacktest cardstack.c
Makefile
Create a Makefile for your assignment that includes the
following targets:
cardstack.o-
Builds that object file from your
cardstack.c. Note that none of the testing routines should be present in the object. stacktest-
Builds that executable program from
your
cardstack.c. Note that all of your testing routines should be present in the program and run when the program is executed.
Your Makefile should
separate out variables CPPFLAGS, CFLAGS,
and LDFLAGS that are subsequently used in the
appropriate target rules.
You may want to add another variable FLAGS (initially
empty), as follows
# Optional, universal flags to use in all build commands (compile, link, etc)
FLAGS=
that is used in all rules, so that you can incorporate the Address
Sanitizer through that variable, i.e.,
make FLAGS=-fsanitize=address
Game Play
Complete the functions
in racko.c to implement
the full game play. Note that the main function has been
completed for you, but the rest of the functions are provided as
stubs. Completing these stubs should allow you to run the game, as
demonstrated in this
transcript. Bad user input should be handled robustly, as
demonstrated in another
transcript.
The following notes may help guide your thinking about the program structure:
-
Game play functions requiring user input should not solicit it
directly, but should instead use the helpers (currently
stubs)
get_choiceandget_slot_number. -
game_playis very simple and should make use ofprint_rack,make_move, andgone_racko. -
make_moveshould make use ofmove_from_discardormove_from_stockbased on the state of the game and/or user choices.
Makefile revisited
Add the following targets to your Makefile, including
any necessary dependencies:
permute.o-
Builds that object file from the provided
code
permute.c(which relies onpermute.h). racko.o-
Builds that object file from your
racko.cprogram. racko- Builds the executable game program by linking the necessary object files.
Grading
In addition to the general grading guidelines for evaluation, the assignment is worth 39 points.
Submit files cardstack.c, cardstack.h,
Makefile, racko.c, references.txt, and
tests.txt.
- [11 points] Library
cardstack.c- [1 point] Preconditions verified with
assert - [1 point] Supported by guarded header
- [1 point] Procedure
cardstack_initis correct - [1 point] Procedure
cardstack_emptyis correct - [2 points] Procedure
cardstack_push- Correctly adds item to stack
- Prints notice and exits if runtime error (non-assertion)
- [1 point] Procedure
cardstack_topis correct - [2 points] Procedure
cardstack_popis correct - [2 points] Procedure
cardstack_clearis correct
- [1 point] Preconditions verified with
- [26 points] Program
racko.c- [2 points] Procedure
setup_gameis correct - [2 points] Procedure
clear_gameis correct - [1 point] Procedure
gone_rackois correct - [1 point] Procedure
print_rackis correct - [2 points] Procedure
get_choiceis correct - [3 points] Procedure
get_slot_numberis correct - [1 point] Procedure
insert_cardis correct - [4 points] Procedure
move_from_stock- [1 point] Removes and displays card from stock pile
- [3 points] Solicits user choice and takes appropriate action
- [2 points] Procedure
move_from_discardis correct - [4 points] Procedure
make_move- [1 point] Moves from stock pile (with notice) when discard pile is empty
- [3 points] Otherwise informs user of discard's top, solicits choice, and takes appropriate action
- [2 points] Procedure
game_playis correct - [2 points] Procedure
reset_stockis correct
- [2 points] Procedure
- [2 points]
Makefileseparately compiles files and links executables -
Evaluation of program Structure, Comments, Design, and Testing.
(Additional points not given, but points may be deducted.)
A five point penalty will apply to any submission that includes personally identifying information anywhere other than the references/honesty file.
To pass the assignment (with a grade of C or better), tests must demonstrate a clean diagnosis from AddressSanitizer.
Beyond those provided in the starter file, additional global variables may not be used anywhere; use of any additional global variable will result in a grade of zero.
