EECS 183 Project 2: Rock-Paper-Scissors
Due Friday, September 29th at 8:00 p.m. (accepted until 11:59:59 p.m.)
Direct autograder link
Overview
In this project, you will be implementing a rock-paper-scissors game! Rock-paper-scissors is a hand game played between two people, in which each player simultaneously forms one of three shapes with an outstretched hand. These shapes are “rock” (a simple fist), “paper” (a flat hand), and “scissors” (a fist with the index and middle fingers extended, forming a V).
A player who plays rock will beat another player who has chosen scissors, but will lose to one who has played paper; a play of paper will lose to a play of scissors. If both players choose the same shape, the game is tied.
This project is significantly more difficult than Project 1 and you can expect it to take 2 to 3 times longer to complete.
See the image below for a visual representation of the rules of rock-paper-scissors:
Objectives
By completing this project, you will learn to:
- Develop programs that are divided into functions
- Compile programs that are not yet complete by using stubs
- Verify the correctness of functions by writing test cases
- Implement functions based on a specification and RME comment
- Use existing operators to perform interactive I/O using C++
- Write logical expressions and selection statements in C++
- Create algorithms that use conditionals and loops
- An important objective is to have fun!
You will apply the following skills you learned in lecture:
- Lecture 3
- Call math functions like
floor()
andceil()
.
- Call math functions like
- Lecture 4
- Call functions with multiple parameters
- Use
return
statements to provide a result from a function
- Lecture 5
- Create function declarations to allow calls to a function before its code is provided in a function definition
- Interpret RME comments
- Use the iterative development cycle for writing your functions
- Lecture 6
- Use
if
,else
, andelse if
to conditionally execute code - Execute the cin algorithm to determine how a given user input will be stored into variables
- Use
- Lecture 7
- Write event-controlled loops using
while
- Combine loops with
cin
to continue reading until the user is finished
- Write event-controlled loops using
- Lecture 8
- Write count-controlled loops using
for
- Write count-controlled loops using
Getting Started
Starter Files
You can download the starter files using this link.
The IDE setup tutorials for Visual Studio and XCode include a video about how to set up a project using the starter files. If you’re on a Windows computer, you should download Visual Studio. If you’re on a Mac, you should download XCode. You can access the tutorials here:
- Visual Studio - Windows computers
-
Make sure there are 3 files in your project:
rps.cpp
,test.cpp
, andstart.cpp
.
Submission and Grading
Submit your code to https://autograder.io/web/project/2143. You receive 4 submits each day and your best overall submission counts as your score. You will submit two files, which must be called rps.cpp
and test.cpp
.
This project must be completed individually, i.e., no partners.
Here is a grade breakdown:
- 60 points: correctness. Implement functions in
rps.cpp
and play the game of rock, paper, scissors. To what extent does your code implement the features required by our specification? To what extent is your code consistent with our specifications and free of bugs? - 10 points: testing. To what extent is your code tested? Implement the testing functions and submit them via the
test.cpp
file. See the Testing section for more details. - 10 points: style. To what extent is your code written well? To what extent is your code readable? We will only look at your
rps.cpp
when determining your style grade. Consult EECS 183 Style Guide and check the Style Checklist at the end of this project’s specification for some tips!
The deadline is Friday, September 29 at 11:59PM Eastern. If your last submission is on Wednesday, September 27 by 11:59PM, you will receive a 5% bonus. If your last submission is on Thursday, September 28 by 11:59PM, you will receive a 2.5% bonus.
You have 3 late days that you can use any time during the semester for projects. There are 3 late days total, not 3 per project. To use a late day, submit to the autograder after the deadline. It will prompt you about using one of your late day tokens. There are more details about late days in the syllabus.
Remember that we grade your BEST submission for style. If multiple submissions are tied in score, we take the last of those.
WARNING: Beware the autograder’s ability to detect cheating! See Collaboration Policy for further information.
Understanding the Distribution Code
rps.cpp: Starter code for the application you will write in this project. Holds the definitions of required functions and the implementations of a couple functions. We have stubbed all required functions for you.
test.cpp: Testing functions for your rps.cpp implementation. Holds the declarations of required testing functions. We have stubbed all required functions for you.
start.cpp: This file contains the main() function for your program, which allows you to run either the rps application or your test suite. You do not need to modify this file or submit it to the autograder.
Stubbing functions means adding the minimal necessary code to make a function compile. For example, some of the functions in rps.cpp
have return types of bool
. We have added return false
in those functions so that they will compile even if you have not implemented all the functions yet. Be sure to remove our return statements when you write your own implementation of the function.
Testing Your Setup
Once you have created a project, you should be able to compile and run the distribution code. We have included a main()
function in start.cpp
which will allow you to run either your tests or the rps application.
------------------------------- | |
EECS 183 Project 2 Menu Options | |
------------------------------- | |
1) Execute testing functions in test.cpp | |
2) Execute rps() function to play game | |
Choice --> 1 | |
Executing your test cases | |
Now testing function isMoveGood() | |
'r': Expected: 1, Actual: 1 | |
'q': Expected: 0, Actual: 1 | |
... |
The second test case currently fails because the isMoveGood()
function is not fully implemented yet.
How to get help
Most students in EECS 183 need help from staff and faculty multiple times each project. We’re here for you! Many more people need help with Project 2 than with Project 1.
If your question is about the specification or about something about the project in general, Piazza is the fastest place to get help.
Office Hours: All office hours and instructions for signing up/attending can be found under the Office Hours tab on the course website.
Individual office hours: You can get 1-1 help over a video call by signing up for office hours at eecsoh.org. You can find instructions here.
Collaboration Policy and the Honor Code
All students in the class are presumed to be decent and honorable, and all students in the class are bound by the College of Engineering Honor Code.
We want students to learn from and with each other, and we encourage you to collaborate. We also want to encourage you to reach out and get help when you need it.
You are encouraged to:
- Give or receive help in understanding course concepts covered in lecture or lab.
- Practice and study with other students to prepare for assessments or exams.
- Consult with other students to better understand project specifications.
- Discuss general design principles or ideas as they relate to projects.
- Help others understand compiler errors or how to debug parts of their code.
To clarify the last item, you are permitted to look at another student’s code to help them understand what is going on with their code. You are not allowed to tell them what to write for their code, and you are not allowed to copy their work to use in your own solution. If you are at all unsure whether your collaboration is allowed, please contact the course staff via the admin form before you do anything. We will help you determine if what you’re thinking of doing is in the spirit of collaboration for EECS 183.
The following are considered Honor Code violations:
- Submitting others’ work as your own.
- Copying or deriving portions of your code from others’ solutions.
- Collaborating to write your code so that your solutions are identifiably similar.
- Sharing your code with others to use as a resource when writing their code.
- Receiving help from others to write your code.
- Sharing test cases with others if they are turned in as part of your solution.
- Sharing your code in any way, including making it publicly available in any form (e.g. a public GitHub repository or personal website).
The full collaboration policy can be found in the syllabus.
We run every submission against every other submission and determine similarities. All projects that are “too similar” are forwarded to the Engineering Honor Council. This happened to numerous students last semester. Also know that it takes months to get a resolution from the Honor Council. Discussing the project with other students will NOT be an issue. Sharing code between students, even if it’s just one function, will likely cause the cheating detector to identify both programs as “too similar”. We also search the web for solutions that may be posted online and add these into the mix of those checked for similarities. Searching the web, by the way, is something that we are very good at.
Any violation of the honor policies appropriate to each piece of course work will be reported to the Honor Council, and if guilt is established, penalties may be imposed by the Honor Council and Faculty Committee on Discipline. Such penalties can include, but are not limited to, letter grade deductions or expulsion from the University.
Also note that on all cases forwarded to the Engineering Honor Council the LSA Dean of Academic Affairs is also notified. Furthermore, the LSA rule is students involved in honor violations cannot withdraw from nor drop the course.
Problem Statement
Your task for this project is to create a program for playing a game of rock-paper-scissors between two players. The game will consist of exactly three rounds of rock-paper-scissors. A player will need to win more of the three rounds than their opponent to win the game. The game will result in a tie if no player wins more rounds than the other player. For example: if Player 1 wins the first round while rounds 2 and 3 both result in a draw, Player 1 would win the game since they have won more rounds than Player 2.
IMPORTANT: So that we can automate the testing of your code, the output messages for the rock-paper-scissors game must be exactly the same as presented in this specification and the function RMEs. Making sure they are exact is critical to passing the autograder. Check the Sample Output below for the exact prompts. To avoid spelling errors, simply copy/paste the appropriate prompt into your code. Note that a spelling error will cause you to fail almost every test case from the autograder. Use of a diffchecker can easily catch such errors.
Here is an example of what the execution of your final application will look like:
---------------------------------------- | |
EECS 183 | |
Rock-Paper-Scissors | |
---------------------------------------- | |
Player 1, enter your name: Rana Makki | |
Player 2, enter your name: David Cao | |
Menu Options | |
------------ | |
1) Play rock, paper, scissors | |
2) Play rock, paper, scissors, lizard, spock | |
3) Quit | |
Choice --> 1 | |
Rana Makki, enter your move: r | |
David Cao, enter your move: p | |
David Cao wins the round! | |
Rana Makki, enter your move: r | |
David Cao, enter your move: r | |
This round is a draw! | |
Rana Makki, enter your move: p | |
David Cao, enter your move: s | |
David Cao wins the round! | |
Congratulations David Cao! | |
You won EECS 183 Rock-Paper-Scissors! | |
Menu Options | |
------------ | |
1) Play rock, paper, scissors | |
2) Play rock, paper, scissors, lizard, spock | |
3) Quit | |
Choice --> 3 | |
---------------------------------------- | |
Thanks for playing | |
Rock-Paper-Scissors! | |
---------------------------------------- |
Development Cycle with Functions
In Project 1, you had to divide the program into pieces so you could test each part individually. In Project 2 and later, the program is already divided into functions in the starter code which you can use as the parts to work on. You should write, test, and debug one function at a time. See Lecture 5 for a recap of how to implement the iterative development cycle for functions.
The functions in a program call each other, and it is easiest to start with the functions that do not call any other functions. For example, in this project, getMove()
will call isMoveGood()
, so it makes sense to complete isMoveGood()
before getMove()
. We will be able to test isMoveGood()
before we write the code that actually uses it in our program.
The order you write the functions will be different than the order they will appear in rps.cpp. We provide a suggested order for writing your functions in the Suggested Timeline.
Solution Overview
- Your program will provide a menu, implemented using a loop, to obtain user input and play rock-paper-scissors games.
NOTE: Even though we are going over what happens in
rps()
early in the specification, this does NOT mean you should begin your implementation withrps()
. Actually, you should writerps()
last, after you have implemented all of the other functions, sincerps()
will work by calling all of the other functions.
- To begin, your program will call
printInitialHeader()
, which will print this heading:
---------------------------------------- | |
EECS 183 | |
Rock-Paper-Scissors | |
---------------------------------------- |
- Next, your program will obtain the two player names, which will not change for the duration of the program. First, Player 1 will be asked to input their name:
---------------------------------------- | |
EECS 183 | |
Rock-Paper-Scissors | |
---------------------------------------- | |
Player 1, enter your name: |
Once Player 1’s name is entered, the program will prompt Player 2 for their name:
---------------------------------------- | |
EECS 183 | |
Rock-Paper-Scissors | |
---------------------------------------- | |
Player 1, enter your name: Rana Makki | |
Player 2, enter your name: |
Note that “Rana Makki” in the sample output above is user-entered text, and therefore is not included in the output prompt. Also note that player names can contain whitespace.
Next, your program will call
getMenuChoice()
, which will print the menu (by calling another function that does this) and will obtain user input for menu selection.The menu options are:
Menu Options ------------ 1) Play rock, paper, scissors 2) Play rock, paper, scissors, lizard, spock 3) Quit Choice --> Depending upon the value the user enters for “Choice”, the program will either initiate a game of rock-paper-scissors, initiate a game of rock-paper-scissors-lizard-spock, or quit.
Your program shall continue to play games and prompt the user for another choice until a user input of ‘Quit’ (user choice 3) is entered.
When the user input indicates that they’ve had enough and want out of EECS 183 Rock-Paper-Scissors, your program will call
printCloser()
, which will print this heading:---------------------------------------- Thanks for playing Rock-Paper-Scissors! ---------------------------------------- and the program naturally finishes.
There are many functions that assist in making all of this happen. Below is a brief overview of the functions you will use in this project. For in-depth descriptions of the functions’ behavior, please read the RME’s within rps.cpp.
IMPORTANT: For the functions you will implement, write their definitions below
rps()
, as indicated in rps.cpp.
printInitialHeader()
- This function has been implemented for you.
printMenu()
- This function has been implemented for you.
printErrorMessage()
- This function has been implemented for you.
printCloser()
- This function has been implemented for you.
getName()
This function prompts a player for their name and handles the input accordingly.
This function utilizes the following function(s):
printErrorMessage()
getMenuChoice()
This function will handle printing the menu and reading in the user’s menu choice from input.
Make sure to print an extra newline right after every call to cin. This is so it can behave correctly on the autograder.
This function utilizes the following function(s):
printMenu()
Invalid input: You cannot depend upon users to get the input within range. You also need to handle out of range input. If the user enters a menu option other than
1
,2
, or3
you need toprint
Invalid menu choice
re-print the menu, and
get another menu choice
This needs to be repeated until a valid menu choice is entered.
BE CAREFUL: this function’s purpose is solely to get a single menu choice from the user and return this choice. This function should not be for playing the actual game of rock-paper-scissors and should not call additional functions beyond
printMenu()
.
isMoveGood()
- This function determines whether or not a player’s move is valid. A valid move consists of an ‘r’, ‘p’ or ‘s’ character, corresponding to “rock”, “paper”, and “scissors”, respectively. The uppercase versions of these characters are also considered valid. Any other characters a user enters will be considered invalid.
IMPORTANT: Note that for this project you can assume user input will always be of the data type expected (which is
char
for moves). In other words, as the programmer, you only need to check that values entered are valid moves - you do not need to worry about users enteringintegers
,doubles
,strings
,bools
or any combination of these. Those are bad input and prohibited by the REQUIRES clause.
- This function utilizes no other functions.
getMove()
This function prompts a player to enter their move during a round, and handles the input accordingly.
Make sure to print an extra newline before the function returns. This is so it can behave correctly on the autograder.
This function utilizes the following function(s):
printErrorMessage()
isMoveGood()
There are two things that could happen depending on the character that the user inputs for their move:
- If valid move: The function returns the move.
David Cao, enter your move: p |
- If invalid move: The program will print an error message as shown below, and the function will assign (and return) a “default” move for the user that entered invalid input. Note that the default move is ‘r’.
David Cao, enter your move: a | |
ERROR: Illegal move given, using default |
isRoundWinner()
This function determines if the player made a winning move. Note: a move that results in a tie is not a winning move.
This function utilizes no other functions.
announceRoundWinner()
This function announces the name of the round winner. If there is no round winner, it outputs that the round resulted in a draw.
This function utilizes no other functions.
doRound()
This function will simulate one round of the game.
This function utilizes the following function(s):
getMove()
isRoundWinner()
announceWinner()
This function announces the name of the game winner. If there is no winner of the game, it outputs that there was no winner.
This function utilizes no other functions.
doGame()
This is the function that plays three rounds of rock-paper-scissors, announces round winners, and keeps track of the number of rounds each player has won. A player receives a point if they win a round. If the round is a draw, no player receives a point. The full game will always consist of three rounds. This means that even if the same player wins the first two rounds, the third round will always be played.
Hint: Make use of the
MAX_ROUNDS
constant defined and initialized at the top of rps.cpp when implementing this function.This function utilizes the following function(s):
doRound()
announceRoundWinner()
For the base project, if the game_type provided to this function is 2 (indicating that the user selected rock-paper-scissors-lizard-spock), the only thing this function needs to do is return an empty string after printing the following message:
Under Construction Only the S’more version needs to handle a game_type of 2 and implement rock-paper-scissors-lizard-spock.
Putting it Together: Writing rps()
Once you have written and tested each of the above functions, it is time to combine everything in
rps()
and do further testing with your new debugging skills. Be sure that your program behaves as illustrated in the Sample Output.Now that you have a new project created and
rps.cpp
in front of you, it’s time to begin! The game is managed in therps()
function — but do not write code there before you have thought about the problem and implemented all of the other functions.You can find some starter pseudocode for implementing the rock-paper-scissors game below to help get you started:
// Print the header // Get player 1 name // Get player 2 name // Repeat the following until the user quits the program: // Print the menu and get the menu choice, continuing to prompt until the user // chooses a valid menu choice // Play the game and announce the winner, or quit the program (according to user's menu choice) // Print the closing message In programming, when you start by outlining the problem at hand, add in one small piece at a time, and test as you go, implementing a solution is much more manageable.
Function Table
The table below provides an outline of which other functions each function should call, if any. You should not be using other functions if not specified.
Function | Other functions it should call |
---|---|
getName() | printErrorMessage() |
getMenuChoice() | printMenu() |
isMoveGood() | Does not utilize any other functions |
getMove() | printErrorMessage() , isMoveGood() |
isRoundWinner() | Does not utilize any other functions |
announceRoundWinner() | Does not utilize any other functions |
doRound() | getMove() , isRoundWinner() |
announceWinner() | Does not utilize any other functions |
doGame() | doRound() , announceRoundWinner() |
rps() | printInitialHeader() , getName() , getMenuChoice() , doGame() , announceWinner() , printCloser() |
Here is an example of how to read the table:
getName()
should callprintErrorMessage()
Suggested Timeline
Note: It’s common to not completely understand the project after reading through the spec. This is okay! You can start working on the project without fully understanding the spec. In fact, working on the project will likely help you better understand the spec.
As an approximate timeline, you will be on track if by:
- September 18: Starter code downloaded and new project set up in IDE. Starter code submitted to autograder. You’ve read through the spec.
- September 20:
isMoveGood()
,getMove()
,isRoundWinner()
,announceRoundWinner()
, andannounceWinner()
implemented, fully tested, and passing autograder. - September 22:
getName()
,getMenuChoice()
,doRound()
implemented, fully tested, and passing autograder. - September 24:
doGame()
implemented, fully tested, and passing autograder. Start work onrps()
. - September 25:
rps()
code “complete.” Debugging in progress, passing all individual function tests, 80% or higher on autograder - September 27: Make last submission to autograder for 5% extra credit
- September 28: Make last submission to autograder for 2.5% extra credit
- September 29: Project due date.
Creating a Project
If you haven’t done so already, read the Getting Started with Xcode guide or Getting Started with Visual Studio guide, depending on the operating system you’re using. They will walk you through creating a new project and basic editing.
Once you create a project, you’ll need to import rps.cpp
, test.cpp
, and start.cpp
.
Xcode
There are a couple of ways to import a file in Xcode. The easiest way, perhaps, is to drag and drop that file next to
main.cpp
in the Navigator area on the left side of the Xcode window.Check the checkbox next to Destination: Copy items if needed, make sure that the checkbox next to Add to targets is checked and click Finish.
Alternatively, you can choose File > Add Files to… in the menu bar, navigate to your file, select it and click Add (or press Option-Command-A). Make sure that the checkbox next to Add to targets is checked when you are adding
.cpp
files.Now there is a problem: there are two
main()
functions in your project: one inmain.cpp
that was automatically inserted by Xcode when you created a new project and another one written by the staff instart.cpp
that you’ve just imported. Recall that a C++ program must have one and only onemain()
function, so your code will not compile. But not to worry! Just deletemain.cpp
that was automatically created by Xcode by right-clicking (or Control-clicking) onmain.cpp
in the Navigator area on the left side of the Xcode window and choose Delete.
Visual Studio
To add a new file to your Visual Studio project, right-click on Source Files in the Solution Explorer and choose Add > Existing Item… (or press Shift-Alt-A).
Navigate to
rps.cpp
, select it and click Add.You should now see the contents of
rps.cpp
in the Code pane (editing area).
IMPORTANT: Repeat the process to add
test.cpp
andstart.cpp
to your project.
NOTE: Be sure to add your name, your uniqname and a small description of the program to the header comments at the top of
rps.cpp
andtest.cpp
.
Running the Program
Once you have created a project, you should be able to compile and run the distribution code. We have included a main()
function in start.cpp
which will allow you to select exectuing your test cases or executing the game Rock Paper Scissors. When executing your project, you should see the following message:
Enter 1 to select exectuing your test cases starting with the
startTests()
function intest.cpp
, enter 2 to select executing your Rock Paper Scissors game starting with therps()
function inrps.cpp
(red text represents your input)Select 1 for test cases
------------------------------- EECS 183 Project 2 Menu Options ------------------------------- 1) Execute testing functions in test.cpp 2) Execute rps() function to play game Choice --> 1 Executing your test cases Now testing function isMoveGood() 'r': Expected: 1, Actual: 1 'q': Expected: 0, Actual: 1 Testing
As part of this project, you will also submit a test suite for testing some of the functions you implement in
rps.cpp
. It is important to note that you will only be testing your program for invalid input rather than bad input. For the purposes of this document, “bad input” will refer to input whose type (char
,int
,double
, etc.) is different than what is expected by your program. So if your program is expecting that the user will input an integer — you are guaranteed to always receive input of typeint
and will not receive something likechar
, which would be considered bad input. On the other hand, you will be testing for “invalid input,” which has the correct type but is considered invalid given the program specification. The RMEs will be clear about what is considered to be invalid input for a specific function.To help you with writing your tests, you can take advantage of
test.cpp
and the autograder. You will write your test functions intest.cpp
and submit it to the autograder. (See How to Submit section.) The autograder will run your test suite against buggy programs in order to see if your tests can expose enough bugs. The nature of the bugs will be hidden from you so you will have to think about how invalid input may affect your program and cause it to produce incorrect behavior given specifications.When thinking about writing tests, it is helpful to examine the RME for the functions and figure out what the function is actually supposed to do. Then, write tests that target each step in that process for potential bugs. One question you might have is: how do I know that I have enough tests? In practice, this question is usually not helpful and isn’t the correct way to think about writing tests. ?This is because a common pitfall for students is to write a lot of tests that all fundamentally test the same functionality of a function. This isn’t useful when trying to expose bugs in other parts of a function’s implementation, and so in this case more tests are not necessarily better.
- For example, if you are trying to test a function that divides two integers and returns the result, you could write an infinite number of test cases that divide positive integers by positive integers and never expose a bug with negative integers or dividing by zero.
In Lab 4, you will be writing test cases for certain functions in this project. The test cases you come up with for lab are meant to help you with this project and you are meant to submit them along with your test cases for the remaining functions to the autograder. It is not an Honor Code violation to submit tests that you may have come up with in your group for the lab (but still is for functions not covered in lab).
NOTE: Remember, you only have to think about exposing bugs related to invalid input and not bad input.
Testing Overview
It is considered good practice to write the test suite BEFORE you implement a function. The idea is to know if you are correct or not without using a submit to the autograder. This is also a very good way to cut coding time by a significant amount.
NOTE: The basic idea of testing is you start small and build. Start with the obvious inputs needed then expand to the boundary conditions, and then expand further into the what else category.
Remember, a computer does not interpret. If you misspell a word, you will fail all autograder test cases. If you omit punctuation, you will fail all autograder test cases. We strongly suggest you test your code. Use
diff
tools to compare the Sample Output against the output generated by your code using the same input. Some easy-to-use diff websites that we recommend are:
Testing getName() and getMenuChoice()
To test
getName()
andgetMenuChoice()
, you do NOT need any of the other functions implemented. You should test these functions thoroughly now, so if something goes wrong with your code in the future you will know it is NOT these functions. This method of testing will save you mega-time.To test
getName()
andgetMenuChoice()
, you need to check them against good input and invalid input. Therefore, to test these functions, call them withinstartTests()
and make sure you get the output and action you expect.void test_getName(); void test_getMenuChoice(); void startTests() { cout << "\nExecuting your test cases\n"; test_isMoveGood(); // TODO: call more test functions here test_getName(); test_getMenuChoice(); return; } void test_getName() { cout << "Now testing function getName()\n"; cout << "testing good input" << endl; // a valid input would be Rana cout << getName(1) << endl; cout << getName(2) << endl; cout << "testing invalid input" << endl; // an invalid input would be just pressing enter cout << getName(1) << endl; // more test cases... } void test_getMenuChoice() { cout << "Now testing function getMenuChoice()\n"; cout << "testing good input" << endl; // good inputs would be 1, 2, or 3 cout << getMenuChoice() << endl; cout << getMenuChoice() << endl; cout << getMenuChoice() << endl; cout << "testing invalid input" << endl; // invalid input would be other numbers, like 5 or -1 cout << getMenuChoice() << endl; // more test cases... } For “good input” in
getName()
, you want to check valid player names (valid names have at least one character). For “good input” ingetMenuChoice()
, you should try the valid menu choices1
,2
, and3
. Run your code. Make absolutely sure that the functions output the values you expect for the different inputs you provide.Now that we have laid out the testing approach for
getName()
andgetMenuChoice()
, take the concepts and apply them to the other functions. You can do this. Just follow the same line of thinking.
Implementing Test Functions for Submission
The file
test.cpp
includes function stubs fortest_isMoveGood()
andtest_isRoundWinner()
. Your task is to implement these functions, which should callisMoveGood()
andisRoundWinner()
, respectively, to test their behavior.The test functions you write should reveal incorrect implementations of
isMoveGood()
andisRoundWinner()
. Your job is to create a thorough test suite, calling the RPS functions with a variety of valid and invalid inputs (not bad inputs, as noted above).Keep in mind that you should only test values that adhere to the Requires clauses of functions. For example, when testing
isRoundWinner()
, note thatbool isRoundWinner(char move, char opponent_move)
“Requires” that “both move and opponent_move are valid moves”.What this means is you can — and should — test:
// because 'r' and 's' are valid moves cout << "'r' and 's' Expected: 1, Actual: " << isRoundWinner('r', 's') << endl; However, a move like ‘x’ is invalid. Therefore, even though it is “legal” within C++ to write
// INVALID test case - this would violate the RME of isRoundWinner() cout << "'r' and 'x' Expected: 1, Actual: " << isRoundWinner('r', 'x') << endl; It violates the Requires clause and the programmer should not do this. It is the responsibility of the coder to not violate the Requires clauses of the functions they call.
Note that the functions stubbed in
test.cpp
are the only test functions you will need to submit to the autograder.However, you should still write tests for
getName()
,getMenuChoice()
, and the functions involved in game play to ensure that your individual functions behave as expected before writing themain()
function for your program. You can call these test functions inmain()
and remove them before submission. Do not include these functions when you submit to the autograder.When you submit
test.cpp
, we will compile and run it with our correct implementation ofrps.cpp
and with our buggy implementation ofrps.cpp
, so as to generate two different outputs. We’ll then compare two outputs. If there is any difference, you’ve successfully exposed a bug! The autograder does not go into the details of what the difference is, it only sees if there exists a difference.Remember that some functions don’t print anything on their own; we have to print their return value, as with the function
isMoveGood()
:cout << "'r': Expected: 1, Actual: " << isMoveGood('r') << endl; cout << "'q': Expected: 0, Actual: " << isMoveGood('q') << endl; (Keep in mind that
bool
values are printed as0
or1
.)After you submit your test suite, you might see output that looks like this:
That means that your test suite exposed 1 out of 8 bugs in the staff’s “buggy” implementations of
rps.cpp
and your score for the test suite is 1.5 out of 10 points.
Bugs To Expose
There are a total of 8 unique bugs to find in our implementations. Your tests do not need to expose all of the bugs to receive full points for this part of the project. The autograder will tell you the names of the bugs that you have exposed, from the following set:
CHECK_ISMOVEGOOD_1
CHECK_ISMOVEGOOD_2
CHECK_ANNOUNCEROUNDWINNER_1
CHECK_ANNOUNCEROUNDWINNER_2
CHECK_ANNOUNCEWINNER_1
CHECK_ANNOUNCEWINNER_2
CHECK_ISROUNDWINNER_1
CHECK_ISROUNDWINNER_2
Preparing your test.cpp for Submission
You will write all your tests and execute them from
startTests()
in yourtest.cpp
file. This will include:The function bodies the test functions (e.g.,
test_isMoveGood()
andtest_isRoundWinner()
).The code you wrote in
startTests()
to call the test functions.
At any time you can submit your
test.cpp
to the autograder (How to Submit) to see how many bugs your tests exposed. However, remember you only have four submissions each day with feedback.