I'm following a tutorial for making a MUD (text-based RPG), and I am having issues with my main function. If you'll look at the code, you'll see that when the player moves it will check for a random encounter, and if monster != 0, it will go into the combat loop. When I execute this in the command prompt, it will allow me to attack the monster, but it never makes it to the monster->attack(mainPlayer) function. It just goes back to the screen that states whether I want to move, rest, view stats, or quit. Any help with this would be greatly appreciated!
#include "stdafx.h"
#include "Map.h"
#include "Player.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
srand( time(0) );
Map gameMap;
Player mainPlayer;
mainPlayer.createClass();
// Begin adventure
bool done = false;
while( !done )
{
// Each loop cycle we output the player position and
// a selection menu.
gameMap.printPlayerPos();
int selection = 1;
cout << "1) Move 2) Rest 3) View Stats 4) Quit: ";
cin >> selection;
Monster* monster = 0;
switch( selection )
{
case 1:
// Move the player
gameMap.movePlayer();
// Check for a random encounter. This function
// returns a null pointer if no monsters are
// encountered.
monster = gameMap.checkRandomEncounter();
// 'monster' not null, run combat simulation.
if( monster != 0)
{
// Loop until 'break' statement.
while( true )
{
// Display hitpoints
mainPlayer.displayHitPoints();
monster->displayHitPoints();
cout << endl;
// Player's turn to attack first.
bool runAway = mainPlayer.attack(*monster);
if( runAway )
{
break;
}
if( monster->isDead() )
{
mainPlayer.victory(monster->getXPReward());
mainPlayer.levelUp();
break;
}
monster->attack(mainPlayer);
if( mainPlayer.isDead() )
{
mainPlayer.gameover();
done = true;
break;
}
}
// The pointer to a monster returned from
// checkRandomEncounter was allocated with
// 'new', so we must delete it to avoid
// memeory leaks.
delete monster;
monster = 0;
}
break;
case 2:
mainPlayer.rest();
break;
case 3:
mainPlayer.viewStats();
break;
case 4:
done = true;
break;
} // End switch statement
} // End While statement
} // End main function
Here is the Player::attack function:
bool Player::attack(Monster& monster)
{
int selection = 1;
std::cout << "1) Attack 2) Run: ";
std::cin >> selection;
std::cout << std::endl;
switch( selection )
{
case 1:
std::cout << "You attack the " << monster.getName()
<< " with a " << mWeapon.mName << std::endl;
if( Random(0, 20) < mAccuracy )
{
int damage = Random(mWeapon.mDamageRange);
int totalDamage = damage - monster.getArmor();
if( totalDamage <= 0)
{
std::cout << "Your attack failed to penetrate the "
<< monster.getName() << "'s armor." << std::endl;
}
else
{
std::cout << "You attack for " << totalDamage
<< " damage!" << std::endl;
// Subtract from monster's hitpoints.
monster.takeDamage(totalDamage);
}
}
else
{
std::cout << "You miss!" << std::endl;
}
std::cout << std::endl;
break;
case 2:
// 25% chance of being able to run.
int roll = Random(1, 4);
if( roll == 1 )
{
std::cout << "You run away!" << std::endl;
return true; //<-- Return out of the function.
}
else
{
std::cout << "You could not escape!" << std::endl;
break;
}
}
}
And here is the Monster::attack function:
void Monster::attack(Player& player)
{
cout << "A " <<mName << " attacks you "
<< "with a " << mWeapon.mName << std::endl;
if( Random(0,20) < mAccuracy )
{
int damage = Random(mWeapon.mDamageRange);
int totalDamage = damage - player.getArmor();
if( totalDamage <= 0 )
{
cout << "The " << mName << "'s attack failed to "
<< "penetrate your armor." << endl;
}
else
{
cout << "You are hit for " << totalDamage
<< " damage!" << endl;
player.takeDamage(totalDamage);
}
}
else
{
cout << "The " << mName << " missed!" << endl;
}
cout << endl;
}
Your Player::attack() method has only one return-statement: return true;. You forgot to add the final line return false; to your method.
This could have easily been prevented if you enable warnings (and pay attention to them!)
Your Player::attack doesn't return in all cases (specifically when it needs to return false). When the calling function tries to access the return value of Player::Attack it will get junk and so you enter the if(ranAway) block and break out of your while loop
Related
So I am making a textbased RPG and I wanted to have multiple enemy encounter at once. So I modified my function that determines whether an object of the class Monster, to fill in the Monster(s) into an array of the class monster and set the objects bool to true, as you can see here:
Monster * Map::checkRandomEncounter()
{
Monster* monster = new Monster[3];
for (int i = 0; i < 3; i++)
{
int roll = Random(0, 20);
if (roll <= 5)
{
//No encounter
return 0;
}
else if (roll > 6 && roll < 10)
{
monster[i] = Monster();
monster[i].giveID("Orc", 10, 8, 200, 100, 1, "Short Sword", 2, 7);
monster[i].isFilled();
std::cout << "You encounter an Orc!" << std::endl;
std::cout << "Prepare for battle!" << std::endl;
std::cout << std::endl;
}
else if (roll >= 11 && roll <= 15)
{
monster[i] = Monster();
monster[i].giveID("Goblin", 6, 6, 100, 75, 0, "Dagger", 1, 5);
monster[i].isFilled();
std::cout << "You encounter a Goblin!" << std::endl;
std::cout << "Prepare for battle!" << std::endl;
std::cout << std::endl;
}
else if (roll >= 16 && roll <= 19)
{
monster[i] = Monster();
monster[i].giveID("Ogre", 20, 12, 500, 200, 2, "Club", 3, 8);
monster[i].isFilled();
std::cout << "You encounter an Ogre!" << std::endl;
std::cout << "Prepare for battle!" << std::endl;
std::cout << std::endl;
}
else if (roll == 20)
{
monster[i] = Monster();
monster[i].giveID("Orc Lord",
25,
15,
2000,
1000,
5,
"Two Handed Sword",
5,
20);
monster[i].isFilled();
std::cout << "You encounter an Orc Lord!" << std::endl;
std::cout << "Prepare for battle!" << std::endl;
std::cout << std::endl;
}
}
return monster;
}
The function above will be called in my main function, which looks like this:
int main()
{
srand(time(0));
Map gameMap;
Player mainPlayer;
mainPlayer.createClass();
//Beginn adventure
bool done = false;
while (done == false)
{
// Each Loop Cycle outputs player pos and selection menu
gameMap.printPlayerPos();
int selection = 1;
std::cout << "1) Move 2) Rest 3) View Stats 4) Quit: ";
std::cin >> selection;
Monster* monster = 0;
switch (selection)
{
case 1: // Move the player
gameMap.movePlayer();
if (gameMap.getPlayerXPos() == 2
&& gameMap.getPlayerYPos() == 3)
{
std::cout << "You see a store nearby !" << std::endl;
}
if (gameMap.getPlayerXPos() == 2
&& gameMap.getPlayerYPos() == 4)
{
Store store;
store.enter();
store.showInventory(mainPlayer);
}
//Check for a random encounter
//returns a null pointer if no encounter happened
monster = gameMap.checkRandomEncounter();
//'monster' not null, start battle script
if (monster != 0)
{
//Loop until a break statement
for (int i = 0; i < 3; i++)
{
//Display Hitpoints
mainPlayer.displayHitPoints();
monster[i].displayHitPoints();
std::cout << std::endl;
//Players turn to attack first
**bool runAway = mainPlayer.attack(monster, mainPlayer);** // Crash happening in this area
if (runAway) // Player flees
{
break;
}
if (monster[i].isDead())
{
mainPlayer.victory(monster->getXPReward(),
monster->getGoldReward());
mainPlayer.levelUp(mainPlayer);
}
break;
//Monster attacks
monster[i].attack(mainPlayer);
if (mainPlayer.isDead())
{
mainPlayer.gameOver();
done = true;
break;
}
}
//Pointer to Monster must destroy created instance of Monster
//to make sure that there is no Memory leak
}
delete monster;
monster = 0;
break;
case 2: // resting
mainPlayer.rest();
monster = gameMap.checkRandomEncounter();
//'monster' not null, start battle script
monster = gameMap.checkRandomEncounter();
//'monster' not null, start battle script
if (monster != 0)
{
//Loop until a break statement
for (int i = 0; i < 3; i++)
{
//Display Hitpoints
mainPlayer.displayHitPoints();
monster[i].displayHitPoints();
std::cout << std::endl;
//Players turn to attack first
bool runAway = mainPlayer.attack(monster, mainPlayer);
if (runAway) // Player flees
{
break;
}
if (monster[i].isDead())
{
mainPlayer.victory(monster->getXPReward(),
monster->getGoldReward());
mainPlayer.levelUp(mainPlayer);
}
break;
//Monster attacks
monster[i].attack(mainPlayer);
if (mainPlayer.isDead())
{
mainPlayer.gameOver();
done = true;
break;
}
}
//Pointer to Monster must destroy created instance of Monster
//to make sure that there is no Memory leak
}
delete monster;
monster = 0;
break;
case 3: // viewing stats
mainPlayer.viewStats();
break;
case 4: // quitting
done = true;
break;
}
}
return 0;
}
and finally the last puzzle piece, the function where the player attacks the Monster(s):
bool Player::attack(Monster Monster[], Player& Player)
{
int ArmorBefore = 0;
int Roll = 0;
int selection = 1;
int i;
if (Monster[0].isFilled() == true)
{
i = 0;
}
else if (Monster[1].isFilled() == true)
{
i = 1;
}
else if (Monster[2].isFilled() == true)
{
i = 2;
}
if (Monster[i].isFilled() == true)
{
std::cout << "1) Attack 2) Run 3) Cast Spell 4) Use Item: ";
std::cin >> selection;
std::cout << std::endl;
switch (selection)
{
case 1: // Player fights
std::cout << " You attack an " << Monster[i].getName()
<< " with a " << mWeapon.mName << std::endl;
if (Random(0, 20) < mAccuracy) // Player hits Monster
{
int damage = Random(mWeapon.mDamageRange);
int totalDamage = damage - Monster[i].getArmor();
if (totalDamage <= 0) // Armor is equal or higher than player atk
{
std::cout << "Your attack failed to penetrate "
<< Monster[i].getName() << "'s armor !"
<< std::endl;
return false;
}
else // Attack is higher than Monsters armor
{
std::cout << "You hit " << Monster[i].getName()
<< " for " << totalDamage << " damage !"
<< std::endl;
// Subtract dmg from Monsters hp
Monster[i].takeDamage(totalDamage);
return false;
}
}
else // Player Misses
{
std::cout << "You miss !" << std::endl;
}
std::cout << std::endl;
return false;
break;
case 2: // Player runs with a 25% chance
Roll = Random(1, 4);
if (Roll == 1) // Success
{
std::cout << "You run away !" << std::endl;
return true; // <- Return out of the function
}
else
{
std::cout << "You failed to escape !" << std::endl;
return false;
}
case 3: // Casting Spell
{
int SpellSelect;
// Spells for the Fighter
if (Player.mClassName == "Fighter")
{
std::cout << std::endl;
std::cout << "1) Shield 2) Mighty Blow: ";
std::cin >> SpellSelect;
if (SpellSelect == 1)
{
if (Player.mMagicPoints >= 10) // checks for player mana
{
std::cout << "You cast a mighty shield!"
<< std::endl;
ArmorBefore = Player.mArmor;
Player.shield(Player);
Player.mMagicPoints -= 10;
}
else
{
std::cout << "Not enough Mana" << std::endl;
break;
}
}
else
{
if (Player.mMagicPoints >= 5) // casting Mighty Blow
{
int damage = Random(mMightyBlow.mDamageRange);
std::cout
<< "You strike with all your might ! and Deal "
<< damage << " damage !" << std::endl;
Monster[i].takeDamage(damage);
Player.mMagicPoints -= 5;
return false;
}
else
{
std::cout << "Not enough Mana" << std::endl;
return false;
}
}
}
//Spells for the Wizard
else if (Player.mClassName == "Wizard")
{
std::cout << "1) Fireball";
std::cin >> SpellSelect;
if (Player.mMagicPoints >= 45)
{
int damage = Random(mFireball.mDamageRange);
std::cout << "You cast a Fireball and deal " << damage
<< " damage !" << std::endl;
Monster[i].takeDamage(damage);
Player.mMagicPoints -= 45;
return false;
}
else
{
std::cout << "Not enough Mana" << std::endl;
return false;
}
}
// Spells for the Cleric
else if (Player.mClassName == "Cleric")
{
std::cout << "1) Magic Missile";
std::cin >> SpellSelect;
if (Player.mMagicPoints >= 35)
{
int damage = Random(mMagicMissile.mDamageRange);
std::cout << "You cast a Magic Missile and deal "
<< damage << " damage !" << std::endl;
Monster[i].takeDamage(damage);
Player.mMagicPoints -= 35;
}
else
{
std::cout << "Not enough Mana" << std::endl;
return false;
}
}
}
case 4: // using Item
int invSlot;
std::cout << "1) HP Potion: ";
std::cin >> invSlot;
if (invSlot == 1) // Potion slot
{
if (mHPot.mAmount.size() > 0)
{
std::cout << "You used a Potion and healed for 5 HP !"
<< std::endl;
int currentSize = mHPot.mAmount.size();
mHPot.mAmount.resize(currentSize - 1);
Player.mHitPoints += 5;
if (Player.mHitPoints > Player.mMaxHitPoints)
{
Player.mHitPoints = Player.mMaxHitPoints;
}
return false;
}
else
{
std::cout << "You have no Potions!" << std::endl;
return false;
}
}
else // wrong slot
{
std::cout << "No Item found!" << std::endl;
return false;
}
}
// Clearing stat boosts
if (Player.shield(Player) == true)
{
Player.mArmor = ArmorBefore;
}
}
return false;
}
When I run the game, I sometimes have the problem, that after filling in a Monster in a slot of the array, no battle will be triggered. And if a battle will be triggered, I get a crash with an error report every time, which says:
_CrtlValidHeadPointer(block)
I guess that something with my pointer is not functioning well.... but since I am a beginner I am pretty much stuck. I would be very grateful for some enlightenment :)
This place can potentially call undefined behavior and crash:
int i;
if (Monster[0].isFilled() == true)
{
i = 0;
}
else if (Monster[1].isFilled() == true)
{
i = 1;
}
else if (Monster[2].isFilled() == true)
{
i = 2;
}
/*else // one of solutions
break;*/
//"i" can be unset! and can have any value from INT_MIN to INT_MAX!
if (Monster[i].isFilled() == true) //potentially index over array
{
Also there are memory leaks and undefined behavior with memory management:
Monster* monster = new Monster[3];
...
delete monster
must be delete [] monster
but it is recommended to use smart pointers, vector, array, etc, for memory management
I'm trying to follow a C++ class to get more acquainted with the language and Unreal Engine. However, now whenever I start the program, the console window immediately closes. I've already tried fixing the subsystem stuff and I've seen some dirty code that wouldn't close the window, but I'd like to know how to get the problem fixed without trying to find a weird circumnavigation.
/* This is the console executable, that makes use of the BullCowClass
This acts as the view in a MVC pattern, and is responsible for all
user interaction. For game logic see the FBullCow`enter code here`Game class.
*/
#include <iostream>
#include <string>
#include "FBullCowGame.h"
using FText = std::string;
using int32 = int;
void PrintIntro();
void PlayGame();
FText GetValidGuess();
bool AskToPlayAgain();
FBullCowGame BCGame; //instantiatiate a new game
// entry point for our application
int main()
{
bool bPlayAgain = false;
do
{
PrintIntro();
PlayGame();
bPlayAgain = AskToPlayAgain();
} while (bPlayAgain == true);
return 0;
}
void PrintIntro()
{
//introduce to game
std::cout << "Welcome to Bulls and Cows" << std::endl;
std::cout << "Can you guess the " << BCGame.GetHiddenWordLength() << " letter isogram I'm thinking of?\n";
std::cout << std::endl;
return;
}
void PlayGame()
{
BCGame.Reset();
int32 MaxTries = BCGame.GetMaxTries();
//looping for the numbert of turns asking for guesses
for (int32 i = 1; i <= MaxTries; i++) {// TODO change from FOR to WHILE
FText Guess = GetValidGuess();
// submit valid guess to the game and receive counts
FBullCowCount BullCowCount = BCGame.SubmitGuess(Guess);
std::cout << "Bulls = " << BullCowCount.Bulls;
std::cout << ". Cows = " << BullCowCount.Cows << "." << "\n\n";
}
// TODO summarize game here
}
//loop continually until the use gives a valid guess
FText GetValidGuess() // TODO change to GetValidGuess
{
EGuessStatus Status = EGuessStatus::Invalid_Status;
do {
//get a guess from the player
int32 CurrentTry = BCGame.GetCurrentTry();
std::cout << "Try " << CurrentTry << " What is your word guess: ";
FText Guess = "";
std::getline(std::cin, Guess);
Status = BCGame.CheckGuessValidity(Guess);
switch (Status)
{
case EGuessStatus::Wrong_Length:
std::cout << "Please enter a " << BCGame.GetHiddenWordLength() << " letter word.\n";
break;
case EGuessStatus::Not_Isogram:
std::cout << "Please enter an isogram.\n";
break;
case EGuessStatus::Not_Lowercase:
std::cout << "Please enter your guess in lowercase letters.\n";
break;
default:
return Guess;
}
std::cout << std::endl;
{
};
} while (Status != EGuessStatus::OK); //keep looping until we get no errors
}
bool AskToPlayAgain()
{
std::cout << "Do you want to play again(y/n)? ";
FText Response = "";
std::getline(std::cin, Response);
if (Response[0] == 'y')
{
return true;
}
if (Response[0] == 'n')
{
return false;
}
return false;
}
IF you are redirecting your output to a text file then it wont stop after execution. You can check the projectsettings under Debugging Section.
I am making a simple game for learning purposes mostly and I recently ran into this problem. Keep in mind that I'm still a huge beginner. When I go into the game from the menu and write anything in the "Command Line" I instantly starve and dehydrate. I haven't been able to connect to the internet for a couple of days and I've read through the entire program but I can't find anything wrong.
menu.h
#include <iostream>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <dos.h>
#include <windows.h>
#include <WinBase.h>
//-------------//
#include "tutorial.h"
#include "game.h"
void menu() {
std::cout << "-------MENU------- \n";
std::cout << " 1.Play \n";
std::cout << " 2.Tutorial \n";
std::cout << " 3.Exit \n";
std::cout << " \n";
std::cout << " \n";
std::cout << " \n";
std::cout << "Choose Option: ";
int menuOption;
std::cin >> menuOption;
int menuLoop = 0;
while (menuLoop != 1) {
if (menuOption == 1) {
menuLoop = 1;
play();
}
if (menuOption == 2) {
menuLoop = 1;
system("CLS");
tutorial();
}
if (menuOption == 3) {
menuLoop = 1;
std::cout << "Bye!";
Sleep(1000);
}
if (menuOption > 3)
std::cout << "\"" << menuOption << "\"" << " is not a valid option.\n";
}
}
game.h
#include <iostream>
#include <string>
#include <windows.h>
#include <WinBase.h>
//initiating functions
void step();
void run();
void theme();
void starve();
void die();
void dehydrate();
void b();
//globals
std::string name;
std::string commandLine;
int onRoad = 1; // 1 = True, 0 = False
int steps = 0;
double hunger = 0.0;
double thirst = 0.0;
int energy = 5;
void play() {
system("CLS");
std::cout << "Enter your name: \n";
std::cin >> name;
system("CLS");
theme();
Sleep(350);
std::cout << " " << name << "'s Roadtrip\n";
std::cout << "Type \"/help\" for help\n";
std::cout << "---------Command Line---------\n";
std::cin >> commandLine;
while (onRoad != 0){
//------------------Conditions start------------------
// Hunger Conditions
if (hunger = 0){
if (hunger < 0){
std::cout << "You can't eat that, you're not hungry.\n";
b();
}
}
if (hunger > 100){
hunger = 100;
}
if (hunger < 0){
hunger = 0;
}
if (hunger = 100){
starve();
}
else if (hunger > 96){
std::cout << "You're extremely hungry! If you don't eat something quick you're going to die!\n";
b();
}
else if (hunger > 90) {
std::cout << "You're very hungry.\n";
b();
}
else if (hunger > 80) {
std::cout << "You're hungry.\n";
b();
}
// Thirst Conditions
if (thirst = 0){
if (thirst < 0){
std::cout << "You can't drink that, you're not thirsty.\n";
}
}
if (thirst < 0){
thirst = 0;
}
if (thirst > 100) {
thirst = 100;
}
if (thirst = 100){
dehydrate();
}
else if (thirst > 90){
std::cout << "You're extremely thirsty! If you don't drink something quick you're going to die!\n";
b();
}
else if (thirst > 75) {
std::cout << "You're very thirsty.\n";
b();
}
else if (thirst > 50){
std::cout << "You're thirsty.\n";
b();
}
//Energy Conditions
if (energy > 10){
energy = 10;
}
if (energy < 0){
energy = 0;
}
//-------------------Conditions end-------------------
if (commandLine == "/commands"){
std::cout << "-Command- -Action-\n";
std::cout << " /help Displays this menu.\n";
std::cout << " /commands Displays list of commands.\n";
std::cout << " /step Take a step and display total amount of steps.\n";
std::cout << " /run Take 5 steps and consume 5 energy.\n";
std::cout << " Doesn't increase hunger or thirst.\n";
std::cout << " /inventory Displays inventory.\n";
std::cout << " /info Displays stats.\n";
b();
}
if (commandLine == "/step") {
step();
b();
}
if (commandLine == "/info") {
std::cout << name << "'s stats\n";
std::cout << "Hunger: " << hunger << std::endl;
std::cout << "Thirst: " << thirst << std::endl;
std::cout << "Energy: " << energy << std::endl;
b();
}
else {
std::cout << commandLine << " is not a valid command. Type /commands to display commands.\n";
b();
}
}
}
void step(){
steps += 1;
std::cout << steps;
hunger += 5;
thirst += 5;
}
void run() {
steps += 5;
std::cout << steps;
}
void starve(){
std::cout << "You starved to death!\n";
die();
}
void dehydrate(){
std::cout << "You dehydrated!\n";
die();
}
void die(){
std::cout << "Steps taken: " << steps << std::endl;
onRoad = 0;
}
void theme(){
Beep(600, 200);
Beep(500, 200);
Beep(800, 400);
}
// b takes you back to the command line
void b(){
std::cin >> commandLine;
}
main.cpp
#include <iostream>
#include "menu.h"
#include <WinBase.h>
#include <windows.h>
int main(){
menu();
system("PAUSE");
return 0;
}
**EDIT: ** Pic: http://i.imgur.com/yu1V1pq.png (need 10 rep to post picture)
This is really weird. I entered /step and it worked, and then i entered /run and it also worked. I don't understand...
Some of your if statements do assignment instead of comparison
if (hunger = 100){
starve();
}
You probably need to change = to ==
Enable warnings while compiling, if you have not already done so.
Because
// b takes you back to the command line
void b(){
std::cin >> commandLine;
}
b doesn't take you back to the command line just wait for a character to be read and then it returns. If you want to go back, you should follow the way you came from. For example exiting play will return you to the menu loop, obviously with menuLoop = 1 so it will exit the whole program but with modifications this is not a bad looping system.
Edit: I've seen what you do mean in the "command line".
Like others said, you have a load of conditions accidentally spelled as assignments.
Also, indeed, the b() function is eating subsequent commands.
Maybe you should
use std::getline() to read a command one line at a time
or use std::cin.ignore() inside b() to actually consume until the end of the line
PS. Due to the use of globals I have a hard time verifying the game loop logic. I just know that /step after /step gets ignored without effect right now. Separate your input from the loop control and try to remove the global variables.
INFO
Instead of writing std::cout every single time you can just write using namespace std; on the beginning after that you dont need to write std::cout just write cout << "" ;
I am currently in the process of writing a C++ Monty Hall Problem Simulation and have run into some trouble. The error I keep getting is:
source.cpp(23): error C4700: uninitialized local variable 'doorReveal' used
source.cpp(25): error C4700: uninitialized local variable 'doorSwitch' used
source.cpp(52): error C4700: uninitialized local variable 'stayWin' used
source.cpp(56): error C4700: uninitialized local variable 'switchWin' used
I can't seem to figure out what is wrong. The project is supposed to simulate the wins by first staying with the original door choice on the first 100 tries and then switching when door is revealed on the next 100 tries. Thank you all for your help in advance.
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
int doorChoice;
int prizeDoor;
int doorReveal;
int doorSwitch;
int count;
int switchWin;
int stayWin;
srand((unsigned int) time(0));
for (count = 0; count <= 200; count++)
{
prizeDoor = (rand() % 3) + 1;
doorChoice = (rand() % 3) + 1;
cout << "The prize door is door number " << prizeDoor << " ." << endl;
cout << "The door the contestant chose was door " << doorChoice << endl;
doorReveal != prizeDoor || doorChoice;
cout << "The host revealed door number " << doorReveal << " ." << endl;
doorSwitch != doorChoice || doorReveal;
while (count < 101)
{
if (doorChoice == prizeDoor)
{
cout << "Great Job! You won!" << endl;
}
else {
cout << "Not this time!" << endl;
}
}
while (count < 201)
{
if (doorSwitch == prizeDoor)
{
cout << "You switched and won!" << endl;
}
else {
cout << "You switched and lost!" << endl;
}
}
if (doorChoice == prizeDoor)
{
stayWin++;
}
if (doorSwitch == prizeDoor)
{
switchWin++;
}
count++;
}
cout << "Your win percentage when staying was " << stayWin << "%!" << endl;
cout << "Your win percentage when switching was " << switchWin << "%!" << endl;
return 0;
}
Problem 1: operator!=
operator != doesn't do what you think it does.
Did you mean
doorReveal = !(prizeDoor || doorChoice);
cout << "The host revealed door number " << doorReveal << " ." << endl;
doorSwitch = (doorChoice || doorReveal);
I sense another logic issue in determining the doorReveal. I'll have to think about that later.Edit: see problem 5
Problem 2: while
There's also a problem with the while loops:
while(count < 101)
// ...
while(count < 201)
They're infinite loops, because count isn't increased during the loop. I think you meant if there, instead of while.
Problem 3: Initiliazing switchWin and stayWin
These variables are only being incremented. Like #KonradRudolph suggested,
declare your variables where they are first needed
initialize them
while you're at it, mark them const as appropriate
Problem 4: rand()%3 is biased
You should probably use a uniform distribution.
See
http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx
I'll leave using std::uniform_int_distribution as an exercise for the reader here, as it is likely beyond the scope of your course. Remember to use it though, in any real life code.
Problem 5: Fix your door 'derivation'
Booleans aren't sets. Even if they were, you'd be stuck to binary sets. I propose the following model:
enum doors { door1 = 1, door2 = 2, door3 = 4, any = door1|door2|door3 };
so you can say:
doors const doorReveal = doors(~(prizeDoor | doorChoice) & any);
doors const doorSwitch = doors(~(doorChoice | doorReveal) & any);
Fixing that results in a program that appears to work:
#include <iostream>
#include <time.h>
using namespace std;
enum doors { door1 = 1, door2 = 2, door3 = 4, any = door1|door2|door3 };
static inline std::ostream& operator<<(std::ostream& os, doors val) {
switch(val) {
case door1: return os << "door #1";
case door2: return os << "door #2";
case door3: return os << "door #3";
case any: return os << "any door";
}
return os << "OOPS";
}
int main()
{
unsigned switchWin = 0;
unsigned stayWin = 0;
srand((unsigned int) time(0));
for(int count = 0; count <= 200; count++)
{
doors const prizeDoor = doors(1 << rand() / ( RAND_MAX / 3 ));
doors const doorChoice = doors(1 << rand() / ( RAND_MAX / 3 ));
cout << "The prize door is door number " << prizeDoor << " ." << endl;
cout << "The door the contestant chose was door " << doorChoice << endl;
doors const doorReveal = doors(~(prizeDoor | doorChoice) & any);
doors const doorSwitch = doors(~(doorChoice | doorReveal) & any);
cout << "The host revealed door number " << doorReveal << " ." << endl;
if(count < 101)
{
if(doorChoice == prizeDoor)
{
cout << "Great Job! You won!" << endl;
}
else
{
cout << "Not this time!" << endl;
}
};
if(count < 201)
{
if(doorSwitch == prizeDoor)
{
cout << "You switched and won!" << endl;
}
else
{
cout << "You switched and lost!" << endl;
}
};
if(doorChoice == prizeDoor)
{
stayWin++;
}
if(doorSwitch == prizeDoor)
{
switchWin++;
};
count++;
}
cout << "Your win percentage when staying was " << stayWin << "%!" << endl;
cout << "Your win percentage when switching was " << switchWin << "%!" << endl;
return 0;
}
Im new to programming and C++ and I started making a little string type game for fun, which gives the user two options through out the program, but in the final part of the program i cant get it to output a unique option for the final input(makeCure) - which i only want to output at the end not through out the program. Hope Im making sense :/ .Iv tried and tried and tried and the more i try the more probloms I create. Iv shown below in my code where Im sure the problom lies. Any advice would much appreciated.
#include<iostream>
#include<string>
using std::string;
bool intro(void);
void room(bool enemy, bool data, bool cure, string description);
//player stats
string Name = "";
//enemy states
string enemyName = "";
//data stats
string dataName = "";
//Cure - Option in room7 only
string makeCure = "";
//room descriptions(string constructs)
const string room1 = "You enter the first town of infected Zombies.";
const string room2 = "You are overwelmed by Zombies, and plunder into the sewers to escape.";
const string room3 = "You make your way to safety and find yourself in the Central Town Hall.";
const string room4 = "You decide to venture into the local forest to find the finalingrediants";
const string room5 = "You venture further for the final ingrediant, into a nearby Cave.";
const string room6 = "Its time for you to face the Zombie General!!!";
const string room7 = "You work day and Night in the Labs to make the Cure.";
int main(void)
{
if(intro())
return 0;
dataName = "First Ingrediant- Zombie Rags with infected DNA";
enemyName = "Zombie Soldior";
room(true, true, false, room1);
enemyName = "Massive Zombie Rat";
room(true, false, false, room2);
dataName = "Seconed Ingrediant- StemCells";
enemyName = "Mutated Scientists";
room(true, true, false, room3);
dataName = "Third Magic-Mushrooms";
room(false, true, false, room4);
dataName = "Fourth Final Ingrediant - Coffee Beans";
enemyName = "Commander Zombie";
room(true, true, false, room5);
enemyName = "Zombie General";
room(false, true, false, room6);
return 0;
makeCure = "Elixier to Save the World";
room(false, false, true, room7);
return 0;
}
bool intro(void)
{
using std::cout;
using std::cin;
cout << "Brave Soul!!! What is your name?\n";
cin >> Name;
cout << "Ahh... " << Name << " You say.." << "How about Zombie Slayer?.. Good, glad we agree!\n";
cout << "Humanity is in need of your Help, "
<< "The world is being infected by the\n"
<< "ZD1678 ZOMBIE VIRUS \n"
<< "And we need to send you to Cape Town to stop the central spread.\n"
<< "Your task will be tough, but we know you can do it \n"
<< "Will you accept the challenge?\n\n";
cout << "1)Yes. \n"
<< "2)No. \n\n";
int response;
cin >> response;
return !(response ==1);
}
void room(bool enemy, bool data, bool cure, string description)
{
using std::cout;
using std:: cin;
while(true)
{
cout << description.c_str() << "\n\n";
int response = 0;
do
{
cout << "Shall Our Hero continue his Quest?\n";
if(enemy)
cout << "1) Attack the "
<< enemyName.c_str() << "\n";
else if(!enemy)
cout << "1) venture further....";
if(data)
cout << "2)Pick up the "
<< dataName.c_str() << "\n";
cin >> response;
/* Trying to create the last if that only kicks in at room7( string makeCure )
* that displays the option to make the cure
* This is where my Problem is.
* Iv tried anouther if
* and else
* and while and nothing works, its just messes up everything..
* badly
*/
} while(response < 1 || response > 2);
switch(response)
{
case 1:
if(enemy)
{
enemy = !enemy;
cout << "You slay the deadly "
<< enemyName.c_str() << "\n";
}
else if(!enemy)
return;
break;
case 2:
data = !data;
cout << "You pick up the "
<< dataName.c_str() << "\n";
break;
}
}
}
what you probably want to do is dynamically generate a list of possible events each time you write out the list and present it to the user, then you can match the response to the list to get what the user wants to do. like this:
enum EventType
{
ET_Enemy,
ET_Item,
ET_Cure,
ET_Continue,
ET_MAX
};
void room(bool enemy, bool data, bool cure, string description)
{
using std::cout;
using std:: cin;
int currentEventChoices[ET_MAX];
int numEventChoices;
while(true)
{
cout << description.c_str() << "\n\n";
int response = 0;
do
{
numEventChoices = 0;
cout << "Shall Our Hero continue his Quest?\n";
if(enemy)
{
cout << (numEventChoices+1) << ") Attack the "
<< enemyName.c_str() << "\n";
currentEventChoices[numEventChoices] = ET_Enemy;
numEventChoices++;
}
if(data)
{
cout << (numEventChoices+1) << ") Pick up the "
<< dataName.c_str() << "\n";
currentEventChoices[numEventChoices] = ET_Item;
numEventChoices++;
}
if(cure)
{
cout << (numEventChoices+1) << ") cure related string "
<< makeCure.c_str() << "\n";
currentEventChoices[numEventChoices] = ET_Cure;
numEventChoices++;
}
cout << (numEventChoices+1) << ") venture further....\n"; // note if this is only meant to be an option if there is no enemy, put it in an else after the if(enemy)
numEventChoices++;
cin >> response;
} while(response < 1 || response > numEventChoices);
switch(currentEventChoices[response-1])
{
case ET_Enemy:
enemy = !enemy;
cout << "You slay the deadly "
<< enemyName.c_str() << "\n";
break;
case ET_Item:
data = !data;
cout << "You pick up the "
<< dataName.c_str() << "\n";
break;
case ET_Cure:
//do cure stuff
break;
case ET_Continue:
return;
}
}
}
the trouble you are having is that by just using a very static next of if/else statements each time you want to match the option number to the event, it gets very complex and messy, it was fine when there was just the 4 cases of there being an enemy or not, or data or not. but now you are adding another branch with cure, its just got really complex to do it that way.
It's a bit hard to understand what you need, so tell me if it's not what you wanted.
Using braces and indenting consistently can really help with this:
do {
cout << "Shall Our Hero continue his Quest?\n";
if (enemy) {
cout << "1) Attack the " << enemyName << "\n";
} else {
cout << "1) venture further....";
}
if (data) {
cout << "2) Pick up the " << dataName << "\n";
}
if (cure) {
cout << "2) take the " << makeCure << "\n";
}
cin >> response;
} while (response < 1 || response > 2);
and fix "case 2" in the switch part:
case 2:
if (data) {
data = false;
cout << "You pick up the " << dataName << "\n";
} else if (cure) {
// fill in ...
}
break;
Notes:
You can use endl (from std) instead of '\n'. cout << "hello" << endl;
You can pass many of your global variables as arguments, so you won't need them to be global (global is bad, in general).
Much of your game can be be squeeszed into arrays and structs - being "data driven" and "table driven". I don't know if you got there already, but you can try and identify these parts.
if(enemy) ... else if(!enemy) you don't need the !enemy part. it is implied by the else.