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'} {}
Related
i was creating a tictactoe game and for the player vs player feature of the game I cant seem to wrap my head around getting the player symbols the correct way around.
I'm not really able to provide the minimum amount of code, as it would be my entire program, so I have grabbed the function. I belive it is something to do with the conditional operator but cant figure out what.
but some guy provided a compilable example for me :)
#include <iostream>
#include <string>
/* MOCK */
void print() {};
bool win() { return false; };
bool tie() { return false; };
void player_move() {};
void player_move2() {};
char player, player2;
std::string playerName, player2Name;
/********/
void pvp() {
while (true) {
std::cout << "Player 1 Name: ";
std::cin >> playerName;
std::cout << "Player 2 Name: ";
std::cin >> player2Name;
std::cout << "Which symbol (Player 1: X or player 2: O) goes first? ";
std::cin >> player;
if (player == 'X' || player == 'O') {
break;
}
}
player2 = player == 'O' ? 'X' : 'O';
if (player == 'O') {
player_move2();
}
print();
while (true) {
std::cout << playerName << "'s turn to make a move\n";
player_move();
print();
if (win()) {
std::cout << playerName << " wins!\n";
return;
} else if (tie()) {
std::cout << "Tie!\n";
return;
}
std::cout << player2Name << "'s turn to make a move\n";
player_move2();
print();
if (win()) {
std::cout << player2Name << " wins!\n";
return;
} else if (tie()) {
std::cout << "Tie!\n";
return;
}
}
}
int main() {
pvp();
}
EXPLANATION
There are some patterns in your code, e.g. "making a move":
std::cout << playerName << "'s turn to make a move\n";
player_move();
print();
if (win()) {
std::cout << playerName << " wins!\n";
return;
} else if (tie()) {
std::cout << "Tie!\n";
return;
}
Which is the same for player 1 and player 2, except that you call player2_move(), and display the name of player 2.
Your second loop can then be simplified as
while(true) {
// do_player1_move
// do_player2_move
}
You now come about the problem that the loop will always begin with player 1. To solve this, you're trying to do_player2_move before the loop, if player 2 shall start.
if (player == 'O') {
// do_player2_move
}
while(true) {
// do_player1_move
// do_player2_move
}
However, in your code you only call player2_move(), instead of the entire pattern "making a move" for player 2.
SOLUTION
Therefore, adjusting
if (player == 'O') {
player_move2();
}
to
if (player == 'O') {
std::cout << player2Name << "'s turn to make a move\n";
player_move2();
print();
if (win()) {
std::cout << player2Name << " wins!\n";
return;
} else if (tie()) {
std::cout << "Tie!\n";
return;
}
}
should solve your problem
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 have a board game that has spaces (has numeral values 1,2,3, etc.) starting from 1 and 16 pieces of pawns; four for each player.
I want to show the result of my board game at some point. I tried the method below but that will make my code extremely long.
i have 16 pieces and 100 spaces that i have to repeat that code with 100 space that would take forever. the code below is just for one space (the first space)
Any idea how to show my result in a short way? Thanks in advance!
Here is my old-fashioned way:
//space 1
if (bpiece1->value == 1)
{
cout << " bpiece1";
}
else if (bpiece2->value == 1)
{
cout << " bpiece2";
}
else if (bpiece3->value == 1)
{
cout << " bpiece3";
}
else if (bpiece4->value == 1)
{
cout << " bpiece4";
}
else if (gpiece1->value == 1)
{
cout << " gpiece1";
}
else if (gpiece2->value == 1)
{
cout << " gpiece2";
}
else if (gpiece3->value == 1)
{
cout << " gpiece3";
}
else if (gpiece4->value == 1)
{
cout << " gpiece4";
}
else if (ypiece1->value == 1)
{
cout << " ypiece1";
}
else if (ypiece2->value == 1)
{
cout << " ypiece2";
}
else if (ypiece3->value == 1)
{
cout << " ypiece3";
}
else if (y4->value == 1)
{
cout << " y4";
}
else if (rpiece1->value == 1)
{
cout << " rpiece1";
}
else if (rpiece2->value == 1)
{
cout << " rpiece2";
}
else if (rpiece3->value == 1)
{
cout << " rpiece3";
}
else if (rpiece4->value == 1)
{
cout << " rpiece4";
}
else
{
cout << " 01";
}
C++ is an object-oriented language. Therefore, we start by creating a class that stores your board and implements all functions on it. Like
//Board.h
#include <array>
using std::array;
enum class Figure { None, Pawn };
class Board {
private:
array<array<Figure, 8>, 8> fields; //8x8 if it was a chess board
public:
void print() const;
};
//Board.cpp
#include "Board.h"
#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
inline string to_string(const Figure figure){
switch(figure){
case Figure::None:
return " ";
case Figure::Pawn:
return "p";
}
//throw error here
return "";
}
void Board::print() const {
for(size_t i = 0; i < fields.size(); i++){
for(size_t j = 0; j < fields[i].size(); j++){
cout << to_string(fields[i][j]);
}
cout << endl;
}
cout << endl;
}
If this is new to you, you should really read the basic tutorials first and make sure that you understand each line I wrote in the end.
Important here is: Representation, represenation, representation. Don't think in "1 is a pawn", think in "a pawn is a pawn". Everything that has a function which you can think of should probably be a class, a structure or an enum.
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.
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)