I have a list of 'cell' objects in a 2d array of length [sizeX][sizeY]. These Cell objects contain an array of type *Cell, which should point to each of the given cell's adjacent cells in the format North, East, South, West (Never Eat Soggy Waffles).
This array is called compass, and is defined with a length of 4. After the cells have been initialized (at which time all values of compass are set to nullptr), I have a loop which attempts to fill Cell.compass with pointers to the appropriate nearby cells.
However, I have found that despite all this, in each cell I have found that compass still is full of null values.
In this loop, I also run a function Cell::computeTopology() which populates a vector (which is a property of Cell) of the valid non-null indexes of compass. This is similarly empty.
I have made a breakpoint both before and after this function has been called to the exact same effect. Regardless I will include this function as well. I'm utterly perplexed and some help here would be greatly appreciated.
Problem area:
const int sizeX = SCREEN_WIDTH / SCALE;
const int sizeY = SCREEN_HEIGHT / SCALE;
Cell cells[sizeX][sizeY];
for (int x = 0; x < sizeX; x++){
for (int y = 0; y < sizeY; y++){
cells[x][y].setPos(x, y);
cells[x][y] = Cell();
//cells[x][y].setColor(rand() % 255, rand() % 255, rand() % 255);
}
}
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
Cell c = cells[x][y];
if (x - 1 >= 0) {
c.compass[3] = &cells[x - 1][y];
}
if (x + 1 < (SCREEN_WIDTH / SCALE)) {
c.compass[1] = &cells[x + 1][y];
}
if (y - 1 >= 0) {
c.compass[0] = &cells[x][y - 1];
}
if (y + 1 < (SCREEN_HEIGHT / SCALE)) {
c.compass[2] = &cells[x][y + 1];
}
c.computeTopology();
}
}
And the computeTopology() function
void Cell::computeTopology()
{
int i = 0;
for (Cell *c : compass) {
if (c != nullptr) {
notNull.push_back(i);
i++;
}
}
}
Change
Cell c = cells[x][y]; // make a copy
to
Cell& c = cells[x][y];
you want to modify item of array, not copy.
Another issue
cells[x][y].setPos(x, y);
cells[x][y] = Cell(); // ?
you are setting some members of cells[x][y] by calling setPos and after it you are overwriting cells[x][y] by default constructed Cell object. I think the second line in above code should be removed.
Your words
which populates a vector (which is a property of Cell) of the valid
non-null indexes of compass
so i index should be advanced with every iteration of for loop:
int i = 0;
for (Cell *c : compass) {
if (c != nullptr) {
notNull.push_back(i);
}
++i; // moved
}
Related
I'm working on a project that uses a 2D array. The inside (anything that isn't on the edge of the array) of the array has each cell averaging out based on the four values touching it. The values are supposed to keep updating until the change in value (new array value - previous value in array) is less than a number input by the user called epsilon. This change in value has to be less than epsilon for each and every index. So how would I go about checking each change in index value to epsilon? I was thinking about storing the change in a new array and checking each index to epsilon but the way I implemented it didn't work. You can ignore the tempChange array I didn't remove it incase someone wanted to build off of what I wrote. Here is my code:
void determineInteriorTemp(double tempArr[26][30], int rowArr, int colArr, double epsilon)
{
int iteration = 0;
double tempChange[26][30] = { 300 };
for (int x = 1; x < rowArr - 1; x++)
{
for (int y = 1; y < colArr - 1; y++)
{
while (tempChange[x][y] > epsilon)
{
tempArr[x][y] = (tempArr[x - 1][y] + tempArr[x + 1][y] + tempArr[x][y + 1] + tempArr[x][y - 1]) / 4; //update
tempChange[0][0] = tempArr[x][y] - tempChange[x][y];
}
}
}
iteration++;
}
I wanted to create a function that will split a string by a delimiter.. I know there's already a function that does this thing but I wanted to make on my own.. But it doesn't work as it should.
char** Engine::splitString(const char* text, char delimiter)
{
char** splitted;
splitted = (char**)malloc(50 * sizeof(char*));
for (int y = 0; y < 50; y++)
splitted[y] = (char*)malloc((strlen(text) + 2) * sizeof(char));
int delimiterPosition[50];
int arrayLength = 0;
int f = 0;
int g = 0;
for (int x = 0; x < strlen(text); x++)
{
if (text[x] == delimiter)
{
delimiterPosition[f] = x;
f++;
}
}
for (int x = 0; x < 50; x++)
if (delimiterPosition[x] > 0 )
arrayLength++;
while (g < arrayLength) {
if (g == 0) {
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
}
else if(g > 0)
{
for (int y = delimiterPosition[g - 1]; y < delimiterPosition[g] - delimiterPosition[g - 1]; y++)
{
splitted[g][y] = text[y];
}
}
g++;
}
return splitted;
}
First of all, I declared a two dimensional char array -> splitted. This was the variable that I should store my results into. Then I allocated a memory for it.. I wanted to have 50 words maximum. After that I created integer array.. this served as a storage for delimiters' positions. I also defined some variables below it for my code. Then I looped through the text to see if there's any delimiter.. if yes, I wanted to store it's position to a certain position in array, starting off from 0. I looped through delimiterPosition's array to how many positions I have stored. Then I made a simple loop using while to take all the characters up to the delimiter's position and store them to splitted[g][y] .. g represents the whole word.. y represents the character in that word. If g was greater than zero, I tok the previous position of a delimiter and then substracted the current from the previous.. and that gave me the distance between the first delimiter and the next..
The main problem here is that the first word is written correctly, the second one is not working, but it has some weird characters behind it when I try to call it.. is the text somehow leaking? the second one isn't being stored at all?:
char** strings = en.splitString("Hello;boy", ';');
printf("%s", strings[1]);
First word:
Second:
Any solutions, guys ? :) Thank you for any comment.
This does not initialize the memory:
int delimiterPosition[50];
So its content is potentially random (and its undefined to read from unless you initialize it first). So here:
if (delimiterPosition[x] > 0 ) // Is potentially invalid if x >= f
Easily solved with:
int delimiterPosition[50] = {0};
Potential for overflow here:
delimiterPosition[f] = x;
f++;
You don't validate that f remains in the correct range (less than 50). Another easy fix:
size_t stringLen = strlen(text); // Don't need to recalculate this each time!
for (int x = 0; f < 50 && x < stringLen; x++)
{
if (text[x] == delimiter)
{
delimiterPosition[f] = x;
f++;
}
}
Here is the problem you are complaining about:
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
You copy the string.
But you don't add a terminator to the string. So when you try and print it you see all the extra characters on the end.
for (int y = 0; y < delimiterPosition[0]; y++)
{
splitted[g][y] = text[y];
}
splitted[g][y] = '\0'; // Add string terminator.
For the second a subsequent string you have the null terminator problem. But you also have the issue that you are copying the string to not the beginning.
// After the first string the value of y in an offset into text only
// So when used with `splitted[g]` you are offset from the beginning
// if the string.
splitted[g][y] = text[y];
Also your test for the end of the string is wrong:
Remember you start at:
int y = delimiterPosition[g - 1]
So y is an offset into the string. So as you increase it it will always be an offset not a length.
// So this test is wrong (you are using a length not an offset.
y < delimiterPosition[g] - delimiterPosition[g - 1]
Lets fix both at the same time:
int dstIndex = 0;
for (int y = delimiterPosition[g - 1]; y < delimiterPosition[g]; y++, dstIndex++)
{
splitted[g][dstIndex] = text[y];
}
splitted[g][dstIndex] = '\0';
I'm writing a battleship game in the console, and I'm writing a function that will draw one grid based on a 2-dimensional array. The approach I'm taking is such:
--> Draw 1 row which contains a character X amount of times (like 10)
--> Draw that row, putting a newline at the end of the drawing process, 10 times to get a nice field.
Now, I do need to insert a newline at the end of 1 row, right? But how do I compare only the x-element of the array, and not the y-element?
Here's my code:
// Includes
#include <iostream> // For IO
#include <cstdlib> // For rand()
// Important game stuff
const int empty = 0; // Water
const int occupied = 1; // Ship
const int hit = 2; // Hit a ship
const int missed = 3; // Missed
// Variables
const int fields = 10;
// We want a 10x10 field
int board[fields][fields]; // board[x][y]
// Initialize board
void initb(int array[fields][fields]);
// Draw board x-axis
void drawbx(int array[fields][fields]);
int main(void)
{
drawbx(board;)
// game(Players);
return 0;
}
// Initialize the board, make everything hit
void initb(int array[fields][fields])
{
for(int x = 1; x <= 10; x++)
{
for(int y = 1; y <= 10; y++)
{
array[x][y] = hit;
}
}
}
void drawbx(int array[fields][fields])
{
for(int i = 1; i <= fields; i++)
{
if(array[i][] == empty || array[i][] == occupied)
{
if(i == 10)
std::cout << " X\n";
else if(i == 1)
std::cout << "X ";
else
std::cout << " X ";
}
}
}
Take a look specifically at the drawbx() function. I want to draw something like
X X X X X X X X X X\n
The syntax that I tried, if(array[i][] == empty || array[i][] == occupied), doesn't work. There must be an expression in the second pair of square brackets. Can someone help me?
I see two major problems:
1) Array indexing is out of range. You use index 1 to 10. It shall be 0 to 9.
2) Code array[i][] == empty is illegal syntax. You can't leave one index empty.
If you want a function that draw one row, perhaps pass the row number to the function like:
void draw_one_row(int array[fields][fields], int row_to_draw)
{
for(int i = 0; i < fields; i++)
{
if(array[row_to_draw][i] == empty || array[row_to_draw][i] == occupied)
{
...
}
}
}
To draw the whole board:
void draw_board(int array[fields][fields])
{
for(int i = 0; i < fields; i++)
{
draw_one_row(array, i);
}
}
BTW: Since you write C++, I'll recommend that you use vector instead of arrays.
I'm trying to learn C++, so I apologize if my code is messy or inefficient.
I've been trying to learn vectors, and I'm attempting to generate a "map" stored in one.
So far, I can generate the vector, but I'm having troubles with assigning values to it. This is the function I have set up to assign values to my "map" vector:
void generateMap(mapSize size, vector<vector<vector<int>>>& map) {
int xSize, ySize;
//Resize Vector Based on Map Size Choice
if (size == tiny) { xSize = 10; ySize = 10; }
if (size == medium) { xSize = 30; ySize = 30; }
if (size == large) { xSize = 50; ySize = 50; }
map.resize(xSize, vector<vector<int>>(ySize, vector<int>(2)));
//Generate Map
for (int x = 0; x < xSize; x++) {
for (int y = 0; y < ySize; y++) {
if (x == 0 || x == xSize) map[x][y][0] = wallTile;
else if (y == 0 || y == ySize) map[x][y][0] = wallTile;
else map[x][y][0] = tileType::floorTile;
}
} }
With the vector "map" defined in main as:
vector<vector<vector<int>>> map;
And my "mapSize" and tile enums defined as such:
enum tileType { emptyTile, floorTile, wallTile };
enum mapSize { tiny, medium, large }; //10x10, 30x30, 50x50 tiles, respectively
(In my head, the vector holds x and y coordinates to a "cell", and each "cell" (not sure what they're actually called) has two entries, tileType, and presence of a monster/trap/something else)
To test, I attempted to display the "map" in main as such:
for (int y = 0; y < ySize; y++) {
for (int x = 0; x < xSize; x++) {
cout << map[x][y][0];
}
cout << endl;
}
Now, what I was expecting to be produced was a box, with the outside 4 "walls" being comprised of wallTiles (or in this case, 2s), and the inside filled with floorTiles (1s).
What was actually displayed, however, is the top and left walls being comprised of 2s, and the rest being 1s.
I'm not entirely sure what's going wrong since, to me, the if statements should have taken care of that. I went through with debug mode as well, watching the values change, and I still can't figure where it's setting the wrong "tiles" to 1s. It could also be that I'm going about assigning values to the vector wrong; I was just going off research from the c++ reference, as well as here.
At this point, I just need another set of (more experienced) eyes.
Thanks!
(This is the full code, if it helps: http://pastebin.com/i2mwEm0M)
Your for loops are written as:
for (int x = 0; x < xSize; x++)
Yet when you decide what's a wall you write:
if (x == 0 || x == xSize) map[x][y][0] = wallTile;
x will never be xSize, at most it will be xSize - 1.
I have some C++ code I wrote to find an A* path, but it's behaving strangely. There's quite a bit of code here, so I'll split it into chunks and try to explain what I'm doing. I'm not gonna explain how A* pathing works. I assume if you're trying to help you already know the algorithm.
First off, here's my function for calculating the h value of a node:
int
calculateH(int cX, int cY, int eX, int eY, int horiCost = 10, int diagCost = 14) {
int h;
int xDist = abs(eX - cX);
int yDist = abs(eY - cY);
if (xDist > yDist)
h = (diagCost * yDist) + (horiCost * (xDist - yDist));
else
h = (diagCost * xDist) + (horiCost * (yDist - xDist));
return h;
}
I'm pretty sure there's no problem here; pretty simple stuff.
Next my Node class. And I know, I know, make those variables private and use getters; I just did it this way for testing purposes.
class Node {
public:
Node(int x_, int y_, int g_, int h_, int pX_, int pY_, bool list_) {
x = x_;
y = y_;
g = g_;
h = h_;
pX = pX_;
pY = pY_;
list = list_;
};
int x, y, g, h, pX, pY;
bool list;
};
Each Node has an X and Y variable. I only store G and H, not F, and calculate F when I need it (which is only once in my code). Then there's the Parent X and Y values. List is a boolean: fale = open list, true = closed list.
I also have a Object class. The only variables that matter here are X, Y, and Passable, all accessed through getters.
Now here's the start of my actual pathfinding code. It returns a string of numbers corresponding to directions as shown below:
432
501
678
So 1 means move right, 8 means go down and right, 0 means don't go anywhere.
string
findPath(int startX, int startY, int finishX, int finishY) {
// Check if we're already there.
if (startX == finishX && startY == finishY)
return "0";
// Check if the space is occupied.
for (int k = 0; k < objects.size(); k ++)
if ((objects[k] -> getX() == finishX) &&
(objects[k] -> getY() == finishY) &&
(!objects[k] -> canPass()))
return "0";
// The string that contains our path.
string path = "";
// The identifier of the current node.
int currentNode = 0;
// The list of nodes.
vector<Node> nodes;
// Add the starting node to the closed list.
nodes.push_back(Node(startX, startY, 0,
calculateH(startX, startY, finishX, finishY),
startX, startY, true));
Now we loop through until we find the destination. Note that sizeLimit is just to make sure we don't loop forever (it WONT if I can fix this code. As of right now it's very necessary). Everything from this point on, until I mark otherwise, is inside the i j loops.
int sizeLimit = 0;
while ((nodes[currentNode].x != finishX) | (nodes[currentNode].y != finishY)) {
// Check the surrounding spaces.
for (int i = -1; i <= 1; i ++) {
for (int j = -1; j <= 1; j ++) {
bool isEmpty = true;
// Check if there's a wall there.
for (int k = 0; k < objects.size(); k ++) {
if ((objects[k] -> getX() == (nodes[currentNode].x + i)) &&
(objects[k] -> getY() == (nodes[currentNode].y + j)) &&
(!objects[k] -> canPass())) {
isEmpty = false;
}
}
Next part:
// Check if it's on the closed list.
for (int k = 0; k < nodes.size(); k ++) {
if ((nodes[k].x == (nodes[currentNode].x + i)) &&
(nodes[k].y == (nodes[currentNode].y + j)) &&
(nodes[k].list)) {
isEmpty = false;
}
}
Continuing on:
// Check if it's on the open list.
for (int k = 0; k < nodes.size(); k ++) {
if ((nodes[k].x == (nodes[currentNode].x + i)) &&
(nodes[k].y == (nodes[currentNode].y + j)) &&
(!nodes[k].list)) {
// Check if the G score is lower from here.
if (nodes[currentNode].g + 10 + (abs(i * j) * 4) <= nodes[k].g) {
nodes[k].g = nodes[currentNode].g + 10 + (abs(i * j) * 4);
nodes[k].pX = nodes[currentNode].x;
nodes[k].pY = nodes[currentNode].y;
}
isEmpty = false;
}
}
This is the last part of the i j loop:
if (isEmpty) {
nodes.push_back(Node(nodes[currentNode].x + i,
nodes[currentNode].y + j,
nodes[currentNode].g + 10 + (abs(i * j) * 4),
calculateH(nodes[currentNode].x + i, nodes[currentNode].y + j, finishX, finishY),
nodes[currentNode].x,
nodes[currentNode].y,
false));
}
}
}
Now we find the Node with the lowest F score, change it to the current node, and add it to the closed list. The protection against infinite lopping is also finished up here:
// Set the current node to the one with the lowest F score.
int lowestF = (nodes[currentNode].g + nodes[currentNode].h);
int lowestFIndex = currentNode;
for (int k = 0; k < nodes.size(); k ++) {
if (((nodes[k].g + nodes[k].h) <= lowestF) &&
(!nodes[k].list)) {
lowestF = (nodes[k].g + nodes[k].h);
lowestFIndex = k;
}
}
currentNode = lowestFIndex;
// Change it to the closed list.
nodes[currentNode].list = true;
sizeLimit ++;
if (sizeLimit > 1000)
return "";
}
The problem I'm having is that it wont find certain paths. It seems to never work if the path goes up or left at any point. Down, left, and right all work fine. Most of the time anyway. I have absolutely no idea what's causing this problem; at one point I even tried manually following my code to see where the problem was. No surprise that didn't work.
And one more thing: if you're counting my curly braces (first of all wow, you have more dedication than I thought), you'll notice I'm missing a close brace at the end. Not to mention my return statement. There's a little bit of code at the end to actually make the path that I've left out. I know that that part's not the problem however; I currently have it commented out and it still doesn't work in the same way. I added some code to tell me where it's not working, and it's at the pathfinding part, not the interpretation.
Sorry my code's so messy and inefficient. I'm new to c++, so any critical advice on my technique is welcome as well.
I think that when you are looking for the next "currentNode", you should not start with lowestF = (nodes[currentNode].g + nodes[currentNode].h); because that value, in principle, will (always) be lower-or-equal-to any other nodes in the open-set. Just start with the value of std::numeric_limits<int>::max() or some very large number, or use a priority queue instead of an std::vector to store the nodes (like std::priority_queue, or boost::d_ary_heap_indirect).
I'm pretty sure that is the problem. And since your heuristic can very often be equal to the actual path-distance obtained, there is a good chance that following nodes in the open-set turn out to have the same cost (g+h) as the currentNode. This would explain why certain paths get explored and others don't and why it gets stuck.