While loop is going one too far - c++

So the problem I'm having is this: When a win condition is met the program should stop the while loop and just display the win/lose/draw message, but instead it allows the X and O of the game to take one more turn and I'm rather at a loss as to why. Any help would be greatly appreciated.
#include <iostream>
#include <cmath>
#include <string>
#include <cstdlib>
#include <ctime>
const int yCoordMax = 6;
const int xCoordMax = 2;
int xCoord;
int yCoord;
int square = 0;
const char PLAYER1 = 'X';
const char COMPUTER = 'O';
const int MAXTURN = 9;
char playerChar ; //the current turn's player's symbol
const std::string WIN = "You won! How nice.\n";
const std::string LOSE = "You lost.\n";
const std::string DRAW = "It's a draw.\n";
const std::string PLAY = "You will be the X's against the computer O's\n\n";
const std::string INSTRUCTIONS = "Enter the number of the square you wish to mark\nwith 1 being top left and 9 being bottom right.\n\n";
const std::string INVALIDSQUARE = "Please enter a correct square number between 1 and 9.\n";
const std::string SQUAREISFULL = "That square is already marked. Choose another.\n";
bool gameOver = false;
bool isGameDraw = false;
char boardChoices[3][3] = {{'1', '2', '3'},{'4', '5', '6'},{'7', '8', '9'}};
void drawBoard(void);
void playGame(void);
bool checkForWinner(void);
void isMoveValid(void);
int main()
{
std::srand(time(0)); //sets the seed for computer only once
std::cout << PLAY;
std::cout << INSTRUCTIONS;
playerChar = PLAYER1;
while(!gameOver)
{
drawBoard();
playGame();
isMoveValid();
gameOver = checkForWinner();
}
if (playerChar == 'O' && !isGameDraw)
{
drawBoard();
std::cout << std::endl << std::endl << "Player 1 [X] Wins! Game Over!\n";
}
else if (playerChar == 'X' && !isGameDraw)
{
drawBoard();
std::cout << std::endl << std::endl << "Player 2 [O] Wins! Game Over!\n";
}
else
{
drawBoard();
std::cout << std::endl << std::endl << "It's a draw! Game Over!\n";
}
return 0;
}
void drawBoard()
{
std::cout << std::endl << std::endl << "gameover says " << gameOver << std::endl;
std::cout << "+----" << "+----+" << "----+" << std::endl; // 0
std::cout << "| " << boardChoices[0][0] << " " << "| " << boardChoices[0][1] << " |" << " " << boardChoices[0][2] << " |" << std::endl; // 1 input here only [1][0], [1][1], [1][2]
std::cout << "+----" << "+----+" << "----+" << std::endl; // 2
std::cout << "| " << boardChoices[1][0] << " " << "| " << boardChoices[1][1] << " |" << " " << boardChoices[1][2] << " |" << std::endl; // 3 input here only [3][0], [3][1], [3][2]
std::cout << "+----" << "+----+" << "----+" << std::endl; // 4
std::cout << "| " << boardChoices[2][0] << " " << "| " << boardChoices[2][1] << " |" << " " << boardChoices[2][2] << " |" << std::endl; // 5 input here only [5][0], [5][1], [5][2]
std::cout << "+----" << "+----+" << "----+" << std::endl;
}
void playGame()
{
std::cout << std::endl;
if(playerChar == PLAYER1)
{
std::cout << "X's turn :: ";
std::cin >> square;
}
else if(playerChar == COMPUTER)
{
square = rand() % 9 + 1;
std::cout << "O's turn:: " << square << std::endl << std::endl;
}
if (square == 1)
{yCoord = 0;
xCoord = 0;}
if (square == 2)
{yCoord = 0;
xCoord = 1;}
if (square == 3)
{yCoord = 0;
xCoord = 2;}
if (square == 4)
{yCoord = 1;
xCoord = 0;}
if (square == 5)
{yCoord = 1;
xCoord = 1;}
if (square == 6)
{yCoord = 1;
xCoord = 2;}
if (square == 7)
{yCoord = 2;
xCoord = 0;}
if (square == 8)
{yCoord = 2;
xCoord = 1;}
if (square == 9)
{yCoord = 2;
xCoord = 2;}
}
void isMoveValid()
{
if(playerChar == PLAYER1 && boardChoices[yCoord][xCoord] != PLAYER1 && boardChoices[yCoord][xCoord] != COMPUTER)
{
boardChoices[yCoord][xCoord] = playerChar;
playerChar = COMPUTER;
}
else if(playerChar == COMPUTER && boardChoices[yCoord][xCoord] != PLAYER1 && boardChoices[yCoord][xCoord] != COMPUTER)
{
boardChoices[yCoord][xCoord] = COMPUTER;
playerChar = PLAYER1;
}
else
{
if(playerChar == PLAYER1)
std::cout << SQUAREISFULL;
}
}
bool checkForWinner()
{
std::string victoryOrDefeat;
if(playerChar == COMPUTER)
{
victoryOrDefeat = LOSE;
}
else if(playerChar == PLAYER1)
{
victoryOrDefeat = WIN;
}
if(boardChoices[0][0] == playerChar && boardChoices[0][1] == playerChar && boardChoices[0][2] == playerChar) // Horizontal
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[1][0] == playerChar && boardChoices[1][1] == playerChar && boardChoices[1][2] == playerChar) // Horizontal
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[2][0] == playerChar && boardChoices[2][1] == playerChar && boardChoices[2][2] == playerChar) // Horizontal
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[0][0] == playerChar && boardChoices[1][0] == playerChar && boardChoices[2][0] == playerChar) // Vertical
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[0][1] == playerChar && boardChoices[1][1] == playerChar && boardChoices[2][1] == playerChar) // Vertical
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[0][2] == playerChar && boardChoices[1][2] == playerChar && boardChoices[2][2] == playerChar) // Vertical
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[0][0] == playerChar && boardChoices[1][1] == playerChar && boardChoices[2][2] == playerChar) // Diagonal
{std::cout << victoryOrDefeat;
return true;}
if(boardChoices[0][2] == playerChar && boardChoices[1][1] == playerChar && boardChoices[2][0] == playerChar) // Diagonal
{std::cout << victoryOrDefeat;
return true;}
for (int i = 0; i < 3; i++)//Check for draw
{
for (int j = 0; j < 3; j++)
{
if (boardChoices[i][j] != 'X' && boardChoices[i][j] != 'O')
{
return false;
}
}
}
isGameDraw = true;
return true;
}

I have got it..You are changing playerChar after each isMoveValid() check as a result when you should be checking with X you are checking with O..simple do this change after checking the winner..that will give correct result.
Initially when player1 gives X position you are checking the win move for giving O and in later cases too this happens.. That's why it's getting the error.

Related

infinite loop in movement function

I have this program that is supposed to simulate fish and sharks moving around on a grid of any given size, but I'm running into an infinite loop in my fish's move function.
the program isn't consistent on when the looping occurs because when I run it sometimes it gets stuck on turn 0, but it could also happen on turn 3; this is possible because of my randomness attached to it
here's my fish_class.cpp where the problem occurs, I've marked where the infinite loop happens. hope anyone could help.
#include "fish_class.h"
#include "world.h"
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
void FishT::SetFishBreed(int fishBreedRate)
{
fishBreed = fishBreedRate;
//return fishBreed;
}
int FishT::GetFishBreed()
{
return fishBreed;
}
int FishT::IncreaseMoves()
{
if (moveCount == fishBreed) //just incase for unlimited breeding
{
moveCount = 0;
}
moveCount++;
return moveCount;
}
void FishT::Move(WorldT& world)
{
bool HasMoved = false;
srand (time (NULL)); //initialize random seed
//generate a number from 1 to 4 (north, south, east, west) to move to on the world grid
int PlaceToMove = static_cast<int>(rand() % 4 + 1);
while (HasMoved == false)
{
if (PlaceToMove == 1 and world.IsInBoundry(x, y - 1) and world.IsEmpty(x, y - 1)) //checking if north is empty and in bounds
{
//cout << "moving fish north" << endl;
//update fish's position
world.SetEmpty(x, y);
world.SetFishPlacement(x, y - 1);
y = y - 1;
HasMoved = true;
Turn(world); //increase our move tracker
}
else if (PlaceToMove == 2 and world.IsInBoundry(x, y + 1) and world.IsEmpty(x, y + 1)) //checking if south is empty and in bounds
{
//cout << "moving fish south" << endl;
//update fish's position
world.SetEmpty(x, y);
world.SetFishPlacement(x, y + 1);
y = y + 1;
HasMoved = true;
Turn(world);
}
else if (PlaceToMove == 3 and world.IsInBoundry(x + 1, y) and world.IsEmpty(x + 1, y)) //checking if east is empty
{
//cout << "moving fish east" << endl;
//update fish's position
world.SetEmpty(x, y);
world.SetFishPlacement(x + 1, y);
x = x + 1;
HasMoved = true;
Turn(world);
}
else if (PlaceToMove == 4 and world.IsInBoundry(x - 1, y) and world.IsEmpty(x - 1, y)) //checking if west is empty
{
//cout << "moving fish west" << endl;
//update fish's position
world.SetEmpty(x, y);
world.SetFishPlacement(x - 1, y);
x = x - 1;
HasMoved = true;
Turn(world);
}
else
{
// *** this is where the loop problem occurs ***
//cout << "updating fish's placetomove" << endl;
PlaceToMove = PlaceToMove % 4 + 1;
}
}
if (PlaceToMove == 1 and moveCount == fishBreed)
{
//cout << "in reproduce north" << endl;
//cout << "fish breed is: " << GetFishBreed() << endl;
//cout << "move count is: " << moveCount << endl;
Reproduce(x, y + 1, world);
}
else if (PlaceToMove == 2 and moveCount == fishBreed)
{
//cout << "in reproduce south" << endl;
//cout << "fish breed is: " << GetFishBreed() << endl;
//cout << "move count is: " << moveCount << endl;
Reproduce(x, y - 1, world);
}
else if (PlaceToMove == 3 and moveCount == fishBreed)
{
//cout << "in reproduce east" << endl;
//cout << "fish breed is: " << GetFishBreed() << endl;
//cout << "move count is: " << moveCount << endl;
Reproduce(x - 1, y, world);
}
else if (PlaceToMove == 4 and moveCount == fishBreed)
{
//cout << "in reproduce west" << endl;
//cout << "fish breed is: " << GetFishBreed() << endl;
//cout << "move count is: " << moveCount << endl;
Reproduce(x + 1, y, world);
}
}
void FishT::Reproduce(int x, int y, WorldT& world)
{
//cout << "in reproduce function" << endl;
world.SetFishPlacement(x, y);
world.AddNewFish(x, y);
}
void FishT::Turn(WorldT& world)
{
IncreaseMoves(); //keep track of move turns
}
void FishT::Die(WorldT& world)
{
world.FishDie(x, y);
}

Problem with array of class objects leads to crash

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

Combat Game - C++, Given a Spawner Class, How can I spawn stronger enemy every round

I have a problem in my OOP homework. I have to code a 1 v 1 battle.
This is a Survival Game where in the player fights continuously with enemies until the player dies. The Player gets stronger as he advances through. The enemy also grows stronger every round.
I have created two Classes, The Unit and the Spawner.
We cannot use Inheritance nor Polymorphism.
We Have to use only the simple definition of the class.
My problem is that i cannot think of a SIMPLE way to make the class Spawner spawn a stronger enemy every round.
I have thought of overloading the Unit's Contructor but i have trouble manipulating that.
Would anyone please help?
Here's my Unit Header file (Unit.h):
#pragma once
#include <string>
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
// Class Types
const string CLASS_WARRIOR = "Warrior" ;
const string CLASS_ASSASSIN = "Assassin";
const string CLASS_MAGE = "Mage" ;
// Class Choices
const int CHOICE_WARRIOR = 1;
const int CHOICE_ASSASSIN = 2;
const int CHOICE_MAGE = 3;
// Multipliers
const double MULTIPLIER_DAMAGE = 0.50f;
const double MULTIPLER_HEAL = 0.30f;
// Advantage
const bool ADVANTAGE = true;
// Win Bonus
const int BONUS_THREE = 3;
const int BONUS_FIVE = 5;
// Minimum and maximum values
const int HIT_RATE_MAX = 80;
const int HIT_RATE_MIN = 20;
const int DAMAGE_MIN = 1;
// Hit or miss
const bool ATTACK_HIT = true;
const bool ATTACK_MISS = false;
class Unit
{
public:
// Constructors
Unit(string name, int classChoice);
// Getters and setters
string getName();
string getClass();
int getHp();
int getMaxHp();
int getPower();
int getVitality();
int getAgility();
int getDexterity();
int getDamage();
int getHeal();
int getBonusDamage();
bool getFirstToAttack();
bool getHit();
void setClassStats(const int classChoice);
// Primary Actions
void attack(Unit* target);
// Secondary Actions
void check(const Unit* target); // Inspects the enemy
void lvlUp(); // Grants this Unit Bonus Stats on Victory
private:
// Info
string mName;
string mClass;
// Basic Stats
int mHp;
int mMaxHp;
int mPower;
int mVitality;
int mAgility;
int mDexterity;
// Derived Stats
int mDamage;
int mHitrate;
int mHeal;
int mBonusDamage;
// Miscellaneous
bool mAdvantage; // If the player has the advantage
string mTargetClass;// This Unit keeps in mind the class of this Unit's Opponent for reference
int mChanceOfHit; // The random chance if the attack will Hit/Miss
bool mFirstToAttack;//if this unit will attack first
bool mHit; // if the attack is a hit or miss
};
Here's my Unit.cpp file (Unit.cpp):
#include "Unit.h"
Unit::Unit(string name, int classChoice)
{
mName = name;
setClassStats(classChoice);
}
string Unit::getName()
{
return mName;
}
string Unit::getClass()
{
return mClass;
}
int Unit::getHp()
{
return mHp;
}
int Unit::getMaxHp()
{
return mMaxHp;
}
int Unit::getPower()
{
return mPower;
}
int Unit::getVitality()
{
return mVitality;
}
int Unit::getAgility()
{
return mAgility;
}
int Unit::getDexterity()
{
return mDexterity;
}
int Unit::getDamage()
{
return mDamage;
}
int Unit::getHeal()
{
return mHeal;
}
int Unit::getBonusDamage()
{
return mBonusDamage;
}
bool Unit::getFirstToAttack()
{
return mFirstToAttack;
}
bool Unit::getHit()
{
return mHit;
}
void Unit::setClassStats(const int classChoice)
{
if (classChoice == CHOICE_WARRIOR) {
mClass = CLASS_WARRIOR;
mMaxHp = 20;
mHp = mMaxHp;
mPower = 15;
mVitality = 10;
mAgility = 7;
mDexterity = 7;
return;
}
else if (classChoice == CHOICE_ASSASSIN) {
mClass = CLASS_ASSASSIN;
mMaxHp = 15;
mHp = mMaxHp;
mPower = 17;
mVitality = 8;
mAgility = 12;
mDexterity = 10;
return;
}
else if (classChoice == CHOICE_MAGE) {
mClass = CLASS_MAGE;
mMaxHp = 30;
mHp = mMaxHp;
mPower = 12;
mVitality = 12;
mAgility = 9;
mDexterity = 8;
return;
}
throw exception("Error! Class not part of this game. ");
}
void Unit::attack(Unit * target)
{
// Determine Whether the attack will Hit/Miss Based on the hit rate
mChanceOfHit = rrand() % 100 + 1;
if (mChanceOfHit > mHitrate) {
mHit = ATTACK_MISS;
return;
}
// Deducts the targets Hp by the Damage given by this Unit (if the attack didn't miss)
target->mHp -= mDamage;
mHit = ATTACK_HIT;
// if target HP is negative, set it to zero
if (target->mHp < 0) target->mHp = 0;
}
void Unit::check(const Unit * target)
{
// The Unit Keeps in Mind his target's Class
if (target->mClass == CLASS_WARRIOR) mTargetClass = CLASS_WARRIOR;
else if (target->mClass == CLASS_ASSASSIN) mTargetClass = CLASS_ASSASSIN;
else if (target->mClass == CLASS_MAGE) mTargetClass = CLASS_MAGE;
// Checks if the Unit is Advantageous Against his Target
if (mClass == CLASS_WARRIOR) {
if (target->mClass == CLASS_ASSASSIN) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
else if (mClass == CLASS_ASSASSIN) {
if (target->mClass == CLASS_MAGE) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
else if (mClass == CLASS_MAGE) {
if (target->mClass == CLASS_WARRIOR) mAdvantage = ADVANTAGE;
else mAdvantage = false;
}
// Determine if this Unit Will Attack first
if (mAgility >= target->mAgility) mFirstToAttack = true;
else mFirstToAttack = false;
// Determines Damage, Bonus Damage ( If Applicable ), and Hit Rate Based on targets stats
mDamage = mPower - target->mVitality;
if (mDamage < DAMAGE_MIN) mDamage = DAMAGE_MIN;
mBonusDamage = mDamage * MULTIPLIER_DAMAGE;
// Evaluates Damage Based on advantage
if (mAdvantage) mDamage += mBonusDamage;
mHitrate = ((float)mDexterity / (float)target->mAgility) * 100;
// Clamps the Hit Rate within the Hit Rate Range
if (mHitrate > HIT_RATE_MAX) mHitrate = HIT_RATE_MAX;
else if (mHitrate < HIT_RATE_MIN) mHitrate = HIT_RATE_MIN;
}
void Unit::lvlUp()
{
// Determine Win Bonus Based on the target that he kept in mind
if (mTargetClass == CLASS_WARRIOR) {
mMaxHp += BONUS_THREE;
mVitality += BONUS_THREE;
}
else if (mTargetClass == CLASS_ASSASSIN) {
mAgility += BONUS_THREE;
mDexterity += BONUS_THREE;
}
else if (mTargetClass == CLASS_MAGE) {
mPower += BONUS_FIVE;
}
// Heals the player 30% of his Maximum HP
mHeal = mMaxHp * MULTIPLER_HEAL;
mHp += mHeal;
}
Here's my Spawner Header file (Spawner.h):
#pragma once
#include "Unit.h"
class Spawner
{
public:
Spawner();
~Spawner();
void spawn(Unit*& unit);
private:
Unit* mUnit;
int mRandomClass;
};
Here's my Spawner.cpp file (Spawner.cpp):
#include "Spawner.h"
Spawner::Spawner()
{
}
Spawner::~Spawner()
{
delete mUnit;
mUnit = NULL;
}
void Spawner::spawn(Unit *& unit)
{
mRandomClass = rand() % 3 + 1;
unit = new Unit("Enemy", mRandomClass);
mUnit = unit;
}
And finally here is my main.cpp:
#include "Unit.h"
#include "Spawner.h"
// Create player
Unit* createPlayer();
// Display Stats
void displayStats(Unit* unit);
// Play 1 round
void playRound(Unit*player, Unit* enemy);
// Simulate 1 attack (implement Higher agility gets to atttack first)
void combat(Unit* player, Unit* enemy);
void main()
{
srand(time(NULL));
Unit* player = createPlayer();
Unit* enemy = NULL;
Spawner *spawner = new Spawner();
int round = 1;
while (true) {
cout << "Round " << round << endl;
spawner->spawn(enemy);
player->check(enemy);
enemy->check(player);
playRound(player, enemy);
// if player is dead, end the game
if (player->getHp() == 0) break;
// else, add stats
player->lvlUp();
delete enemy;
enemy = NULL;
cout << "You defeted an enemy" << endl;
system("pause>nul");
system("cls");
round++;
}
cout << "You were defeted! " << endl;
cout << "You survived until Round " << round << endl;
displayStats(player);
delete player;
player = NULL;
delete spawner;
spawner = NULL;
system("pause>nul");
system("cls");
}
Unit* createPlayer()
{
Unit* unit = NULL;
string name;
int classChoice;
cout << "Enter your Name: ";
getline(cin, name);
system("cls");
cout << "Pick a class: " << endl
<< "\t [ 1 ] Warrior" << endl
<< "\t [ 2 ] Assassin" << endl
<< "\t [ 3 ] Mage" << endl
<< endl;
cin >> classChoice;
while (classChoice > 3 || classChoice <= 0) {
cout << "INVALID INPUT! Please try again" << endl;
cout << "Pick a class: " << endl
<< "\t [ 1 ] Warrior" << endl
<< "\t [ 2 ] Assassin" << endl
<< "\t [ 3 ] Mage" << endl
<< endl;
cin >> classChoice;
}
unit = new Unit(name, classChoice);
return unit;
}
void displayStats(Unit* unit)
{
cout << "=========================================================================================" << endl
<< "Name: " << unit->getName() << " \t \t \t HP: " << unit->getHp() << " / " << unit->getMaxHp() << endl
<< "Class: " << unit->getClass() << endl
<< "==========================================================================================" << endl
<< "POW: " << unit->getPower() << endl
<< "VIT: " << unit->getVitality() << endl
<< "AGI: " << unit->getAgility() << endl
<< "DEX: " << unit->getDexterity() << endl
<< endl;
}
void playRound(Unit*player, Unit* enemy)
{
while (player->getHp() > 0 && enemy->getHp() > 0) {
displayStats(player);
displayStats(enemy);
system("pause>nul");
combat(player, enemy);
system("cls");
}
}
void combat(Unit* player, Unit* enemy)
{
if (player->getFirstToAttack()) {
player->attack(enemy);
if (player->getHit() == ATTACK_MISS) cout << player->getName() << "'s Attack Missed! " << endl;
else if (player->getHit() == ATTACK_HIT) cout << player->getName() << " dealt " << player->getDamage() << " Damage" << endl;
system("pause>nul");
if (enemy->getHp() == 0) return;
enemy->attack(player);
if (enemy->getHit() == ATTACK_MISS) cout << enemy->getName() << "'s Attack Missed! " << endl;
else if (enemy->getHit() == ATTACK_HIT) cout << enemy->getName() << " dealt " << enemy->getDamage() << " Damage" << endl;
system("pause>nul");
return;
}
else if (enemy->getFirstToAttack()) {
enemy->attack(player);
if (enemy->getHit() == ATTACK_MISS) cout << enemy->getName() << "'s Attack Missed! " << endl;
else if (enemy->getHit() == ATTACK_HIT) cout << enemy->getName() << " dealt " << enemy->getDamage() << " Damage" << endl;
system("pause>nul");
if (player->getHp() == 0) return;
player->attack(enemy);
if (player->getHit() == ATTACK_MISS) cout << player->getName() << "'s Attack Missed! " << endl;
else if (player->getHit() == ATTACK_HIT) cout << player->getName() << " dealt " << player->getDamage() << " Damage" << endl;
system("pause>nul");
return;
}
}
Add a "level" to the Unit class, and use the level to increase the stats of the unit (for example level 2 could mean the stats are multiplied by 1.5 or some such). Pass the level as an argument to the constructor similar to the units class.
You need to make your spawner aware of how many enemies it has spawned:
// this belongs into your class definition, it should start at zero
int mCurrentSpawn;
So set it to zero in your constructor:
Spawner::Spawner()
{
mCurrentSpawn = 0;
}
Then reference it when you spawn an enemy:
void Spawner::spawn(Unit *& unit)
{
mRandomClass = rand() % 3 + 1;
unit = new Unit("Enemy", mRandomClass);
mUnit = unit;
mCurrentSpawn++;
int levelUps = mCurrentSpawn - 1;
while(levelUps > 0)
{
mUnit->lvlUp();
levelUps--;
}
}

Unexpected Output using char array in TicTacToe Class

It was pointed out to me here that passing an board array into member functions of a tictactoe class was a bit of bad practice. It makes more sense to make it a private member variable and manipulate it internally without main ever having knowledge of it.
I attempted to implement this change in my code and now i'm receiving very strange character outputs when attempting to print the board to the console:
Image of Output
I have just begun using classes so I imagine that I have made an elementary mistake and it's showing through in this way. Any thoughts?
Main
//implementation of TicTacToe
//Using classes this time
#include <iostream>
#include "TicTacToeClass.h"
int main()
{
//Assumes no play unless user decides they want to play and initializes game variable to TicTacToe class
bool play = false;
TicTacToe game;
play = game.getUserWantToPlay();
//allows for multiple games to be played
while(play == true)
{
char playerWinner = 'n';
char player = 'X';
//single game iteration
while(playerWinner == 'n')
{
game.drawBoard();
game.getPlayerMove(player);
playerWinner = game.checkForWin(player);
if(playerWinner == 'n')
{
player = game.togglePlayer(player);
}
}
game.drawBoard();
play = game.getUserWantToPlay();
}
return(0);
}
Class Header
* TicTacToeClass.h
*
* Created on: Jun 15, 2016
*
*/
#ifndef TICTACTOECLASS_H_
#define TICTACTOECLASS_H_
class TicTacToe
{
public:
bool getUserWantToPlay();
void drawBoard();
void getPlayerMove(char player);
char togglePlayer(char player);
char checkForWin(char player);
private:
char squareArray[9];
};
#endif /* TICTACTOECLASS_H_ */
Class Implementation
//TicTacToe class implementation
//Leeroy Jenkins
#include "TicTacToeClass.h"
#include <iostream>
char squareArray[9] = {'1','2', '3', '4', '5', '6', '7', '8', '9'};
bool TicTacToe::getUserWantToPlay()
{
char response;
bool invalidResponse = true;
bool play = false;
while(invalidResponse == true)
{
std::cout << "Would you like to play a new game of TicTacToe? (y/n) " << std::endl;
std::cin >> response;
if(response == 'y')
{
invalidResponse = false;
play = true;
}
else if(response == 'n')
{
std::cout << "No Problem!";
invalidResponse = false;
}
else
{
std::cout << "Please input a proper response (y/n)" << std::endl;
}
}
return play;
}
void TicTacToe::drawBoard()
{
//draws the game board with updated characters for each player
std::cout << "Player 1 (X) - Player 2 (O)" << std::endl << std::endl << std::endl;
std::cout << " | |" << std::endl;
std::cout << " " << squareArray[0] << " | " << squareArray[1] << " | " << squareArray[2] << std::endl;
std::cout << "____|_____|____" << std::endl;
std::cout << " | | " << std::endl;
std::cout << " " << squareArray[3] << " | " << squareArray[4] << " | " << squareArray[5] << std::endl;
std::cout << "____|_____|____" << std::endl;
std::cout << " | | " << std::endl;
std::cout << " " << squareArray[6] << " | " << squareArray[7] << " | " << squareArray[8] << std::endl;
}
void TicTacToe::getPlayerMove(char player)
{
//Gets player move and stores in board array for display through next iteration
bool playerMoveFound = false;
char playerTurn = '0';
char playerMove = '0';
if(player == 'X')
{
playerTurn = '1';
}
else
{
playerTurn = '2';
}
while(playerMoveFound == false)
{
std::cout << "Player " << playerTurn << " please make a move" << std::endl;
std::cin >> playerMove;
for(int x = 0; x < 9; x++)
{
//If finds the array number makes the change to the iteration...prevents x or o movement
if(playerMove == squareArray[x] && playerMove != 'X' && playerMove != 'O' && playerMove != 'x' && playerMove != 'o')
{
squareArray[x] = player;
playerMoveFound = true;
}
}
if(playerMoveFound == false)
{
std::cout << "Invalid player move..." << std::endl;
}
}
}
char TicTacToe::checkForWin(char player)
{
char playerWin = 'n';
int testForTie = 0;
//Tests winning combinations
if(squareArray[0] == squareArray[1] && squareArray[1] == squareArray[2])
{
playerWin = player;
}
else if(squareArray[0] == squareArray[3] && squareArray[3] == squareArray[6])
{
playerWin = player;
}
else if(squareArray[0] == squareArray[4] && squareArray[4] == squareArray[8])
{
playerWin = player;
}
else if(squareArray[1] == squareArray[4] && squareArray[4] == squareArray[7])
{
playerWin = player;
}
else if(squareArray[2] == squareArray[4] && squareArray[4] == squareArray[6])
{
playerWin = player;
}
else if(squareArray[2] == squareArray[5] && squareArray[5] == squareArray[8])
{
playerWin = player;
}
else if(squareArray[3] == squareArray[4] && squareArray[4] == squareArray[5])
{
playerWin = player;
}
else if(squareArray[6] == squareArray[7] && squareArray[7] == squareArray[8])
{
playerWin = player;
}
else
{
//Tests for a tie game
for(int x = 0; x < 9; x++)
{
if(squareArray[x] == 'x' || squareArray[x] == 'o' || squareArray[x] == 'X' || squareArray[x] == 'O')
{
testForTie++;
}
}
if(testForTie == 9)
{
playerWin = 't';
}
}
if(playerWin == player)
{
if(player == 'X')
{
std::cout << std::endl << "Congratulations player 1! You Win!" << std::endl;
}
else
{
std::cout << std::endl << "Congratulations player 2! You Win!" << std::endl;
}
}
else if(playerWin == 't')
{
std::cout << "Tie! You should play again to settle the duel!" << std::endl;
}
return(playerWin);
}
char TicTacToe::togglePlayer(char player)
{
player = player == 'X' ? 'O':'X';
return(player);
}
It doesn't appear that your TicTacToe class has a constructor that initializes its squareArray class member, your game's board.
char squareArray[9] = {'1','2', '3', '4', '5', '6', '7', '8', '9'};
This declares some variable called squareArray, in the global scope. It does not initialize your class member of the same name, and this doesn't have anything to do with the class's member.
As such, the class member's initial contents consist of uninitialized memory, with random garbage. You're seeing the results of the undefined behavior, displaying the contents of an uninitialized array to std::cout.
You need to have a class constructor that initializes the class member, accordingly.
You never initialized squareArray in TicTacToe which is what
std::cout << " " << squareArray[0] << " | " << squareArray[1] << " | " << squareArray[2] << std::endl;
uses. When you did
char squareArray[9] = {'1','2', '3', '4', '5', '6', '7', '8', '9'};
in the implementation file you make a global char array named squareArray. You do not initialize the class member variable squareArray. You need to write a default constructor that initializes the member variable. You could use
TicTacToe() : squareArray{'1','2', '3', '4', '5', '6', '7', '8', '9'} {}

C++ compile error with functions

I was wondering if someone could lend me some advice as to why my code wont compile. I have a simple tic tac toe game here split up into 3 files. Yet, main.cpp is unable to create an objects from my ticTacToe.h file and I just don't understand why. I feel like I'm a step away from getting this to run. ticTacToe.cpp and ticTacToe.h compile just fine. It's the main.cpp file that produces an error when it gets to line 14 "ttt.create_board();". The error message is "unidentified reference to 'ticTacToe: :create_board(char)'" Any help would be greatly appreciated. Thanks guys.
main.cpp
#include "ticTacToe.h"
#include <iostream>
#include <limits> //This is required to catch invalid user input
void run_game()
{
char letter_o = 'O';
char letter_x = 'X';
ticTacToe ttt; //creates an object "ttt" to be used later
ttt.player1Piece = letter_x;
ttt.player2Piece = letter_o;
std::cout << "Welcome to tic tac toe!" << std::endl;
std::cout << "Here is a blank board: " << std::endl;
ttt.create_board();
while (true){
std::cout << "\nPlayer X, it is your turn\n" << std::endl;
ttt.update_board(letter_x);
if (ttt.determine_winner(letter_x) == true){
break;
}
std::cout << "\nPlayer O, it is your turn\n" << std::endl;
ttt.update_board(letter_o);
if (ttt.determine_winner(letter_o) == true){
break;
}
}
}
int main() //main kicks things off by calling "run_game()"
{
run_game();
}
ticTacToe.h
#ifndef TICTACTOE_H
#define TICTACTOE_H
class ticTacToe
{
public: //Allow us to use the functions anywhere
char board[3][3]; //Creates an 2d array for the board
char player1Piece; //variable used in multiple functions
char player2Piece; //varibable used in multiple
void create_board();
void print_board(char playerPiece, int pos1 = 0, int pos2 = 0);
int check_for_overlap(int pos1, int pos2, char playerPiece);
void update_board(char playerPiece);
int determine_winner(char playerPiece);
};
#endif // TICTACTOE_H
ticTacToe.cpp
#include "ticTacToe.h"
#include <iostream>
#include <limits>
ticTacToe::ticTacToe()
{
void ticTacToe::create_board()
{
//initializes a blank board
for(int a = 0; a < 3; a++){
std::cout << "\n";
for (int b = 0; b < 3; b++){
board[a][b] = '-';
std::cout << board[a][b];
}
}
}
void ticTacToe::print_board(char playerPiece, int pos1 = 0, int pos2 = 0)
{
//prints out the updated board when called upon to do so
for(int a = 0; a < 3; a++){
std::cout << "\n";
for (int b = 0; b < 3; b++){
board[pos1][pos2] = playerPiece;
std::cout << board[a][b];
}
}
}
int ticTacToe::check_for_overlap(int pos1, int pos2, char playerPiece)
{
if (board[pos1-1][pos2-1] != '-'){
std::cout << "\nOVERLAP DETECTED!!!!!!" << std::endl;
return true;
}
return false;
}
void ticTacToe::update_board(char playerPiece)
{
//updates the board based on user input
int x, y;
std::cout << "Enter a position to place the " << playerPiece << " on the board" << std::endl;
while (true){
std::cout << "Enter row: " << std::endl;
std::cin >> x;
if (x < 1 || x > 3 || std::cin.fail()){
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
std::cout << "Your number is invalid. Try again. " << std::endl;
} else {
break;
}
}
while (true)
{
std::cout << "Enter col: " << std::endl;
std::cin >> y;
if (y < 1 || y > 3 || std::cin.fail()){
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
std::cout << "Your number is invalid. Try again. " << std::endl;
} else {
break;
}
}
if (check_for_overlap(x, y, player1Piece) == true){
x--;y--;print_board(player2Piece, x, y);
std::cout << "\nThe board has been re-set. Try again!" << std::endl;
} else if (check_for_overlap(x, y, player2Piece) == true){
x--;y--;print_board(player1Piece, x, y);
std::cout << "\nThe board has been re-set. Try again." << std::endl;
} else {
x--;y--;print_board(playerPiece, x, y);
}
}
int ticTacToe::determine_winner(char playerPiece)
{
/*slices the board and checks if playerPiece occupies that slot.
If the player makes a line, print that playerPiece has won
and exit the game.*/
if (board[0][0] == playerPiece && board[0][1] == playerPiece && board[0][2] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[1][0] == playerPiece && board[1][1] == playerPiece && board[1][2] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[2][0] == playerPiece && board[2][1] == playerPiece && board[2][2] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[0][0] == playerPiece && board[1][0] == playerPiece && board[2][0] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[0][1] == playerPiece && board[1][1] == playerPiece && board[2][1] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[0][2] == playerPiece && board[1][2] == playerPiece && board[2][2] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[0][0] == playerPiece && board[1][1] == playerPiece && board[2][2] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
}
else if(board[0][2] == playerPiece && board[1][1] == playerPiece && board[2][0] == playerPiece){
std::cout << "\nPlayer " << playerPiece << " wins!" << std::endl;
return true;
} else {
return false;
}
}
}
}
Simply remove both } at the very end of ticTacToe.cpp and
ticTacToe::ticTacToe()
{
You didn't declare any constructor in the header file.
Then there is another Problem with the function print_board.
It's declared as void print_board(char playerPiece, int pos1 = 0, int pos2 = 0) but you're using default arguments in definition, too.
Change both int pos1=0, int pos2=0 to int pos1, int pos2 in ticTacToe.cpp.
Try to overthink your code formatting to know which bracet belong to which. :)
Change this
ticTacToe::ticTacToe()
{
void ticTacToe::create_board()
{
//initializes a blank board
for(int a = 0; a < 3; a++){
std::cout << "\n";
for (int b = 0; b < 3; b++){
board[a][b] = '-';
std::cout << board[a][b];
}
}
}
to this
void ticTacToe::create_board()
{
//initializes a blank board
for(int a = 0; a < 3; a++){
std::cout << "\n";
for (int b = 0; b < 3; b++){
board[a][b] = '-';
std::cout << board[a][b];
}
}
}
Then remove from ticTacToe.cpp file the last two curly brackets in the file.
If you want to have a constructor, then you should define it inside the class, like the other functions (and then of course implement it inside .cpp).
class ticTacToe {
...
char player2Piece; //varibable used in multiple
ticTacToe(); <--- HERE
void create_board();
void print_board(char playerPiece, int pos1, int pos2); <-- Change the default arguments here
...
};
Also, in
void print_board(char playerPiece, int pos1, int pos2);
you should not pass the default arguments in the .h file (or the other way around).
The problem is here
ticTacToe::ticTacToe()
{
void ticTacToe::create_board()
{
}
// more functions
}
You have wrapped all your member functions inside your tictacToe constructor. As you are not actually doing anything in your constructor you can remove it.
Remove
ticTacToe::ticTacToe()
{
and
}
}
At the end of your cpp file.
Also do not specify default parameters to a method in the method definition (cpp file) and the method declaration (h file).
if you do
class ticTacToe
{
public: //Allow us to use the functions anywhere
...
void print_board(char playerPiece, int pos1 = 0, int pos2 = 0);
...
};
Don't then redeclare the defaults.
void ticTacToe::print_board(char playerPiece, int pos1 = 0, int pos2 = 0)
Instead declare the method
void ticTacToe::print_board(char playerPiece, int pos1, int pos2)
A final comment
check_for_overlap returns int. As you internally use bool and check for bool when you call it, you should change the method signature to
bool ticTacToe::check_for_overlap(int pos1, int pos2, char playerPiece)