Deal or No Deal – With a twist
Program Description
This assignment requires you to write a program to play a modified version of the popular game “Deal or No Deal”. Usually, the game begins with 26 unopened cases where each case corresponds to a certain amount of money. However, your program should give the player the choice of playing the game with 16, 18, 20, 22, 24, or 26 unopened cases.
A game is played for a certain number of rounds. The number of rounds depends on the number of cases chosen by the player. In the first and subsequent rounds, the player must open a certain number of cases before getting an offer from the bank. At this point, the player can choose to accept the offer and stop playing (“Deal”) or keep on playing (“No Deal”).
The monetary amounts in a game and the number of rounds in the game depend on the number of cases chosen at the beginning by the player. This information must be read from a file as follows:
You should assume that there will be at least 16 cases and at most 26 cases; also, you should assume that the number of cases is even.
Structure of Data Files
If the player chooses to play a game with 26 cases, the file Data26.txt must be opened. The first 26 lines of the file contain the monetary amounts (integer values) that should be assigned to each case. The remaining lines contain the number of rounds for the game and the number of cases to be opened in each round. The contents of Data16.txt, Data18.txt, Data20.txt, Data22.txt, and Data24.txt are organized in the same way.
Functionality of Program
- 1. The program should start by requesting the player to choose the number of cases for the game (16, 18, 20, 22, 24, or 26).
2. Based on the number of cases chosen, the appropriate text file is opened and the data is read and stored (preferably in 1-D arrays, one for the cases and one for the rounds). The remainder of this section assumes that the player chooses 26 cases.
3. The player should be requested to choose a case to start the game. This case must be removed from play and set aside, but it must not be opened.
4. In each round of the game, the player is requested to pick a certain number of unopened cases (as specified in the data file), one by one. At the start of the round and before the player is asked to choose a case, the unopened cases must be displayed. For example, if the player chooses case 26 at the beginning, at the start of Round #1, the following cases should be displayed:
As each case is opened, the monetary value is shown and the monetary value for that case is ‘removed’ (i.e., not shown) from the “money board”. For example, suppose that the player picks case 13 as the first case in Round #1. If case 13 has $15.00, it is ‘removed’ as follows:
When a case is opened, it is also ‘removed’ from the list of available cases to choose from:
5. At the end of each round, except the last, the banker makes an offer to the player. The offer is calculated as follows:
- (a) Find the average of the monetary amount in the unopened cases.
- (b) Multiply the result in (a) by (number of the current round / total number of rounds), using floating-point division.
6. The player can accept the offer and terminate the game (“Deal”). If the player does not accept the offer (“No Deal”), the next round is entered. This continues until there are no more rounds.
Solution:
#include < iostream>
#include < iomanip>
#include < fstream>
#include < cstdlib>
#include < ctime>
using namespace std;
// To be opened by the player
struct Case
{
int value;
bool opened;
};
// Display the cases as a table
void displayCases(Case *cases, int numCases, int heldCaseIndex)
{
for (int i = 0; i < numCases; i++)
{
if (i != 0 && i % 5 == 0)
cout << endl;
if (heldCaseIndex == i || cases[i].opened)
cout << setw(5) << " ";
else
cout << setw(5) << (i + 1);
}
cout << endl;
}
// The user will choose a case to open
int chooseCase(Case *cases, int numCases, int heldCaseIndex)
{
cout << "Please choose a case: ";
int chosenCase;
cin >> chosenCase;
chosenCase--;
// Validate the chosen case
while (chosenCase < 0 || chosenCase >= numCases
|| chosenCase == heldCaseIndex
|| cases[chosenCase].opened)
{
cout << "Invalid case. Try again: ";
cin >> chosenCase;
chosenCase--;
}
return chosenCase;
}
// Remove a value from the list of case values
void clearChosenCaseValue(int *sortedCaseValues, int numCases, int value)
{
for (int i = 0; i < numCases; i++)
{
if (sortedCaseValues[i] == value)
{
sortedCaseValues[i] = 0;
break;
}
}
}
// Display the 2 column case values
void displayCaseSortedValues(int *sortedCaseValues, int numCases)
{
for (int leftI = 0, rightI = numCases / 2; leftI < numCases / 2; leftI++, rightI++)
{
if (sortedCaseValues[leftI] == 0)
cout << setw(10) << " ";
else
cout << setw(10) << sortedCaseValues[leftI];
if (sortedCaseValues[rightI] == 0)
cout << setw(10) << " ";
else
cout << setw(10) << sortedCaseValues[rightI];
cout << endl;
}
}
// Play a round
void playRound(int round, Case *cases, int *sortedCaseValues,
int numCases, int heldCaseIndex, int numAllowedCases)
{
cout << "We are in Round " << round << "." << endl;
cout << "You must choose " << numAllowedCases << " cases in this round." << endl;
cout << endl;
// Display the case numbers
for (; numAllowedCases > 0; numAllowedCases--)
{
displayCases(cases, numCases, heldCaseIndex);
int chosenCaseIndex = chooseCase(cases, numCases, heldCaseIndex);
// Open the case and remove the value from the sorted case values
cases[chosenCaseIndex].opened = true;
clearChosenCaseValue(sortedCaseValues, numCases, cases[chosenCaseIndex].value);
// Display the values of the unopened cases
cout << "The value of case " << (chosenCaseIndex + 1) << " is $"
<< cases[chosenCaseIndex].value << ". "
<< "The unopened cases contain the following values" << endl;
displayCaseSortedValues(sortedCaseValues, numCases);
cout << endl;
}
}
// Shuffle the cases
void shuffleCases(Case *cases, int numCases)
{
// Shuffle the case values
for (int i = numCases - 1; i > 0; i--)
{
int j = rand() % (i + 1);
Case temp = cases[i];
cases[i] = cases[j];
cases[j] = temp;
}
}
// Load the cases from file
void loadedCases(ifstream &inFile, Case *cases,
int *sortedCaseValues, int numCases)
{
for (int i = 0; i < numCases; i++)
{
inFile >> cases[i].value;
cases[i].opened = false;
sortedCaseValues[i] = cases[i].value;
}
shuffleCases(cases, numCases);
}
// Load how many cases are allowed to open for each round
void loadCasesPerRound(ifstream &inFile, int *allowedCasesPerRound, int numRounds)
{
for (int i = 0; i < numRounds; i++)
inFile >> allowedCasesPerRound[i];
}
// Force the user to choose the starting case of the game
int chooseInitialCase(int numCases)
{
cout << "There are " << numCases << " cases. Enter a case number you want to hold: ";
int heldCaseIndex;
cin >> heldCaseIndex;
while (heldCaseIndex < 1 || heldCaseIndex > numCases)
{
cout << "Invalid selection, try again: ";
cin >> heldCaseIndex;
}
return heldCaseIndex - 1;
}
// Count how many are closed
int countClosedCases(Case *cases, int numCases)
{
int numClosed = 0;
for (int i = 0; i < numCases; i++)
if (!cases[i].opened)
numClosed++;
return numClosed;
}
// Calculate how much the banker would offer
double calculateBankerOffer(Case *cases, int numCases, int currentRound, int totalRounds)
{
// Find the aveage of closed
double totalValue = 0;
int numClosed = countClosedCases(cases, numCases);
for (int i = 0; i < numCases; i++)
if (!cases[i].opened)
totalValue += cases[i].value;
double averageValue = totalValue / numClosed;
int numOpened = numCases - numClosed;
return averageValue * ((double)currentRound / totalRounds);
}
// Entry point of the program
int main()
{
srand((unsigned) time(0));
// Load the number of cases
cout << "How many cases (16, 18, 20, 22, 24, or 26)? ";
int numCases;
cin >> numCases;
ifstream inFile;
if (numCases == 16)
inFile.open("Data16.txt");
else if (numCases == 18)
inFile.open("Data18.txt");
else if (numCases == 20)
inFile.open("Data20.txt");
else if (numCases == 22)
inFile.open("Data22.txt");
else if (numCases == 24)
inFile.open("Data24.txt");
else if (numCases == 26)
inFile.open("Data26.txt");
else
{
cout << "Invalid value." << endl;
return 0;
}
if (!inFile.is_open())
{
cout << "Failed to open data file." << endl;
return 0;
}
// Load the cases value all of them are closed initially
int *sortedCaseValues = new int[numCases];
Case *cases = new Case[numCases];
loadedCases(inFile, cases, sortedCaseValues, numCases);
// Load the number of rounds
int numRounds;
inFile >> numRounds;
// For each round load the number of cases allowed to open
int *allowedCasesPerRound = new int[numRounds];
loadCasesPerRound(inFile, allowedCasesPerRound, numRounds);
inFile.close();
// Now we play the game, the user will choose a case to hold
int heldCaseIndex = chooseInitialCase(numCases);
// Now we play each round
double valueWon = -1;
for (int round = 0; round < numRounds; round++)
{
int numAllowedCases = allowedCasesPerRound[round];
playRound(round + 1, cases, sortedCaseValues, numCases,
heldCaseIndex, numAllowedCases);
cout << endl;
// We finished a round, time for banker to make an offer
double offer = calculateBankerOffer(cases, numCases, round + 1,
numRounds);
cout << fixed;
cout << "The banker is offering you $" << setprecision(2) << offer
<< ", do you accept? (Y/N): ";
char option;
cin >> option;
if (option == 'Y' || option == 'y')
{
valueWon = offer;
break;
}
// Apply a game twist, allow the player to swap a case
if (countClosedCases(cases, numCases) > 2)
{
cout << "Would you like to swap your case to another case? (Y/N): ";
cin >> option;
if (option == 'y' || option == 'Y')
{
heldCaseIndex = chooseCase(cases, numCases, heldCaseIndex);
cout << "Case swapped." << endl;
}
}
cout << endl;
}
// If all rounds finished, we open the last case
if (valueWon == -1)
{
cout << "The case you are holding has a value of $"
<< setprecision(2) << cases[heldCaseIndex].value << endl;
valueWon = cases[heldCaseIndex].value;
}
cout << fixed;
cout << "Game over! You won $" << setprecision(2) << valueWon << endl;
// Cleanup
delete[] cases;
delete[] allowedCasesPerRound;
delete[] sortedCaseValues;
return 0;
}