const int PIXEL_WIDTH = 10;
const int PIXEL_HEIGHT = 10;
const int WORLD_X = 64; //WORLD_X * PIXEL WIDTH = SCREEN_WIDTH if you want the world to be the same size as the screen
const int WORLD_Y = 64;
enum Pixel_Types {
AIR,
WALL,
DIRT,
STONE
};
class Pixel
{
int x, y;
bool affected_by_gravity;
Pixel_Types type;
public:
Pixel() : affected_by_gravity(false), type(AIR), x(0), y(0) {}
Pixel(int temp_x, int temp_y) : affected_by_gravity(false), type(AIR), x(temp_x), y(temp_y) {}
int getX() { return x; } //x is 0-63, scales up in the rendering code
int getY() { return y; } //y is 0-63, scales up in the rendering code
int getScreenX() { return x*PIXEL_WIDTH; } //x is 0-63, scales up in the rendering code
int getScreenY() { return y*PIXEL_HEIGHT; } //y is 0-63, scales up in the rendering code
bool setDeltaX(int temp_delta_x);
bool setDeltaY(int temp_delta_y);
void setAffectedByGravity(bool yesorno) { affected_by_gravity = yesorno; }
bool getAffectedByGravity() { return affected_by_gravity; }
Pixel_Types getType() { return type; }
void setType(Pixel_Types what_type) { type = what_type; }//if (type == DIRT or type == STONE) { affected_by_gravity = true; } }
};
std::vector<Pixel> world; //the world is a dynamically allocated thing
Pixel* getPixelFromCoordinates(int x, int y)
{
if (x > 63) x = 63;
else if (x < 0) x = 0;
if (y > 63) y = 63;
else if (y < 0) y = 0;
for (int pixel_index = 0; pixel_index < world.size(); pixel_index++) {
if (world.at(pixel_index).getX() == x && world.at(pixel_index).getY() == y) {
return &world.at(pixel_index);
}
}
return NULL;
}
bool Pixel::setDeltaX(int temp_delta_x) {
if (x+temp_delta_x > SCREEN_WIDTH/PIXEL_WIDTH or x+temp_delta_x < 0) {
return false;
}
if (getPixelFromCoordinates(x+temp_delta_x, y)->type == AIR) {
x += temp_delta_x;
return true;
}
return false;
}
bool Pixel::setDeltaY(int temp_delta_y) {
if (y+temp_delta_y > SCREEN_HEIGHT/PIXEL_HEIGHT or y+temp_delta_y < 0) {
return false;
}
if (getPixelFromCoordinates(x, y+temp_delta_y)->type == AIR) {
y += temp_delta_y;
return true;
}
return false;
}
void generateWorld()
{
for (int world_generation_index = 0; world_generation_index < 4096; world_generation_index++) {
int x = world_generation_index % WORLD_X; //the world is 64 pixels left and right, and 64 up and down. this math is pretty easy and just extrapolates that. also each pixel is 10 pixels across, times 64 pixels = 640 (the resolution)
int y = floor(world_generation_index / WORLD_Y); //both x and y start at 0
world.push_back(Pixel(x, y));
if (x == 0 || x == 63) {
world.at(world_generation_index).setType(WALL);
}
if (y == 1) {
world.at(world_generation_index).setType(WALL);
}
}
std::cout << "World size: " << world.size() << std::endl;
}
void createPixel(int x, int y, Pixel_Types type)
{
std::cout << x << std::endl;
std::cout << y << std::endl << std::endl;
y = (SCREEN_HEIGHT / PIXEL_HEIGHT) - y; //compensate for the stupid inverted y in opengl
//if (getPixelFromCoordinates(x, y)->getType() == AIR) {
getPixelFromCoordinates(x, y)->setType(type);
//}
}
void physicsOneStep()
{
for (int pixel_index = 0; pixel_index < world.size(); pixel_index++) {
if (world.at(pixel_index).getType() == DIRT or world.at(pixel_index).getType() == STONE) {//if (world.at(pixel_index).getAffectedByGravity()) {
world.at(pixel_index).setDeltaY(-1);
//std::cout << world.at(pixel_index).getX() << std::endl;
//std::cout << world.at(pixel_index).getY() << std::endl << std::endl;
}
}
}
So when I try to run this code (part of a larger project) it occasionally gives me a Segfault on calling setType(DIRT) from within createPixel(). I know that the values provided to createPixel() are within the range that they are allowed to be (0 to 64). It seems to segfault if you click (which calls createPixel()) in the same spot twice. The line that the debugger says segfaults is
void setType(Pixel_Types what_type) { type = what_type; }
though, I've verified that the values that I have supplied to this are correct.
Since there is no dynamic allocation inside the class, having a segfault on such an allocation most certainly occur because the this pointer itself is incorrect (NULL or badly allocated). You should get up the traceback when it segfaulted to see how the object on which you called setType was allocated. For example, shouldn't the line
world.push_back(Pixel(x, y));
be
world.push_back(new Pixel(x,y));
?
Related
New to C++. Here is my code:
#include <string>
#include <cstdlib>
#include <time.h>
using namespace std;
const int Gardensize = 20;//Garden size, a 20X20 2d array
const int initialants = 100;//100 initial ants
const int initialdoodlebug = 5;//5 intial bug
const int antType = 1;//
const int doodleType = 2;//
const char antchar = 'O';//ant will display'O'in the window
const char bugchar = 'X';//
class Garden;
class Organism;
class Ant;
class Doodlebug;
class Garden {
friend class Organism;
friend class Ant;
friend class Doodlebug;
public:
Garden();
~Garden();
int checkType(int x, int y);//check the element type (ant or bug)in the grid
void Display();
private:
Organism grid[Gardensize][Gardensize]; //C2079 'Garden::grid' uses undefined class 'Organism' I have already define the class Organism in advance,have no ideal how to fix this error.
};
Garden::Garden() { //initialize the garden, set all elements in grid to "NULL"
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
grid[i][j] = NULL; //error:subscript requires array or pointer
}
}
}
Garden::~Garden() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j] != NULL) {
grid[i][j] = NULL;
}
}
}
}
void Garden::Display() {
for (int i = 0; i < Gardensize; i++) {
for (int j = 0; j < Gardensize; j++) {
if (grid[i][j].getType == antType) {
cout << antchar;
}
else if (grid[i][j].getType == NULL) {
cout << ".";
}
else if (grid[i][j].getType == doodleType) {
cout << bugchar;
}
}
cout << endl;
}
}
int Garden::checkType(int x, int y) {
return grid[x][y].getType();
}
class Organism {
friend class Garden;
public:
virtual int getType() {}; //
virtual void breed() {};
virtual bool starve() {};
virtual int move( int &breedtoken) {};
protected:
int x = -1; //initial xy place
int y = -1;
Garden garden;
bool moved; //used to define whether org has moved or not
int breedtoken = 0; //used to define whether org need to breed
};
class Ant : public Organism {
public:
Ant() {}; //
Ant(int x, int y, Garden* g)//initial a ant object by define the xy place in the gardene
{
this->x = x;
this->y = y;
garden = *g;
}
~Ant() {};
virtual int getType() {
return antType;
}
virtual int move(int &breedtoken);
virtual void breed() {};
virtual bool starve() { return false; };// ant wont starve
};
int Ant::move(int& breedtoken) {
int dir = rand() % 4;// randomly select direction
switch (dir) {
case 0 :// 0move upwards
if( this->x > 0 && garden.grid[x - 1][y] == NULL ){
garden.grid[x-1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x--;
}
break;
case 1:// 1 move downwards
if (this->x < Gardensize - 1 && garden.grid[x + 1][y] == NULL) {
garden.grid[x + 1][y] = garden.grid[x][y];
garden.grid[x][y] = NULL;
x++;
}
break;
case 2: // 2 move leftwards
if (this->y > 0 && garden.grid[x][y-1] == NULL) {
garden.grid[x][y-1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y--;
}
break;
case 3: // 3 move to right
if (this->y < Gardensize- 1 && garden.grid[x][y + 1] == NULL) {
garden.grid[x][y + 1] = garden.grid[x][y];
garden.grid[x][y] = NULL;
y++;
}
break;
this->breedtoken += 1;
return breedtoken;
}
}
class Doodlebug :public Organism {
public:
Doodlebug() {};
Doodlebug(int x, int y, Garden* g)
{
this->x = x;
this->y = y;
garden = *g;
}
virtual int getType() {
return doodleType;
}
};
int main()
{
srand(time(NULL));//
Garden garden;
int antCount = 0; //Ant counter, used to intilize 100 ants
int DoodleCount = 0;
Ant antarray[initialants];
Doodlebug doodlebugarray[initialdoodlebug];
while (antCount < initialants) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
antarray[antCount] = Ant(x, y, &garden); //initilize 100 ants
antCount++;
}
}
while (DoodleCount < initialdoodlebug) {
int x = rand() % Gardensize;
int y = rand() % Gardensize;
if (garden.checkType(x, y) == NULL) {
doodlebugarray[DoodleCount] = Doodlebug(x, y, &garden); //用数组的模式创建100只蚂蚁
DoodleCount++;
}
}
garden.Display();//display
}
The project is not finished yet. Right now, the code can initialize 100ants and 5 bugs. It can run properly but keep showing"subscript requires array or pointer " wherever I write grid[i][j] in the for loop. and " 'Garden::grid' uses undefined class 'Organism'" when I define the "Organism grid[][]" in the Garden class. I wonder to know how can i fix these 2 errors, and what's wrong with my 2d array grid?
The problem with the 2d array is caused, because you try to create an array of Organisms, which are up to that point only declared, not defined, and so the compiler doesn't know their size and can't create an array of them. This can b fixed by reordering your classes, or by putting the class declarations in headers. You can also just replace the array with a dynamic array (double pointer), and initialize it after they have been declared.
The other error is just a consequence of the first, fix it and they will both disapear.
You should try reading some book about c or c++ first, and learn a bit about pointers, and design and structure of c++ programs
I was reading antti lakesonen's competitive programming handbook and I came across backtracking for finding grid paths with some optimizations applied. In nutshell here are the rules for a valid path across the grid :
0. Path search starts from top left cell and ends at bottom right cell.
1. A valid path has traversed all the cells of the grid once.
2. From current cell you can move right, left, top, bottom and only if the move doesn't leave the grid.
Now I have written this code that works fine with square grid of dimension = 7 with time taken ~400ms and total paths : 111712. I have two queries here :
--> With dimension = 9 its taking like a lot of time to report even the first valid path in its search. Am I stuck into the infinite loop or what?
--> Grid path search for even number of dimension like 2,4,6 are giving answer 0. I tried with finding path for 2*2 and 4*4 grid manually but I see that it's impossible to find such paths, but i don't know how to formally or logically prove that even dimensions square grids cannot have such paths mentioned above.
Here is my code :
#include <bits/stdc++.h>
using namespace std;
#define LOG_PATH 1;
#define ARRAY_BASED_CONSTANT_GRID 1;
struct Cell {
int x,y;
};
const int HORIZONTAL_DIRECTION = 0, VERTICAL_DIRECTION = 1;
long long validPathCount, recursiveCallCount, visitedCellCount, currentDirection;
#ifdef ARRAY_BASED_CONSTANT_GRID
const int DIMENSION = 7;
bool grid[DIMENSION][DIMENSION];
#else
int DIMENSION;
vector<vector<bool>> grid;
#endif
/* *-*-*-*-*-*-*-*- UTILITY FUNCTIONS -*-*-*-*-*-*-*-*-*-*-*-*-*-* */
bool hasPathCompleted(Cell);
bool isPathValid();
void validPathCheckAndUpdate();
void setState(Cell);
void resetState(Cell);
void updateAndLogPathCounter();
void backtrackPathSearching(Cell);
void moveAlongTheGrid(Cell);
bool isOccupied(Cell);
bool canMoveRight(Cell);
bool canMoveLeft(Cell);
bool canMoveUp(Cell);
bool canMoveDown(Cell);
bool isRightBorder(Cell);
bool isLeftBorder(Cell);
bool isUpBorder(Cell);
bool isDownBorder(Cell);
Cell generateRight(Cell);
Cell generateLeft(Cell);
Cell generateUp(Cell);
Cell generateDown(Cell);
bool isThereHorizontalPartition();
bool isThereVerticalPartition();
void printGrid();
/* *-*-*-*-*-*-*-*- UTILITY FUNCTIONS -*-*-*-*-*-*-*-*-*-*-*-*-*-* */
Cell generateRight(Cell position) {
currentDirection = HORIZONTAL_DIRECTION;
return {position.x, position.y + 1};
}
Cell generateLeft(Cell position) {
currentDirection = HORIZONTAL_DIRECTION;
return {position.x, position.y - 1};
}
Cell generateUp(Cell position) {
currentDirection = VERTICAL_DIRECTION;
return {position.x - 1, position.y};
}
Cell generateDown(Cell position) {
currentDirection = VERTICAL_DIRECTION;
return {position.x + 1, position.y};
}
bool isRightBorder(Cell position) { return position.y == DIMENSION - 1; }
bool isLeftBorder(Cell position) { return position.y == 0; }
bool isUpBorder(Cell position) { return position.x == 0; }
bool isDownBorder(Cell position) { return position.x == DIMENSION - 1; }
bool isOccupied(Cell position) { return grid[position.x][position.y]; }
bool canMoveRight(Cell position) { return !isRightBorder(position) && !isOccupied(generateRight(position)); }
bool canMoveLeft(Cell position) { return !isLeftBorder(position) && !isOccupied(generateLeft(position)); }
bool canMoveUp(Cell position) { return !isUpBorder(position) && !isOccupied(generateUp(position)); }
bool canMoveDown(Cell position) { return !isDownBorder(position) && !isOccupied(generateDown(position)); }
bool hasPathCompleted(Cell position) { return position.x == DIMENSION - 1 && position.y == DIMENSION - 1; }
bool isPathValid() { return visitedCellCount == DIMENSION * DIMENSION; }
void validPathCheckAndUpdate() {
if (isPathValid()) { updateAndLogPathCounter(); }
}
void updateAndLogPathCounter() {
validPathCount++;
#ifdef LOG_PATH
cout << "\rFound " << validPathCount << " paths";
cout.flush();
#endif
}
void setState(Cell position) {
recursiveCallCount++;
visitedCellCount++;
grid[position.x][position.y] = true;
}
void resetState(Cell position) {
visitedCellCount--;
grid[position.x][position.y] = false;
}
void printGrid() {
cout << "-------------------------------" << endl;
for (int i = 0; i < DIMENSION; i++) {
for (int j = 0; j < DIMENSION; j++) {
cout << grid[i][j] << " ";
}
cout << endl;
}
}
void moveAlongTheGrid(Cell position) {
if (canMoveRight(position)) {
backtrackPathSearching(generateRight(position));
}
if (canMoveLeft(position)) {
backtrackPathSearching(generateLeft(position));
}
if (canMoveUp(position)) {
backtrackPathSearching(generateUp(position));
}
if (canMoveDown(position)) {
backtrackPathSearching(generateDown(position));
}
}
bool isThereHorizontalPartition(Cell position) {
if (currentDirection == VERTICAL_DIRECTION) {
if (!canMoveUp(position) && !canMoveDown(position)) {
if (canMoveLeft(position) && canMoveRight(position)) {
return true;
}
}
}
return false;
}
bool isThereVerticalPartition(Cell position) {
if (currentDirection == HORIZONTAL_DIRECTION) {
if (!canMoveLeft(position) && !canMoveRight(position)) {
if (canMoveUp(position) && canMoveDown(position)) {
return true;
}
}
}
return false;
}
// OPTIMIZATION : 4 > Direction awareness
// Optimization 3 followed border awareness but this concept can be generalized
// and we can make the grid aware of its direction
// If path can't go forward in current direction but either can turn into both cross axis path
// then there is partition
void backtrackPathSearching(Cell position) {
setState(position);
// printGrid();
// cout << "x : " << position.x << " y : " << position.y << endl;
// cout << "validPathCount : " << validPathCount << endl;
// string s;
// getline(cin, s);
if (hasPathCompleted(position)) {
validPathCheckAndUpdate();
}
else if (!isThereHorizontalPartition(position) && !isThereVerticalPartition(position)) {
moveAlongTheGrid(position);
}
resetState(position);
}
#ifndef ARRAY_BASED_CONSTANT_GRID
void inputFromUser() {
cout << "Give Dimension of box grid : ";
cin >> DIMENSION;
for (int i = 0; i < DIMENSION; i++) grid.push_back(vector<bool>(DIMENSION, false));
}
#endif
int main() {
#ifndef ARRAY_BASED_CONSTANT_GRID
inputFromUser();
#endif
validPathCount = recursiveCallCount = 0;
visitedCellCount = 1;
grid[0][0] = 1;
currentDirection = VERTICAL_DIRECTION;
backtrackPathSearching({1, 0});
cout << endl;
cout << "Paths : " << validPathCount * 2 << endl;
cout << "Calls : " << recursiveCallCount << endl;
return 0;
}
/*
Paths : 111712
Calls : 26790463
real 0m0.281s
user 0m0.281s
sys 0m0.000s
*/
Just comment ARRAY_BASED_CONSTANT_GRID to enable user input for grid dimension.
Can someone help me with this? Thanks in advance :)
PS: Due to my coding practices I had to paste the whole code in order to make it sensible. I know in stackoverflow only minimal required code has to be pasted but here I don't know what's really needed in order to analyze the code!
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 attended a class of C++, not like all my students, I bought a Mac using xcode to run and edit my files. But recently there is a piece of code, that can be well ran in Ubuntu system, but in my mac, it kept giving me error.
the error appears in this line: char (*maze)[width] = reinterpret_cast (m_maze);
and there are 3 lines with the same above content. if you use the code in Ubuntu, it runs successfully, but in mac, it terminates and report 3 same errors.
the warn said: can not initialize a type of type 'char()[width]' with an rvalue of 'char()[width] '
Plz help
the code is about a mouse in a MAZE.
here are the codes:
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <cstdio>
using namespace std;
const char MOUSE = '*';
const char WAY = ' ';
const char WALL = '#';
const char PASS = '.';
const char IMPASS = 'X';
typedef enum tag_Direction {
EDIR_RIGHT,
EDIR_DOWN,
EDIR_LEFT,
EDIR_UP
} EDIR;
class Stack {
public:
Stack (void) : m_top (NULL) {}
~Stack (void) {
for (Node* next; m_top; m_top = next) {
next = m_top -> m_next;
delete m_top;
}
}
void push (EDIR dir) {
m_top = new Node (dir, m_top);
}
EDIR pop (void) {
if (! m_top)
throw underflow_error ("Underflow of Stack!");
EDIR dir = m_top -> m_dir;
Node* next = m_top -> m_next;
delete m_top;
m_top = next;
return dir;
}
private:
class Node {
public:
Node (EDIR dir, Node* next) : m_dir (dir),
m_next (next) {}
EDIR m_dir;
Node* m_next;
};
Node* m_top;
};
class Mouse {
public:
Mouse (size_t x, size_t y) : m_x (x), m_y (y),
m_total (0), m_valid (0) {}
size_t getx (void) const {
return m_x;
}
size_t gety (void) const {
return m_y;
}
size_t gettotal (void) const {
return m_total;
}
size_t getvalid (void) const {
return m_valid;
}
void stepright (void) {
m_x++;
remember (EDIR_RIGHT);
}
void stepdown (void) {
m_y++;
remember (EDIR_DOWN);
}
void stepleft (void) {
m_x--;
remember (EDIR_LEFT);
}
void stepup (void) {
m_y--;
remember (EDIR_UP);
}
void stepback (void) {
switch (recall ()) {
case EDIR_RIGHT:
m_x--;
break;
case EDIR_DOWN:
m_y--;
break;
case EDIR_LEFT:
m_x++;
break;
case EDIR_UP:
m_y++;
break;
}
}
private:
void remember (EDIR dir) {
m_brain.push (dir);
m_total++;
m_valid++;
}
EDIR recall (void) {
EDIR dir = m_brain.pop ();
m_total++;
m_valid--;
return dir;
}
size_t m_x;
size_t m_y;
size_t m_total;
size_t m_valid;
Stack m_brain;
};
class Game {
public:
Game (size_t width, size_t height) :
m_width (width), m_height (height),
m_maze (new char[width * height]),
m_mouse (0, 1) {
if (height < 3)
throw invalid_argument ("The maze is too small!");
srand (time (NULL));
char (*maze)[width] = reinterpret_cast<char (*)[width]> (m_maze);**
for (size_t i = 0; i < height; i++)
for (size_t j = 0; j < width; j++)
if (i == m_mouse.gety () &&
j == m_mouse.getx ())
maze[i][j] = MOUSE;
else
if ((i == 1 && j < 4) ||
(i == height - 2 && j >width-5))
maze[i][j] = WAY;
else
if (i == 0 || i == height - 1 ||
j == 0 || j == width - 1)
maze[i][j] = WALL;
else
maze[i][j] =
rand () % 4 ? WAY : WALL;
}
~Game (void) {
if (m_maze) {
delete[] m_maze;
m_maze = NULL;
}
}
void run (void) {
for (show (); ! quit () && step (););
}
private:
void show (void) {
char (*maze)[m_width] = reinterpret_cast<char (*)[m_width]> (m_maze);
for (size_t i = 0; i < m_height; i++) {
for (size_t j = 0; j < m_width; j++)
cout << maze[i][j];
cout << endl;
}
cout << "Total steps:" << m_mouse.gettotal ()
<< ",Valid steps:" << m_mouse.getvalid ()
<< endl;
}
bool quit (void) {
cout << "Press<Q>to exit,Other keys to continue..."<<flush;
int ch = getchar ();
cout << endl;
return ch == 'Q' || ch == 'q';
}
bool step (void) {
char (*maze)[m_width] = reinterpret_cast<char (*)[m_width]> (m_maze);
size_t x = m_mouse.getx ();
size_t y = m_mouse.gety ();
if (x + 1 <= m_width - 1 && maze[y][x + 1] == WAY) {
maze[y][x] = PASS;
m_mouse.stepright ();
}
else
if (y + 1 <= m_height - 1 &&
maze[y + 1][x] == WAY) {
maze[y][x] = PASS;
m_mouse.stepdown ();
}
else
if (x - 1 >= 0 &&
maze[y][x - 1] == WAY) {
maze[y][x] = PASS;
m_mouse.stepleft ();
}
else
if (y - 1 >= 0 &&
maze[y - 1][x] == WAY) {
maze[y][x] = PASS;
m_mouse.stepup ();
}
else {
maze[y][x] = IMPASS;
m_mouse.stepback ();
}
x = m_mouse.getx ();
y = m_mouse.gety ();
maze[y][x] = MOUSE;
show ();
if (x == 0 && y == 1) {
cout << "I can't get out!cry~~~~" << endl;
return false;
}
if (x == m_width - 1 && y == m_height - 2) {
cout << "I am OUT!!!" << endl;
return false;
}
return true;
}
size_t m_width;
size_t m_height;
char* m_maze;
Mouse m_mouse;
};
int main (int argc, char* argv[]) {
if (argc < 3) {
cerr << "Method:" << argv[0] << " <width> <height>"
<< endl;
return -1;
}
try {
Game game (atoi (argv[1]), atoi (argv[2]));
game.run ();
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}
char (*maze)[width] = reinterpret_cast<char (*)[width]> (m_maze);
is not standard: warning: ISO C++ forbids variable length array 'maze' [-Wvla].
You have to use
m_maze[y * width + x]
instead of
maze[y][x]
I don't understand this error it's written the exact same in the tutorial but my one generates an error.
#include "drawEngine.h"
#include <Windows.h>
#include <iostream>
using namespace std;
DrawEngine::DrawEngine(int xSize, int ySize)
{
screenWidth = xSize;
screenHeight = ySize;
//set cursor visibility to false
map = 0;
cursorVisibility(false);
}
DrawEngine::~DrawEngine()
{
//set cursor visibility to true
cursorVisibility(true);
}
int DrawEngine::createSprite(int index, char c)
{
if (index >= 0 && index < 16)
{
spriteImage[index] = c;
return index;
}
return -1;
}
void DrawEngine::deleteSprite(int index)
{
//in this implementation we don't need it
}
void DrawEngine::drawSprite(int index, int posx, int posy)
{
//go to the correct location
gotoxy(posx, posy);
//draw the image with cout
cout << spriteImage[index];
}
void DrawEngine::eraseSprite(int posx, int posy)
{
gotoxy(posx, posy);
cout << ' ';
}
void DrawEngine::setMap(char **data)
{
map = data;
}
void DrawEngine::createBackgroundTile(int index, char c)
{
if (index >= 0 && index < 16)
{
tileImage[index] = c;
}
}
void DrawEngine::drawBackground(void)
{
if (map)
{
for (int y = 0; y < screenHeight; y++)
{
goto(0, y); // This generates the error
for (int x = 0; x < screenWidth; x++)
{
cout << tileImage[map[x][y]];
}
}
}
}
void DrawEngine::gotoxy(int x, int y)
{
HANDLE output_handle;
COORD pos;
pos.X = x;
pos.Y = y;
output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output_handle, pos);
}
void DrawEngine::cursorVisibility(bool visibility)
{
HANDLE output_handle;
CONSOLE_CURSOR_INFO cciInfo;
cciInfo.dwSize = sizeof(CONSOLE_CURSOR_INFO);
cciInfo.bVisible = visibility;
output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(output_handle, &cciInfo);
}
I think you meant to write gotoxy(0, y) instead of goto(0, y).
goto is a C++ keyword which jumps to a label, for example:
home:
goto home; // Loops forever
Don't use it, though, it's too easy to create spaghetti code.
The goto(0, y) should probably be gotoxy(0, y). goto is a reserved keyword in C and cannot be used as a function name.
I think you meant gotoxy. goto is something else entirely.