C++ How to use methods of forward declared classes - c++

I'm doing a console checkers in C++. The problem is I can't refer to methods of forward-declared class.
Here's a header of Board class.
#define BOARD_H
#include "Square.h"
#include <vector>
#include <map>
class Man;
typedef std::vector<Square*> Column;
class Board
{
const int BOARD_SIZE = 8;
std::vector<Column> squares;
std::map<Location, Square*> locationSquareMap; //still kinda secret for me
public:
Board();
~Board();
//Board(Board& board);
void printBoard();
std::map<Location, Square*> getLocationSquareMap();
};
#endif
And it's implementation.
Here (printBoard()) I try to access man object via pointer, but I cannot do this because of incomplete type error.
#include "Board.h"
Board::Board()
{ //white black
for (int row = 0; row < BOARD_SIZE; row++)
{
squares.push_back(Column());
for (int column = 0; column < BOARD_SIZE; column++)
{
Location currentLocation(File(column), row);
SquareColor currentSquareColor = SquareColor::WHITE;
if ((column + row) % 2 == 0) //lol the bug was here, forgot about brackets
{
currentSquareColor = SquareColor::BLACK;
}
Square* currentSquare = new Square(currentLocation, currentSquareColor);
locationSquareMap.insert(std::make_pair(currentSquare->getLocation(), currentSquare));
squares.at(row).push_back(currentSquare);
}
}
}
Board::~Board()
{
}
void Board::printBoard()
{
for (int i = squares.size() - 1; i != -1; i--)
{
for (int g = squares.at(i).size() - 1; g != -1; g--)
{
std::cout << *(squares.at(i).at(g)) << std::endl;
}
}
std::cout << " ";
for (int i = 0; i < BOARD_SIZE; i++)
{
switch (File(i))
{
case File::A : std::cout << "A "; break;
case File::B : std::cout << "B "; break;
case File::C : std::cout << "C "; break;
case File::D : std::cout << "D "; break;
case File::E : std::cout << "E "; break;
case File::F : std::cout << "F "; break;
case File::G : std::cout << "G "; break;
case File::H : std::cout << "H "; break;
default: std::cout << " "; break;
}
}
std::cout << std::endl << std::endl;
for (int i = squares.size() - 1; i != -1; i--)
{
std::cout << i << " ";
for(int g = 0; g < squares.at(i).size(); g++)
{
Man* currentMan;
if (squares.at(i).at(g)->getIsOccupied())
{
currentMan = squares.at(i).at(g)->getCurrentMan();
//currentMan-> can't refer to methods
}
else
{
std::cout << "_ ";
}
}
std::cout << std::endl;
}
}
std::map<Location, Square*> Board::getLocationSquareMap()
{
return locationSquareMap;
}
Man's header:
#ifndef MAN_H
#define MAN_H
#include "ManColorEnum.cpp"
#include "Square.h"
#include <iostream>
#include <string>
#include <vector>
#include "LocationFactory.h"
#include "Board.h"
class Man
{
ManColor color;
Square* currentSquare;
bool isKing;
public:
Man(ManColor color, Square* square);
~Man();
//Man(Man& man);
Square* getCurrentSquare();
void setCurrentSquare(Square* square);
bool getIsKing();
void setIsKing();
ManColor getColor();
void makeMove(Square* square);
std::vector<Location> getValidMoves(Board* board);
friend std::ostream& operator<<(std::ostream& ostream, const Man& man);
};
#endif
Man's .cpp file:
#include "Man.h"
Man::Man(ManColor color, Square* square)
{
this->color = color;
this->currentSquare = square;
this->isKing = false;
}
Man::~Man()
{
//dtor
}
ManColor Man::getColor()
{
return color;
}
std::vector<Location> Man::getValidMoves(Board* board)
{
std::vector<Location> moveCandidates{};
if (!isKing)
{
Location currentLocation = this->currentSquare->getLocation();
std::map<Location, Square*> squareMap = board->getLocationSquareMap();
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, 1, 1)); //move one right forward
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, -1, 1)); //move one left forward
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, 2, 2)); //capture forward right
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, -2, 2)); //capture forward left
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, 2, -2)); //capture backwards right
moveCandidates.push_back(LocationFactory::createLocation(currentLocation, -2, -2)); //capture backwards left
//TODO have to capture
for (int i = 0; i < moveCandidates.size(); i++)
{
//here I filter for moves to exist on the board
if (squareMap.count(moveCandidates.at(i)) == 0)
{
moveCandidates.erase(moveCandidates.begin() + i);
}
//here I filter occupied squares
if (squareMap[moveCandidates.at(i)]->getIsOccupied())
{
moveCandidates.erase(moveCandidates.begin() + i);
}
//here I filter capture moves
File currentFile = moveCandidates.at(i).getFile();
int currentRank = moveCandidates.at(i).getRank();
Square* preSquare = nullptr;
for (std::map<Location, Square*>::iterator it = squareMap.begin(); it != squareMap.end(); it++)
{
//check capture forward right
if (int(it->first.getFile()) == int(currentFile) + 2 && it->first.getRank() == currentRank + 2)
{
for (std::map<Location, Square*>::iterator itr = squareMap.begin(); itr != squareMap.end(); itr++)
{
if (int(itr->first.getFile()) == int(currentFile) + 1 && itr->first.getRank() == currentRank + 1)
{
preSquare = itr->second;
break; //check to be careful here
}
}
//if (it->second->getIsOccupied()
// || (preSquare->getIsOccupied() && preSquare->getCurrentMan()->color == color)
// || (!it->second->getIsOccupied() && !preSquare->getIsOccupied()))
//{
// moveCandidates.erase(moveCandidates.begin() + i);
// break; //check to be careful here
//}
}
//check capture backward right
else if (int(it->first.getFile()) == int(currentFile) + 2 && it->first.getRank() == currentRank - 2)
{
for (std::map<Location, Square*>::iterator itr = squareMap.begin(); itr != squareMap.end(); itr++)
{
if (int(itr->first.getFile()) == int(currentFile) + 1 && itr->first.getRank() == currentRank - 1)
{
preSquare = itr->second;
break;
}
}
}
//check capture forward left
else if (int(it->first.getFile()) == int(currentFile) -2 && it->first.getRank() == currentRank + 2)
{
for (std::map<Location, Square*>::iterator itr = squareMap.begin(); itr != squareMap.end(); itr++)
{
if (int(itr->first.getFile()) == int(currentFile) - 1 && itr->first.getRank() == currentRank + 1)
{
preSquare = itr->second;
break;
}
}
}
//check capture backwards left
else if (int(it->first.getFile()) == int(currentFile) - 2 && it->first.getRank() == currentRank - 2)
{
for (std::map<Location, Square*>::iterator itr = squareMap.begin(); itr != squareMap.end(); itr++)
{
if (int(itr->first.getFile()) == int(currentFile) - 1 && itr->first.getRank() == currentRank - 1)
{
preSquare = itr->second;
break;
}
}
}
if (it->second->getIsOccupied()
|| (preSquare->getIsOccupied() && preSquare->getCurrentMan()->color == color)
|| (!it->second->getIsOccupied() && !preSquare->getIsOccupied()))
{
moveCandidates.erase(moveCandidates.begin() + i);
break; //check to be careful here
}
}
}
}
return moveCandidates;
}
Square* Man::getCurrentSquare()
{
return currentSquare;
}
void Man::setCurrentSquare(Square* square)
{
this->currentSquare = square;
}
bool Man::getIsKing()
{
return isKing;
}
void Man::setIsKing()
{
isKing = true;
}
void Man::makeMove(Square* square)
{
this->currentSquare->reset();
this->currentSquare = square;
}
std::ostream& operator<<(std::ostream& ostream, const Man& man)
{
std::string colorStr;
switch (man.color)
{
case ManColor::BLACK: colorStr = "BLACK"; break;
case ManColor::WHITE: colorStr = "WHITE"; break;
default: colorStr = "COLOR";
}
return std::cout << "Man { color=" << colorStr << " } " << std::endl;
}

Put forward class declarations in header files and include headers in source files.

Related

How would I fix this whitespace from appearing on the sides whenever I am showing the snakes length?

Whenever I run my program I check to see if I would place down 3 os it goes to the right. I know that the problem is that I have a bunch of if statements that cycle through, but I have a for loop there to place down the snakes trail. I know that all those ifs aren't good.
I tried changing in the top of the for loop to be a if statement that was always true, it didn't work nothing did. I am confused on how to check for all of the coordinates, but still not have the walls pop up on the sides.
I am a begginer, so don't hate on my code that much.
snake.cpp
#include <iostream>
#include <conio.h>
#include <random>
#include <time.h>
#include "snake.hpp"
void endGame(int score);
const int KEY_ARROW_CHAR1 = 224;
const int KEY_ARROW_UP = 72;
const int KEY_ARROW_DOWN = 80;
const int KEY_ARROW_LEFT = 75;
const int KEY_ARROW_RIGHT = 77;
void snake::input() {
// checks for arrow key input
if (_kbhit()) {
//stores keycode
int key = _getch();
//checks if key is arrow key
if (key == KEY_ARROW_CHAR1) {
//stores arrow key
key = _getch();
//checks if arrow key is up
if (key == KEY_ARROW_UP) {
direction = '^';
}
//checks if arrow key is down
else if (key == KEY_ARROW_DOWN) {
direction = 'v';
}
//checks if arrow key is left
else if (key == KEY_ARROW_LEFT) {
direction = '<';
}
//checks if arrow key is right
else if(key == KEY_ARROW_RIGHT) {
direction = '>';
}
}
}
switch (direction) {
case '^':
snakeCoords[2]--;
break;
case 'v':
snakeCoords[2]++;
break;
case '>':
snakeCoords[0]++;
break;
case '<':
snakeCoords[0]--;
}
checkForObjects();
}
bool snake::checkForObjects() {
if ((snakeCoords[0] == 40 || snakeCoords[0] == 0) || (snakeCoords[2] == 20 || snakeCoords[2] == 0)) {
endGame(score);
}
if (snakeCoords[0] == fruitCoords[0] && snakeCoords[2] == fruitCoords[2]) {
score++;
getFruitLoc();
return true;
}
return false;
}
void snake::getFruitLoc() {
srand(time(0));
fruitCoords[0] = rand() % 39;
fruitCoords[2] = rand() % 19;
}
void endGame(int score) {
std::cout << "you died, your score was " << score;
exit(0);
}
```
#include <iostream>
#include <conio.h>
#include <random>
#include "snake.hpp"
#include <vector>
void createArena(char direction);
//Coordinates for snake
std::vector <std::vector<int>> previousCoords{
{14, 10},
{13, 10},
{12, 10}
};
snake coordManager{};
int score{0};
int main()
{
//make terminal green
system("color 0a");
while (true) {
std::cout << "\t" << score;
//pushes ascii arena down
for (size_t i{}; i <= 5; i++) {
std::cout << std::endl;
}
score = coordManager.score;
//updates snake based on coordinates
createArena(coordManager.direction);
//manages all snake movements
coordManager.input();
//reminder this clears the screan
system("CLS");
}
}
void createArena(char direction) {
//offsets screen
std::cout << "\t\t\t\t";
for (size_t y{}; y <= 20; y++) {
for (size_t x{}; x <= 40; x++) {
//checks if it hits the snakes coordinates
for (size_t i{}; i < previousCoords.size();) {
if (x == previousCoords.at(i).at(0) && y == previousCoords.at(i).at(1)) {
std::cout << "O";
}
i++;
}
if (coordManager.snakeCoords[0] == x && coordManager.snakeCoords[2] == y) {
std::cout << direction;
}
else if (x == 0 || x == 40) {
std::cout << '|';
}
else if (y == 0 || y == 20) {
std::cout << '-';
}
else if(coordManager.fruitCoords[0] == x && coordManager.fruitCoords[2] == y) {
std::cout << "F";
}
else {
std::cout << " ";
}
}
//offsets again
std::cout << std::endl << "\t\t\t\t";
}
}
#include <conio.h>
#include <random>
#include <time.h>
class snake {
public:
void input();
bool checkForObjects();
int score{};
int snakeCoords[2]{
/* X */ 15,
/* Y */ 10
};
int fruitCoords[2]{
/* X */ rand() % 39,
/* Y */ rand() % 19
};
char direction{'O'};
private:
void getFruitLoc();
};
https://i.stack.imgur.com/bdSNf.png
I got it working, I used a boolean that I would change if it was different from whitespace. it was a simple fix sorry.

While Overloading The << Operator Was It Correctly Formatted?

I have been getting outputs and sometimes even getting the complete output, however I don't quite understand why I'd be getting said outputs. I want to believe it has something to do with my overloading of said operator "<<" when I perform the operation of outputting the information in the "OpenSea" object. Any leads would be tremendously helpful and thank you for your time!
Note: I included only the necessary files but will update if you think you need more to understand the full scope of my situation. Also there is no need to give me tips on how to format my code as I know a lot of it can be reworked for optimization.
main.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
using namespace std;
int main ()
{
srand (time (NULL));
// Simulation
Sea OpenSea (17, 17);
cout << OpenSea;
}
aquaClasses.h <-- "main" header file
#ifndef AQUACLASSES_H
#define AQUACLASSES_H
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <iomanip>
// Constants
const short int AMT_FISH = 200;
const short int AMT_KWHALES = 2;
const short int AMT_PENGS = 50;
const short int MAX_SIM_INTERATIONS = 10000;
const short int MAX_SEA_GRID = 25;
const short int MAX_SEA_SIZE = 625;
// Functions
template <typename TYPE> int calculate_distance (int obj1_x, int obj1_y,
TYPE obj2);
template <typename TYPE> int calculate_direction (int obj1_x, int obj1_y,
TYPE obj2);
#endif
aquaSea.h
#ifndef AQUASEA_H
#define AQUASEA_H
// Forward Declarations to circumvent circular dependency
class Fish;
class Penguin;
class Killer_Whale;
class Sea
{
private:
char m_grid [MAX_SEA_GRID][MAX_SEA_GRID];
int m_fish;
int m_kwhales;
int m_pengs;
int m_size;
int m_height;
int m_width;
void clear ();
void populate ();
public:
Sea (const int grid_size_height, const int grid_size_width);
friend std::ostream &operator<<(std::ostream &os, Sea obj);
int getHeight () const {return m_height;};
int getWidth () const {return m_width;};
void setCell (int obj_x, int obj_y, char cell_symbol);
// Appropriate accessor/mutator functions
};
#endif
aquaSea.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaPenguin.h"
#include "aquaKillerWhale.h"
#include "aquaSea.h"
using namespace std;
// - [row][column]
Sea::Sea (const int grid_size_height, const int grid_size_width)
{
m_fish = 200;
m_kwhales = 2;
m_pengs = 50;
if ((grid_size_height || grid_size_width) <= 0)
{
if (grid_size_height <= 0 && grid_size_width > 0)
{
m_size = MAX_SEA_GRID * grid_size_width;
m_width = grid_size_width;
m_height = MAX_SEA_GRID;
}
else if (grid_size_width <= 0 && grid_size_height > 0)
{
m_size = MAX_SEA_GRID * grid_size_height;
m_width = MAX_SEA_GRID;
m_height = grid_size_height;
}
else if (grid_size_height <= 0 && grid_size_width <= 0)
{
m_size = MAX_SEA_GRID * MAX_SEA_GRID;
m_height = MAX_SEA_GRID;
m_width = MAX_SEA_GRID;
}
}
else
{
m_size = grid_size_height * grid_size_width;
m_height = grid_size_height;
m_width = grid_size_width;
}
clear ();
populate ();
}
ostream &operator<<(ostream &os, Sea obj)
{
os << "Sea Height: " << obj.m_width << endl << "Sea Wdith: "
<< obj.m_width << endl << "Sea Size: " << obj.m_size
<< endl;
os << "Grid View: " << endl;
for (int i = 0; i < obj.m_height; i++)
{
for (int j = 0; j < obj.m_width; j++)
{
os << obj.m_grid [i][j];
}
os << endl;
}
return os;
}
void Sea::clear ()
{
for (int i = 0; i < m_height; i++)
{
for (int j = 0; j < m_width; j++)
{
m_grid[i][j] = 'O';
}
}
return;
}
void Sea::populate ()
{
// Special simluation variables
bool applyFish = true;
bool applyKWhales = false;
bool applyPengs = false;
int amtFishPop = 35;
int amtKWhalesPop = 2;
int amtPengPop = 20;
int index = 0;
int randGridRow = 0;
int randGridCol = 0;
int totalPop = amtFishPop + amtKWhalesPop + amtPengPop;
Fish arr_fish [AMT_FISH];
Killer_Whale arr_kwhales [AMT_KWHALES];
Penguin arr_pengs [AMT_PENGS];
for (int i = 0; i < totalPop; i++)
{
// Grab random place on grid to apply and check if grid plot is open
randGridRow = rand () % 16;
randGridCol = rand () % 16;
while (m_grid [randGridRow][randGridCol] != 'O')
{
randGridRow = rand () % 16;
randGridCol = rand () % 16;
}
// Populate and Update Fish
if (amtFishPop > 0 && applyFish == true)
{
arr_fish[index].setX (randGridCol);
arr_fish[index].setY (randGridRow);
setCell (arr_fish[index].getX (), arr_fish[index].getY (), 'F');
amtFishPop--;
index++;
}
else if (amtFishPop == 0)
{
applyFish = false;
applyKWhales = true;
index = 0;
}
// Populate and Update Killer Whales
if (amtKWhalesPop > 0 && applyKWhales == true)
{
arr_kwhales[index].setX (randGridCol);
arr_kwhales[index].setY (randGridRow);
setCell (arr_kwhales[index].getX (), arr_kwhales[index].getY (), 'K');
amtKWhalesPop--;
index++;
}
else if (amtKWhalesPop == 0)
{
applyKWhales = false;
applyPengs = true;
index = 0;
}
// Populate and Update Penguins
if (amtPengPop > 0 && applyPengs == true)
{
arr_pengs[index].setX (randGridCol);
arr_pengs[index].setY (randGridRow);
setCell (arr_pengs[index].getX (), arr_pengs[index].getY (), 'P');
amtPengPop--;
index++;
}
else if (amtPengPop == 0)
{
applyPengs = false;
index = 0;
}
}
return;
}
void Sea::setCell (int obj_x, int obj_y, char cell_symbol)
{
m_grid [obj_x][obj_y] = cell_symbol;
return;
}
Types of Output
Wanted:
- Image
Unwanted:
- Image
STOP! AFTER THIS POINT IS OPTIONAL CODE TO FURTHER UNDERSTAND THE SITUATION
Other Code Of Reference If You Want But I Don't Think It's Needed
aquaFish.h
#ifndef AQUAFISH_H
#define AQUAFISH_H
class Fish
{
private:
int m_fish_amt_food;
int m_fish_x;
int m_fish_y;
bool m_fish_alive;
public:
Fish ();
int getX () const {return m_fish_x;};
int getY () const {return m_fish_y;};
void setX (int new_x) {m_fish_x = new_x;};
void setY (int new_y) {m_fish_y = new_y;};
int getFishAmtFood () const {return m_fish_amt_food;};
void move ();
};
#endif
aquaFish.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
using namespace std;
Fish::Fish ()
{
int randNum = rand () % 10 + 1;
m_fish_amt_food = randNum;
m_fish_x = -1;
m_fish_y = -1;
}
void Fish::move ()
{
int randDir = rand () % 8 + 1;
if (randDir == 1)
{
m_fish_y++;
}
else if (randDir == 2)
{
m_fish_x++;
m_fish_y++;
}
else if (randDir == 3)
{
m_fish_x++;
}
else if (randDir == 4)
{
m_fish_x++;
m_fish_y--;
}
else if (randDir == 5)
{
m_fish_y--;
}
else if (randDir == 6)
{
m_fish_x--;
m_fish_y--;
}
else if (randDir == 7)
{
m_fish_x--;
}
else if (randDir == 8)
{
m_fish_x--;
m_fish_y++;
}
return;
}
aquaPenguin.h
#ifndef AQUAPENGUIN_H
#define AQUAPENGUIN_H
// Forward Declarations to circumvent circular dependancy
class Sea;
class Fish;
class Killer_Whale;
class Penguin
{
private:
int m_peng_health; // 0-100
int m_peng_x;
int m_peng_y;
bool m_peng_alive;
public:
Penguin ();
int getX () const {return m_peng_x;};
int getY () const {return m_peng_y;};
void setX (int new_x) {m_peng_x = new_x;};
void setY (int new_y) {m_peng_y = new_y;};
void move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size);
};
#endif
aquaPenguin.cpp
#include "aquaClasses.h"
#include "aquaFish.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
#include "aquaSea.h"
#include "aquaFunctions.cpp"
using namespace std;
Penguin::Penguin ()
{
m_peng_health = rand () % (81 - 60) + 60;
m_peng_x = -1;
m_peng_y = -1;
m_peng_alive = false;
}
void Penguin::move (Sea obj_sea, Fish arr_fish [], int arr_fish_size,
Killer_Whale arr_kwhale [], int arr_kwhale_size)
{
int actuDistToFish = 8;
int currDistToFish = 0;
int tempMoveX = 0;
int tempMoveY = 0;
int amtMove = 0;
int direction = 0;
int fishIndex = 0;
bool moveAwayKillerWhale = false;
bool fishInRange = false;
// Determine amount of cells to move in sea
if (m_peng_health >= 81 && m_peng_health <= 100)
{
amtMove = 5;
}
else if (m_peng_health >= 61 && m_peng_health <= 80)
{
amtMove = 4;
}
else if (m_peng_health >= 41 && m_peng_health <= 60)
{
amtMove = 3;
}
else if (m_peng_health >= 21 && m_peng_health <= 40)
{
amtMove = 2;
}
else if (m_peng_health >= 1 && m_peng_health <= 20)
{
amtMove = 1;
}
else
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
// ADD: Find if any killer whales are near first and if so then penguin just moves away
// Find if any fish are near <-- THIS IS WRONG, YOU NEED TO FIND THE CLOSEST FISH
for (int i = 0; i < arr_fish_size; i++)
{
currDistToFish = calculate_distance (m_peng_x, m_peng_y,
arr_fish[i]);
if (currDistToFish <= 8)
{
if (currDistToFish < actuDistToFish)
{
actuDistToFish = currDistToFish;
fishIndex = i;
fishInRange = true;
}
}
}
// ADD: If fish and whale are found do something, we decide. Otherwise move randomly Peng See Dist 8.0
// ADD Move 1 tick then gauge situation again
for (int k = 0; k < amtMove; k++)
{
if (fishInRange == true && moveAwayKillerWhale == false)
{
tempMoveX = m_peng_x; // temp used for storing before changing
tempMoveY = m_peng_y; // temp used for storing before changing
direction = calculate_direction (m_peng_x, m_peng_y,
arr_fish[fishIndex]);
cout << "Penguin pos before moving: " << m_peng_x << ","
<< m_peng_y << endl;
cout << "Closest Fish pos: " << arr_fish[fishIndex].getX () << ","
<< arr_fish[fishIndex].getY () << endl;
if (m_peng_health == 0)
{
cout << "Chicken of the sea at: " << m_peng_x << " " << m_peng_y
<< endl;
return;
}
if (direction == 1)
{
actuDistToFish--;
m_peng_health--;
tempMoveY++;
}
else if (direction == 2)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY++;
}
else if (direction == 3)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
}
else if (direction == 4)
{
actuDistToFish--;
m_peng_health--;
tempMoveX++;
tempMoveY--;
}
else if (direction == 5)
{
actuDistToFish--;
m_peng_health--;
tempMoveY--;
}
else if (direction == 6)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY--;
}
else if (direction == 7)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
}
else if (direction == 8)
{
actuDistToFish--;
m_peng_health--;
tempMoveX--;
tempMoveY++;
}
else
{
cout << "[ERROR]: Penguin direction messed up." << endl;
}
// MODIFY: Lastly check if out of bounds and then move peng
if (tempMoveX > obj_sea.getWidth ()
|| tempMoveX < -(obj_sea.getWidth ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else if (tempMoveY > obj_sea.getHeight ()
|| tempMoveY < -(obj_sea.getHeight ()))
{
m_peng_x = m_peng_x; // AKA dont move
m_peng_y = m_peng_y;
}
else
{
obj_sea.setCell (m_peng_x, m_peng_y, 'O'); // Delete old cell
m_peng_x = tempMoveX;
m_peng_y = tempMoveY;
obj_sea.setCell (m_peng_x, m_peng_y, 'P'); // Set new cell
}
// Check if peng eats after moving
if (actuDistToFish == 0)
{
// Stop moving
amtMove = 0;
// Eat fish
m_peng_health += arr_fish[fishIndex].getFishAmtFood ();
// ADD: Remove fish from grid
}
cout << "Penguin pos after moving: " << m_peng_x << ","
<< m_peng_y << endl;
}
else if (fishInRange == false && moveAwayKillerWhale == true)
{
}
else if (fishInRange == false && moveAwayKillerWhale == false)
{
// If no fish, movement is random, else it's towards fish how ever many
// step the penguin can go
direction = rand () % 8 + 1;
if (direction == 1)
{
m_peng_y++;
}
else if (direction == 2)
{
m_peng_x++;
m_peng_y++;
}
else if (direction == 3)
{
m_peng_x++;
}
else if (direction == 4)
{
m_peng_x++;
m_peng_y--;
}
else if (direction == 5)
{
m_peng_y--;
}
else if (direction == 6)
{
m_peng_x--;
m_peng_y--;
}
else if (direction == 7)
{
m_peng_x--;
}
else if (direction == 8)
{
m_peng_x--;
m_peng_y++;
}
else
{
cout << "[ERROR]: Penguin random direction messed up." << endl;
}
}
}
return;
}
aquaKillerWhale.h
#ifndef AQUAKILLERWHALE_H
#define AQUAKILLERWHALE_H
class Penguin;
class Killer_Whale
{
private:
int m_kwhale_amt_pengs;
int m_kwhale_x;
int m_kwhale_y;
public:
Killer_Whale ();
int getX () const {return m_kwhale_x;};
int getY () const {return m_kwhale_y;};
void setX (int new_x) {m_kwhale_x = new_x;};
void setY (int new_y) {m_kwhale_y = new_y;};
void move (Penguin arr_peng []);
};
#endif
aquaKillerWhale.cpp
#include "aquaClasses.h"
#include "aquaKillerWhale.h"
#include "aquaPenguin.h"
using namespace std;
Killer_Whale::Killer_Whale ()
{
m_kwhale_x = -1;
m_kwhale_y = -1;
}
void Killer_Whale::move (Penguin arr_peng [])
{
return;
}
aquaFunctions.cpp
#include "aquaClasses.h"
using namespace std;
// Functions
template <typename TYPE>
int calculate_direction (int obj1_x, int obj1_y, TYPE obj2)
{
int calculatedX = obj2.getX () - obj1_x;
int calculatedY = obj2.getY () - obj1_y;
int direction = 0;
if (calculatedX == 0 && calculatedY > 0)
{
direction = 1;
}
else if (calculatedX > 0 && calculatedY > 0)
{
direction = 2;
}
else if (calculatedX > 0 && calculatedY == 0)
{
direction = 3;
}
else if (calculatedX > 0 && calculatedY < 0)
{
direction = 4;
}
else if (calculatedX == 0 && calculatedY < 0)
{
direction = 5;
}
else if (calculatedX < 0 && calculatedY < 0)
{
direction = 6;
}
else if (calculatedX < 0 && calculatedY == 0)
{
direction = 7;
}
else if (calculatedX < 0 && calculatedY > 0)
{
direction = 8;
}
else
{
cout << "[ERROR]: Direction calculation failed." << endl;
}
return direction;
}
template <typename TYPE>
int calculate_distance (int obj1_x, int obj1_y, TYPE obj2)
{
int distance = sqrt ((obj1_x - obj2.getX ())
* (obj1_x - obj2.getX ())
+ (obj1_y - obj2.getY ())
* (obj1_y - obj2.getY ()));
return distance;
}

I am having an issue with my AI trying to delete the card that it just played?

I am making a card game, Crazy Eights, I have everything done except I am having a problem with this AI. The AI needs to delete the card it just played from its card options. (Each player is dealt 5 cards, and if the card matches the suit, value, or an 8, it can play). SO far, the computer does play the correct card, it just doesn't remove the card so it can just keep playing and playing.
Main Function
#include <iostream>
#include <time.h>
#include "CCrazyEight.h"
#include "stdafx.h"
using namespace std;
void main()
{
// Calls Crazy eight and declares a variable, then runs the game
CCrazyEight E1;
E1.Menu();
}
CCard Header File
#pragma once
#include <iostream>
#include <time.h>
#include "stdafx.h"
using namespace std;
enum CardSuit { Hearts, Diamonds, Spades, Clubs };
class CCard
{
friend ostream & operator << (ostream &left, CCard right);
private:
int value;
CardSuit suit;
public:
// Constructor, sets default values to suit and value
CCard()
{
value = 1;
suit = Hearts;
}
// return thes value of the card
int GetValue()
{
return value;
}
// returns the suit of the card
CardSuit GetSuit()
{
return suit;
}
// Passes values to CDeck constructor, which then randomizes values for the cards
void InitCard(CardSuit s, int v)
{
suit = s;
if (v > 0 && v < 14)
{
value = v;
}
}
};
// outputs value and suit of the card
ostream & operator << (ostream &left, CCard right)
{
if (right.value < 11 && right.value > 1)
{
left << right.value;
}
else if (right.value == 1)
{
left << "Ace";
}
else if (right.value == 11)
{
left << "Jack";
}
else if (right.value == 12)
{
left << "Queen";
}
else if (right.value == 13)
{
left << "King";
}
left << " of ";
if (right.suit == Hearts)
{
left << "Hearts";
}
else if (right.suit == Diamonds)
{
left << "Diamonds";
}
else if (right.suit == Spades)
{
left << "Spades";
}
else if (right.suit == Clubs)
{
left << "Clubs";
}
return left;
}
CDeck Header File
#pragma once
#include <iostream>
#include "CCard.h"
#include <time.h>
using namespace std;
class CDeck
{
private:
CCard Deck[52];
int TopCard;
public:
// constructor
// randomizes the card numbers for suit and value
CDeck()
{
srand(time(NULL));
TopCard = 0;
for (int suit = 0; suit < 4; suit++)
{
for (int value = 1; value <= 13; value++)
{
Deck[((suit * 13) + value) - 1].InitCard((CardSuit)suit, value);
}
}
}
// shuffles the deck, completely randomizes the cards
void Shuffle()
{
TopCard = 0;
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 52; x++)
{
int SwapPosition = rand() % 52;
CCard temp;
temp = Deck[x];
Deck[x] = Deck[SwapPosition];
Deck[SwapPosition] = temp;
}
}
}
// Draw a card function that gives out a card when called for in crazy eight
CCard DrawCard()
{
if (TopCard > 51)
{
cout << "Deck is Empty." << endl;
}
else
{
return Deck[TopCard++];
}
}
};
CrazyEight header file
#pragma once
#include <iostream>
#include <time.h>
#include "CCard.h"
#include "CDeck.h"
#include "CPlayer.h"
using namespace std;
// Having an issue trying to get the computer to play something different
class CCrazyEight
{
private:
CDeck d1;
CCard c1;
int index;
CCard Topcard;
CPlayer Computer;
CPlayer Human;
public:
// constructor
// shuffles the deck to the played, and assigns the topcard to start the game
CCrazyEight()
{
d1.Shuffle();
c1 = d1.DrawCard();
Topcard = c1;
}
// plays the game, dealing cards to computer and human
void PlayGame()
{
cout << "Welcome to Crazy Eight!" << endl;
cout << "You get to go first!" << endl;
cout << endl;
for (int k = 0; k < 5; k++)
{
Computer.GetCard(d1.DrawCard());
Human.GetCard(d1.DrawCard());
}
}
// displays the topmost card
void TopCard()
{
cout << Topcard << endl;
}
// displays the cards for the human, and the options they can chose, and anything else they need about the game
void Menu()
{
PlayGame();
while (Human.NumCards() != 0 || Computer.NumCards() != 0)
{
cout << endl;
cout << "Top Card is: "; TopCard();
cout << endl;
cout << "You Have " << Human.NumCards() << " Cards Left." << endl;
cout << "Your play: " << endl;
cout << "0) Draw Card" << endl;
cout << Human << endl;
cin >> index;
if (index == 0)
{
Human.GetCard(d1.DrawCard());
Topcard = Topcard;
}
else if (index > 0 && index <= Human.NumCards())
{
Topcard = Human.CardPlayed(index, Topcard);
}
cout << endl;
Topcard = Computer.ComputerAI(Topcard);
cout << "Computer Played: " << Topcard << endl;
if (Computer.NumCards() > 0)
{
cout << "Computer has " << Computer.NumCards() << " Cards Left." << endl;
}
else
cout << "You Lose!" << endl;
}
}
};
CPlayer Header File
#pragma once
#include "CCard.h"
#include <time.h>
#include <iostream>
using namespace std;
class CPlayer
{
friend ostream & operator << (ostream &left, CPlayer right);
private:
CCard Hand[25];
CDeck d1;
int NumberOfCard;
bool Computer;
const int MaxHand = 26;
bool TopCard;
public:
// Constructor for the computer, sets computer to true
CPlayer(bool computer = true)
{
Computer = computer;
NumberOfCard = 0;
}
// Computers AI, checks and sees if they can play, if not then they draw until they can play, or they play a card that is playable******Easy mode**** Lol
CCard ComputerAI(CCard Topcard)
{
for (int i = 0; i < NumberOfCard; i++)
{
if (Hand[i].GetSuit() == Topcard.GetSuit() || Hand[i].GetValue() == 8 || Hand[i].GetValue() == Topcard.GetValue())
{
for (int i = 0; i < NumberOfCard; i++)
{
if (Topcard.GetSuit() == Hand[i].GetSuit() && Hand[i].GetValue() != 8)
{
NumberOfCard--;
return Hand[i];
}
}
for (int i = 0; i < NumberOfCard; i++)
{
if (Topcard.GetValue() == Hand[i].GetValue() && Hand[i].GetValue() != 8)
{
NumberOfCard--;
return Hand[i];
}
}
for (int i = 0; i < NumberOfCard; i++)
{
if (Hand[i].GetValue() == 8)
{
NumberOfCard--;
return Hand[i];
}
}
}
else
{
GetCard(d1.DrawCard());
}
}
}
// Is not the computer, sets computer to fasle. i.e. its the human
void Human()
{
Computer = false;
}
int NumCards()
{
return NumberOfCard;
}
// will hand out a card
bool GetCard(CCard NewCard)
{
if (NumberOfCard < MaxHand)
{
// Now is taking the card
Hand[NumberOfCard] = NewCard;
NumberOfCard++;
return true;
}
else
return false;
}
// subtracts the card that was played from the deck of the human user
CCard CardPlayed(int index, CCard Topcard)
{
if (CheckCard(index, Topcard) == true)
{
CCard TempTopcard = Hand[index - 1];
for (int i = index - 1; i <= NumberOfCard - 1; i++)
{
Hand[i] = Hand[i + 1];
}
NumberOfCard--;
return TempTopcard;
}
else
cout << "Not a valid Card." << endl;
return Topcard;
}
// checks the card and see's if it is playable or not
bool CheckCard(int index, CCard Topcard)
{
if (Hand[index - 1].GetSuit() == Topcard.GetSuit() || Hand[index - 1].GetValue() == 8 || Hand[index - 1].GetValue() == Topcard.GetValue())
{
return true;
}
else
return false;
}
};
// overloads the output to cout the card
ostream & operator << (ostream &left, CPlayer right)
{
for (int i = 0; i < right.NumberOfCard; i++)
{
left << i + 1 << ") " << right.Hand[i] << endl;
}
return left;
}

FileManager isn't working properly

I've been following some tutorials for allegro 5 and Im trying to load a tile map and I keep getting a vector subscript out of range error. I've been trying for so long to get this fixed but I cannot figure it out. The filemanager is supposed to read from a map.txt then go through layer.cpp then actually make the map.
EDIT:
It stops after the 5th loop of contents[i][j]
FileManager.CPP
#include "FileManager.h"
FileManager::FileManager()
{
identifierFound = false;
}
FileManager::~FileManager()
{
}
void FileManager::LoadContent(const char *filename, std::vector<std::vector<std::string>> &attributes, std::vector<std::vector<std::string>> &contents)
{
std::ifstream openFile(filename);
std::string line, newLine;
if(openFile.is_open())
{
while(std::getline(openFile, line))
{
std::stringstream str;
if(line.find("Load=") != std::string::npos)
{
type = LoadType::Attributes;
line = line.erase(0, line.find("=") + 1);
tempAttributes.clear();
}
else
{
type = LoadType::Contents;
tempContents.clear();
}
str << line;
while(std::getline(str, newLine, ']'))
{
newLine.erase(std::remove(newLine.begin(), newLine.end(), '['), newLine.end());
std::string erase = " \t\n\r";
newLine.erase(newLine.find_last_not_of(erase) + 1);
if(type == LoadType::Attributes)
tempAttributes.push_back(newLine);
else
tempContents.push_back(newLine);
std::cout << newLine << std::endl;
}
if(type == LoadType::Contents && tempContents.size() > 0)
{
attributes.push_back(tempAttributes);
contents.push_back(tempContents);
}
}
}
else
{
}
}
void FileManager::LoadContent(const char *filename, std::vector<std::vector<std::string>> &attributes, std::vector<std::vector<std::string>> &contents, std::string identifier)
{
std::ifstream openFile(filename);
std::string line, newLine;
if(openFile.is_open())
{
while(std::getline(openFile, line))
{
std::stringstream str;
if(line.find("EndLoad=") != std::string::npos && line.find(identifier) != std::string::npos)
{
identifierFound = false;
break;
}
else if(line.find("Load=") != std::string::npos && line.find(identifier) != std::string::npos)
{
identifierFound = true;
}
if(identifierFound)
{
if(line.find("Load=") != std::string::npos)
{
type = LoadType::Attributes;
line = line.erase(0, line.find("=") + 1);
tempAttributes.clear();
}
else
{
type = LoadType::Contents;
tempContents.clear();
}
str << line;
while(std::getline(str, newLine, ']'))
{
newLine.erase(std::remove(newLine.begin(), newLine.end(), '['), newLine.end());
std::string erase = " \t\n\r";
newLine.erase(newLine.find_last_not_of(erase) + 1);
if(type == LoadType::Attributes)
tempAttributes.push_back(newLine);
else
tempContents.push_back(newLine);
std::cout << newLine << std::endl;
}
if(type == LoadType::Contents && tempContents.size() > 0)
{
attributes.push_back(tempAttributes);
contents.push_back(tempContents);
}
}
}
}
else
{
std::cout << "Error reading file!" << std::endl;
}
}
Layer.CPP
#include "Layer.h"
Layer::Layer(void)
{
}
Layer::~Layer(void)
{
}
std::pair<int, int> Layer::SetTiles(std::string tileString)
{
std::pair<int, int> tile;
tile.first = atoi(tileString.substr(0, tileString.find(',')).c_str());
tile.second = atoi(tileString.substr(tileString.find(',') + 1).c_str());
return tile;
}
void Layer::LoadContent(std::string layerID, std::string mapID)
{
std::string fileName = "Maps/"+mapID+".txt";
fileManager.LoadContent(fileName.c_str(), attributes, contents, layerID);
int indexY = 0;
for(int i = 0; i < attributes.size(); i++)
{
for(int j = 0; j < contents[i].size(); j++)
{
std::cout << attributes[i][j] << std::endl << std::endl;
std::cout << contents[i][j] << std::endl << std::endl;
if(attributes[i][j] == "SolidTiles")
solidTiles.push_back(SetTiles(contents[i][j]));
else if(attributes[i][j] == "TileSheet")
{
tileSheet = al_load_bitmap(contents[i][j].c_str());
}
else if(attributes[i][j] == "StartLayer")
{
for(int k = 0; k < contents[i].size(); k++)
{
if(contents[i][k] != "---")
{
std::cout << contents[i][k] << std::endl << std::endl;
ALLEGRO_BITMAP *tileImage;
Tile::State tempState = Tile::State::Passive;
std::pair<int, int> tile = SetTiles(contents[i][k]);
if(std::find(solidTiles.begin(), solidTiles.end(), tile) != solidTiles.end())
{
tempState = Tile::State::Solid;
}
tileImage = al_create_sub_bitmap(tileSheet, tile.first * 32, tile.second * 32, 32, 32);
std::pair<float, float> position(k * 32, indexY * 32);
Tile tileInstance;
tiles.push_back(tileInstance);
tiles[tiles.size()-1].SetContent(tileImage, tempState, position);
}
}
indexY++;
}
}
}
}
void Layer::UnloadContent()
{
for(int i = 0; i < tiles.size(); i++)
tiles[i].UnloadContent();
al_destroy_bitmap(tileSheet);
}
void Layer::Update()
{
}
void Layer::Draw(ALLEGRO_DISPLAY *display)
{
for(int i = 0; i < tiles.size(); i++)
tiles[i].Draw(display);
}
map1.txt
Load=[MapProperties]
EndLoad=[MapProperties]
Load=[Layer1]
Load=[SolidTiles]
[2,0]
[1,0]
Load=[TileSheet]
[TileSheets/tilesheet1.png]
Load=[StartLayer]
[2,0][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][2,0][2,0][2,0][---][---][---][---]
[---][---][---][---][---][---][---][2,0][---][---][---][---][---][---][---]
[---][---][---][---][---][---][2,0][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[---][---][2,0][2,0][2,0][---][---][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[---][---][---][---][---][---][---][---][---][---][---][---][---][---][---]
[1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0][1,0]
Load=[EndLayer]
[dummy]
EndLoad=[Layer1]
Load=[PlayerPosition]
[0,0]

Segfault/ "Vector is not dereferencable" on std::vector push_back

I have some C++ code dealing with a card game and it's segfaulting and I can't figure out why. I tried running it in MSVS 2012 to get a more clear error and it threw a "Vector is not dereferencable." I tried doing some research but I'm lost on where the error is coming from. I'm guessing the bug isn't in the push_back but rather somewhere else as the problem line works most of the time. The error occurs in Table::hit(). After looking through the code I think the bug may possibly lie in Hand::split() but I am not sure and I am even less sure how to fix it. Thanks!
class Hand
{
public:
std::vector<Card> hand;
bool active, doubled, isBlackjack, busted;
Hand() : active(true), doubled(false), isBlackjack(false), busted(false) { }
Hand(const Hand& _hand);
void removeCard(Card card) { hand.erase( hand.begin() ); }
Card split();
void clear();
int cards() const { return hand.size(); }
int getHandValue() const;
Card at(int pos) { return hand[pos]; }
friend std::ostream& operator<< (std::ostream& out, const Hand& hand);
friend std::ostream& operator<< (std::ostream& out, const std::vector<Hand>& hands);
};
Hand::Hand(const Hand& _hand)
: hand(_hand.hand), active(_hand.active), doubled(_hand.doubled), isBlackjack(_hand.isBlackjack), busted(_hand.busted)
{ }
Card Hand::split()
{ //COULD THE BELOW CODE BE CAUSING ISSUES?
Card card = hand[0];
hand.erase( hand.begin() );
return card;
}
void Hand::clear()
{
active = true;
hand.clear();
}
int Hand::getHandValue() const
{
int value(0), aces(0);
for(std::vector<Card>::const_iterator it = hand.cbegin(); it != hand.cend(); ++it)
{
value += getCardValue(it->getRank());
if(it->getRank() == ACE)
++aces;
}
while(aces > 0 && value > 21)
{
value -= 10;
--aces;
}
return value;
}
std::ostream& operator<< (std::ostream& out, const Hand& hand)
{
for(std::vector<Card>::const_iterator it = hand.hand.begin(); it != hand.hand.end(); ++it)
{
out << *it << " ";
}
out << hand.getHandValue();
return out;
}
std::ostream& operator<< (std::ostream& out, const std::vector<Hand>& hands)
{
for(std::vector<Hand>::const_iterator it = hands.begin(); it != hands.end(); ++it)
{
out << *it << " ";
}
return out;
}
class Table
{
protected:
Shoe shoe;
Strategy strat;
Hand dealer;
std::vector< Hand > player;
double balance, blackjackPayoff;
bool hitSoft17;
void deal();
void hit(int split=0);
void split(int split=0);
double stand();
Action getUserAction();
bool isCurrentGame();
public:
Table(int decks, int _balance);
double bet;
void play();
void print();
void simulate(std::string fileName, int hands);
};
Table::Table(int decks, int _balance)
: shoe(decks), balance(_balance), blackjackPayoff(1.5), hitSoft17(true), bet(10)
{}
bool Table::isCurrentGame()
{
for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it)
{
if(it->active)
return true;
}
return false;
}
void Table::deal()
{
dealer.clear();
player.clear();
dealer.addCard( shoe.pullCard(true) );
dealer.addCard( shoe.pullCard() );
player.push_back(Hand());
player[0].addCard( shoe.pullCard() );
player[0].addCard( shoe.pullCard() );
if(player[0].getHandValue() == 21 && dealer.getHandValue() == 21)
{
player[0].active = false;
}
else if(player[0].getHandValue() == 21)
{
player[0].active = false;
}
else if(dealer.getHandValue() == 21)
{
player[0].active = false;
}
}
void Table::hit(int split)
{
player[split].hand.push_back( shoe.pullCard() ); //SEGFAULT HERE
if(player[split].getHandValue() > 21)
{
player[split].active = false;
}
}
void Table::split(int split)
{
player.push_back(Hand());
player[player.size() - 1].hand.push_back( player[split].split() );
player[split].hand.push_back( shoe.pullCard() );
player[player.size() - 1].hand.push_back( shoe.pullCard() );
if(player[split].getHandValue() == 21)
{
player[split].active = false;
}
else if(player[player.size() - 1].getHandValue() == 21)
{
player[player.size() - 1].active = false;
}
}
double Table::stand()
{
double winnings(0.0);
bool allNats(true);
//dealer.push_back( shoe.pullCard() );
for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it)
{
if(it->cards() == 2 && it->getHandValue() == 21)
{
winnings += bet * blackjackPayoff;
it->isBlackjack = true;
}
else
{
allNats = false;
if(it->getHandValue() > 21)
it->busted = true;
}
}
if(!allNats)
{
while(dealer.getHandValue() <= 17)
{
if(dealer.getHandValue() == 17)
{
//dealer has 17 and doesnt hit soft 17s so hes not going to draw anymore cards
if( !hitSoft17 || dealer.cards() != 2 || !(dealer.hand.at(0) == ACE || dealer.hand.at(1) == ACE) )
break;
}
dealer.addCard( shoe.pullCard() );
}
}
for(std::vector<Hand>::iterator it = player.begin(); it != player.end(); ++it)
{
if(!it->isBlackjack)
{
if(it->busted)
{
if(it->doubled)
winnings -= 2.0 * bet;
else
winnings -= bet;
}
else if(dealer.getHandValue() > 21 || dealer.getHandValue() < it->getHandValue())
{
if(it->doubled)
winnings += 2.0 * bet;
else
winnings += bet;
}
else if(dealer.getHandValue() > it->getHandValue())
{
if(it->doubled)
winnings -= 2.0 * bet;
else
winnings -= bet;
}
}
}
//only other scenario is a push which we dont do anythign for
return winnings;
}
void Table::simulate(std::string fileName, int hands)
{
int i(0), countHL;
double trueCountHL;
std::ofstream ofs(fileName);
Action action;
while(i < hands)
{
deal();
VisibleCards vc(player[0].at(0), player[0].at(1), dealer.at(0));
while(isCurrentGame())
{
int j(0), q(1);
countHL = shoe.getCountHL();
trueCountHL = shoe.getTrueCountHL();
for(int l = 0; l < q; ++l)
{
while(player[l].active)
{
if(player[l].cards() == 2)
action = getBasicStrategy(player[l].getHandValue(), dealer.at(0).getCardValue(),
player[l].at(0).getCardValue(), player[l].at(1).getCardValue());
else
action = getBasicStrategy(player[l].getHandValue(), dealer.at(0).getCardValue());
switch(action)
{
case HIT:
hit(j);
break;
case DOUBLE:
hit(j);
if(player[l].cards() == 3)
{
player[l].doubled = true;
player[l].active = false;
}
break;
case SPLIT:
if(player.size() <= 4)
{
split(j);
++q;
}
else
hit(j);
break;
case STAND:
player[l].active = false;
break;
}
++j;
}
}
}
double winnings = stand();
balance += winnings;
ofs << std::endl << std::fixed << vc << "," << winnings << "," << std::setprecision(2) << trueCountHL
<< "," << balance << "," << std::setprecision(0) << countHL << "," << shoe.getRemainingDecks();
ofs << std::endl << 1;
//BlackjackData bjd(winnings, balance, shoe.getTrueCountHL(), shoe.getCountHL(), HIT);
//strat.addData(vc, bjd);
++i;
}
strat.print(fileName);
}
Looks like you're trying to get the first card from hand with hand[0] and hand.erase(hand.begin()) without first checking that there IS a first card. If hand is empty (as is the case with a newly created Hand from the constructor), this causes undefined behavior, which may well manifest as a crash at some later time.
I stared at this for a day and couldn't figure it out, stepped out and realize I had an old variable "j" that I was using to access the vector instead of "l" when I was calling the "hit" function.... Thanks everyone for the help.