use of undeclared identifier c++ xcode - c++

I work in cocos2d-x help the problem. error in this line
string route = pathFind(xA, yA, xB, yB);
code HelloWorldScene.cpp
#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include <iostream>
#include <iomanip>
#include <math.h>
#include <queue>
#include <string>
using namespace std;
using namespace cocos2d;
using namespace CocosDenshion;
const int n = 20; // horizontal size of the map
const int m = 20; // vertical size size of the map
static int MAPP[n][m];
static int putX[100];
static int putY[100];
static int closed_nodes_map[n][m]; // map of closed (tried-out) nodes
static int open_nodes_map[n][m]; // map of open (not-yet-tried) nodes
static int dir_map[n][m]; // map of directions
const int dir = 8; // number of possible directions to go at any position
static int dx[dir] = { 1, 1, 0, -1, -1, -1, 0, 1 };
static int dy[dir] = { 0, 1, 1, 1, 0, -1, -1, -1 };
class node
{
// current position
int xPos;
int yPos;
// total distance already travelled to reach the node
int level;
// priority=level+remaining distance estimate
int priority; // smaller: higher priority
public:
node(int xp, int yp, int d, int p)
{
xPos = xp; yPos = yp; level = d; priority = p;
}
int getxPos() const { return xPos; }
int getyPos() const { return yPos; }
int getLevel() const { return level; }
int getPriority() const { return priority; }
void updatePriority(const int & xDest, const int & yDest)
{
priority = level + estimate(xDest, yDest) * 10; //A*
}
// give better priority to going strait instead of diagonally
void nextLevel(const int & i) // i: direction
{
level += (dir == 8 ? (i % 2 == 0 ? 10 : 14) : 10);
}
// Estimation function for the remaining distance to the goal.
const int & estimate(const int & xDest, const int & yDest) const
{
static int xd, yd, d;
xd = xDest - xPos;
yd = yDest - yPos;
// Euclidian Distance
d = static_cast<int>(sqrt(xd*xd + yd*yd));
// Manhattan distance
//d=abs(xd)+abs(yd);
// Chebyshev distance
//d=max(abs(xd), abs(yd));
return(d);
}
};
CCScene* HelloWorld::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
for (int y = 0; y < m; y++)
{
for (int x = 0; x < n; x++) MAPP[x][y] = 0;
}
int xA=0, yA=0, xB=7, yB=5;
// get the route
string route = pathFind(xA, yA, xB, yB);
// follow the route on the map and display it
if (route.length() > 0)
{
int j; char c;
int x = xA;
int y = yA;
MAPP[x][y] = 2;
for (int i = 0; i < route.length(); i++)
{
c = route.at(i);
j = atoi(&c);
x = x + dx[j];
y = y + dy[j];
MAPP[x][y] = 3;
}
MAPP[x][y] = 4;
}
int putS=0;
for (int y = 0; y < m; y++)
{
for (int x = 0; x < n; x++)
{
if (MAPP[x][y] == 3)
{
putY[putS] = y;
putX[putS] = x;
putS++;
}
}
}
return true;
}
bool operator < (const node & a, const node & b)
{
return a.getPriority() > b.getPriority();
}
// A-star algorithm.
// The route returned is a string of direction digits.
string pathFind(const int & xStart, const int & yStart,
const int & xFinish, const int & yFinish)
{
static priority_queue<node> pq[2]; // list of open (not-yet-tried) nodes
static int pqi; // pq index
static node* n0;
static node* m0;
static int i, j, x, y, xdx, ydy;
static char c;
pqi = 0;
// reset the node maps
for (y = 0; y < m; y++)
{
for (x = 0; x < n; x++)
{
closed_nodes_map[x][y] = 0;
open_nodes_map[x][y] = 0;
}
}
// create the start node and push into list of open nodes
n0 = new node(xStart, yStart, 0, 0);
n0->updatePriority(xFinish, yFinish);
pq[pqi].push(*n0);
open_nodes_map[x][y] = n0->getPriority(); // mark it on the open nodes map
// A* search
while (!pq[pqi].empty())
{
// get the current node w/ the highest priority
// from the list of open nodes
n0 = new node(pq[pqi].top().getxPos(), pq[pqi].top().getyPos(),
pq[pqi].top().getLevel(), pq[pqi].top().getPriority());
x = n0->getxPos(); y = n0->getyPos();
pq[pqi].pop(); // remove the node from the open list
open_nodes_map[x][y] = 0;
// mark it on the closed nodes map
closed_nodes_map[x][y] = 1;
// quit searching when the goal state is reached
//if((*n0).estimate(xFinish, yFinish) == 0)
if (x == xFinish && y == yFinish)
{
// generate the path from finish to start
// by following the directions
string path = "";
while (!(x == xStart && y == yStart))
{
j = dir_map[x][y];
c = '0' + (j + dir / 2)%dir;
path = c + path;
x += dx[j];
y += dy[j];
}
// garbage collection
delete n0;
// empty the leftover nodes
while (!pq[pqi].empty()) pq[pqi].pop();
return path;
}
// generate moves (child nodes) in all possible directions
for (i = 0; i < dir; i++)
{
xdx = x + dx[i]; ydy = y + dy[i];
if (!(xdx<0 || xdx>n - 1 || ydy<0 || ydy>m - 1 || MAPP[xdx][ydy] == 1
|| closed_nodes_map[xdx][ydy] == 1))
{
// generate a child node
m0 = new node(xdx, ydy, n0->getLevel(),
n0->getPriority());
m0->nextLevel(i);
m0->updatePriority(xFinish, yFinish);
// if it is not in the open list then add into that
if (open_nodes_map[xdx][ydy] == 0)
{
open_nodes_map[xdx][ydy] = m0->getPriority();
pq[pqi].push(*m0);
// mark its parent node direction
dir_map[xdx][ydy] = (i + dir / 2)%dir;
}
else if (open_nodes_map[xdx][ydy] > m0->getPriority())
{
// update the priority info
open_nodes_map[xdx][ydy] = m0->getPriority();
// update the parent direction info
dir_map[xdx][ydy] = (i + dir / 2)%dir;
// replace the node
// by emptying one pq to the other one
// except the node to be replaced will be ignored
// and the new node will be pushed in instead
while (!(pq[pqi].top().getxPos() == xdx &&
pq[pqi].top().getyPos() == ydy))
{
pq[1 - pqi].push(pq[pqi].top());
pq[pqi].pop();
}
pq[pqi].pop(); // remove the wanted node
// empty the larger size pq to the smaller one
if (pq[pqi].size() > pq[1 - pqi].size()) pqi = 1 - pqi;
while (!pq[pqi].empty())
{
pq[1 - pqi].push(pq[pqi].top());
pq[pqi].pop();
}
pqi = 1 - pqi;
pq[pqi].push(*m0); // add the better node instead
}
else delete m0; // garbage collection
}
}
delete n0; // garbage collection
}
return ""; // no route found
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
code HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::CCLayer
{
public:
// Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer)
virtual bool init();
// there's no 'id' in cpp, so we recommend to return the class instance pointer
static cocos2d::CCScene* scene();
// a selector callback
void menuCloseCallback(CCObject* pSender);
// preprocessor macro for "static create()" constructor ( node() deprecated )
CREATE_FUNC(HelloWorld);
};
#endif // __HELLOWORLD_SCENE_H__

pathFind is a function, you should prototype it. Add this somewhere the top of HelloWorldScene.cpp
string pathFind(const int & xStart, const int & yStart,
const int & xFinish, const int & yFinish);
Or if you are intending to call this function from another module then put the prototype in an appropriate header file.

Related

Im trying to make an astar algorithm for a school thing

Here is my code i've been working on. I've scraped off all the errors from the code. But i cant get the code to run correctly and the application either explodes or doesn't atleast visualise the astar.
#include <SFML/Graphics.hpp>
#include <queue>
#include <unordered_map>
#include <cmath>
#include <vector>
const int WIDTH = 10;
const int HEIGHT = 10;
struct Node
{
int x;
int y;
mutable float gScore;
mutable float fScore;
mutable const Node* parent;
Node(int _x, int _y) : x(_x), y(_y), gScore(0), fScore(0), parent(nullptr) {}
bool operator==(const Node& other) const
{
return x == other.x && y == other.y;
}
};
// Hash function for nodes, needed for storing them in an unordered_map
struct NodeHash
{
std::size_t operator()(const Node& node) const
{
return std::hash<int>()(node.x) ^ std::hash<int>()(node.y);
}
};
// Overload the ">" operator for nodes, needed for using them in a priority queue
struct NodeGreater
{
bool operator()(const Node& left, const Node& right) const
{
return left.fScore > right.fScore;
}
};
// Represents a 2D grid
class Grid
{
public:
Grid()
{
// Initialize the grid with all nodes as walkable
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
nodes[x][y] = true;
}
}
}
// Set the walkability of a node
void setNode(int x, int y, bool walkable)
{
nodes[x][y] = walkable;
}
// Check if a node is walkable
bool isNodeWalkable(int x, int y)
{
return nodes[x][y];
}
private:
bool nodes[WIDTH][HEIGHT];
};
// Calculate the Euclidean distance between two nodes
float euclideanDistance(Node a, Node b)
{
int xDist = b.x - a.x;
int yDist = b.y - a.y;
return std::sqrt(xDist * xDist + yDist * yDist);
}
// Estimate the cost of reaching the end node from a given node
float heuristicCostEstimate(Node start, Node end)
{
return euclideanDistance(start, end);
}
// Get the neighbors of a given node
std::vector<Node> getNeighbors(Grid grid, Node node)
{
std::vector<Node> neighbors;
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
// Skip the current node
if (x == 0 && y == 0)
{
continue;
}
int neighborX = node.x + x;
int neighborY = node.y + y;
// Make sure the neighbor is within the bounds of the grid
if (neighborX >= 0 && neighborX < WIDTH && neighborY >= 0 && neighborY < HEIGHT)
{
// Make sure the neighbor is walkable
if (grid.isNodeWalkable(neighborX, neighborY))
{
Node neighbor = { neighborX, neighborY };
neighbors.push_back(neighbor);
}
}
}
}
return neighbors;
}
// Reconstruct the path from the end node to the start node
std::vector<Node> reconstructPath(Node end)
{
std::vector<Node> path;
Node current = end;
while (current.parent != nullptr)
{
path.push_back(current);
current = *current.parent;
}
path.push_back(current);
std::reverse(path.begin(), path.end());
return path;
}
// Run the A* algorithm to find the shortest path from the start to the end node
std::vector<Node> aStar(Grid grid, Node start, Node end)
{
// Initialize the open and closed sets
std::priority_queue<Node, std::vector<Node>, NodeGreater> openSet;
std::unordered_map<Node, bool, NodeHash> closedSet;
// Add the start node to the open set
openSet.push(start);
// Set the starting node's gScore to 0 and fScore to the estimated cost to the end node
start.gScore = 0;
start.fScore = heuristicCostEstimate(start, end);
// Keep searching until the open set is empty
while (!openSet.empty())
{
// Get the node in the open set with the lowest fScore
Node current = openSet.top();
openSet.pop();
// If the current node is the end node, we have found the shortest path
if (current == end)
{
return reconstructPath(current);
}
// Add the current node to the closed set
closedSet[current] = true;
// Get the neighbors of the current node
std::vector<Node> neighbors = getNeighbors(grid, current);
// Iterate through the neighbors
for (const Node& neighbor : neighbors)
{
// Skip the neighbor if it is already in the closed set
if (closedSet.count(neighbor) > 0)
{
continue;
}
// Calculate the tentative gScore for the neighbor
float tentativeGScore = current.gScore + euclideanDistance(current, neighbor);
bool neighborIsBetter = false;
bool neighborInOpenSet = false;
// Check if the neighbor is already in the open set
std::priority_queue<Node, std::vector<Node>, NodeGreater> tempOpenSet = openSet;
while (!tempOpenSet.empty())
{
Node tempNeighbor = tempOpenSet.top();
tempOpenSet.pop();
if (tempNeighbor == neighbor)
{
neighborInOpenSet = true;
break;
}
}
// Update the neighbor's scores and parent if the tentative gScore is lower than
if (tentativeGScore < neighbor.gScore)
{
neighborIsBetter = true;
neighbor.gScore = tentativeGScore;
neighbor.fScore = tentativeGScore + heuristicCostEstimate(neighbor, end);
}
if (!neighborInOpenSet || neighborIsBetter)
{
// Update the neighbor's parent to the current node
neighbor.parent = &current;
// Add the neighbor to the open set if it is not already there
if (!neighborInOpenSet)
{
openSet.push(neighbor);
}
}
}
}
// If we reach here, it means that we have not found a path to the end node
return std::vector<Node>();
}
int main()
{
// Create the window and grid
sf::RenderWindow window(sf::VideoMode(500, 500), "A*");
Grid grid;
// Set some nodes as unwalkable
grid.setNode(3, 3, false);
grid.setNode(3, 4, false);
grid.setNode(3, 5, false);
grid.setNode(4, 3, false);
// Set the start and end nodes
Node start = { 1, 1 };
Node end = { 8, 8 };
// Run the A* algorithm and get the path
std::vector<Node> path = aStar(grid, start, end);
// Main loop
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
// Draw the grid
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
sf::RectangleShape rect(sf::Vector2f(50, 50));
rect.setPosition(x * 50, y * 50);
if (grid.isNodeWalkable(x, y))
{
rect.setFillColor(sf::Color::White);
}
else
{
rect.setFillColor(sf::Color::Black);
}
window.draw(rect);
}
}
// Draw the path
for (Node node : path)
{
sf::RectangleShape rect(sf::Vector2f(50, 50));
rect.setPosition(node.x * 50, node.y * 50);
rect.setFillColor(sf::Color::Green);
window.draw(rect);
}
// Draw the start and end nodes
sf::RectangleShape startRect(sf::Vector2f(50, 50));
startRect.setPosition(start.x * 50, start.y * 50);
startRect.setFillColor(sf::Color::Red);
window.draw(startRect);
sf::RectangleShape endRect(sf::Vector2f(50, 50));
endRect.setPosition(end.x * 50, end.y * 50);
endRect.setFillColor(sf::Color::Blue);
window.draw(endRect);
window.display();
}
return 0;
}
any idea why its doing this?
I've tried to debug the code and i cant seem to find the problem. Either the code doesn't run or it just shows the same thing

KDtree : bad performances when the point is far away

I have a basic KDtree implementation so far and the performance is very bad when the points are very far, i.e. if all the points are in [-10;10]^3 and the query is for example at (100, 100, 100), then the bruteforce is 20% faster than the normal version. Why?
This implementation is very basic, I know there is possible improvement everywhere, but just to make work with the minimum vital but still, it shouldn't be that slow... right?
KDTree.h
#pragma once
#include <memory>
#include <vector>
#include <cassert>
#include <vector>
#include <stdexcept>
#include <cmath>
#include <stack>
/**
* #brief K-d tree of 3D float points.
*
* #see Variable names, and algorithm inspired by https://youtu.be/TrqK-atFfWY?t=2567
*/
class KDTree
{
public:
/**** Utility structures ****/
struct Point
{
float x, y, z;
float& operator[](int i)
{
assert(i < 3 && i >= 0);
switch(i) {
case 0: return x;
case 1: return y;
case 2: return z;
}
throw std::runtime_error("Invalid index");
}
const float& operator[](int i) const
{
return const_cast<Point&>(*this)[i];
}
float distance(const Point& other) const
{
return sqrtf(distanceSquared(other));
}
float distanceSquared(const Point& other) const
{
const float dx = (x - other.x);
const float dy = (y - other.y);
const float dz = (z - other.z);
return dx*dx + dy*dy + dz*dz;
}
template<typename T> friend T& operator<<(T& lhs, const Point& rhs)
{
lhs << "(" << rhs.x << ", " << rhs.y << ", " << rhs.z << ")";
return lhs;
}
};
struct AABB
{
Point min, max;
bool inside(const Point& p) const
{
return p.x >= min.x && p.y >= min.y && p.z >= min.z
&& p.x < max.x && p.y < max.y && p.z < max.z;
}
};
public:
/**** Utility (static) functions ****/
/**
* #brief Compute the bounding box of a set of points.
* #param points
* The points to make the boudning box from.
* If the set of points is empty, the returned value is undefined.
* #return
* The bounding box of theses points.
* The bounding box will be always of minimum size, i.e. there will be a vertex on each of the 6 faces of the
* returned AABB.
*/
static AABB computeBoundingBox(const std::vector<Point> &points);
static float median(std::vector<float> vec);
static void store_min(float& current, float newValue)
{
if(current > newValue) {
current = newValue;
}
}
static void store_max(float& current, float newValue)
{
if(current < newValue) {
current = newValue;
}
}
public:
KDTree() = default;
explicit KDTree(const std::vector<Point>& points);
Point computeNearestNeighbor(const Point& pos) const;
private:
/**
* #brief Represent each node of the k-d tree.
*/
struct Node
{
/**
* #brief
* Children. Both of them or neither of them are null.
*/
std::unique_ptr<Node> left, right;
/**
* The distance between the origin and the wall to split (for left node),
* or the distance from the wall and the end to split (for right node).
*/
float splitDistance;
int splitDim;
std::vector<Point> points;
/**
* #return true if this node is a leaf node (it has no children).
*/
bool leaf() const
{
// left or right it doesn't matter
return left == nullptr;
}
};
struct SplitStack
{
int dim;
std::vector<Point> points;
Node* node;
AABB aabb;
};
private:
/**
* #brief Split the tree during the build.
* #param dim The dimension to split.
* #param points The list of remaining candidate points for this area, inside the AABB.
* #param node The node, allocated, to fill.
* #param aabb The bounding box of the node.
*/
void split(std::stack<SplitStack>& stack);
void searchRecursive(const Point& pos, Node* node, float& currentDist, Point& currentNeighbor) const;
private:
AABB m_rootAABB;
std::unique_ptr<Node> m_root;
};
KDTree.cpp
#include "KDTree.h"
#include <climits>
#include <cfloat>
#include <algorithm>
#include <iostream>
#include <cmath>
float KDTree::median(std::vector<float> vec)
{
size_t size = vec.size();
if (size == 0)
{
return 0; // Undefined, really.
}
else
{
std::sort(vec.begin(), vec.end());
if (size % 2 == 0)
{
return (vec[size / 2 - 1] + vec[size / 2]) / 2;
}
else
{
return vec[size / 2];
}
}
}
KDTree::AABB KDTree::computeBoundingBox(const std::vector<Point>& points)
{
AABB res;
if (!points.empty())
{
const auto& firstPoint = points.front();
// Initialize the bounding box to a point
for (int dim = 0; dim < 3; dim++)
{
res.min[dim] = firstPoint[dim];
res.max[dim] = firstPoint[dim];
}
// Grow the bounding box for each point if needed
for (const Point& point: points)
{
for (int dim = 0; dim < 3; dim++)
{
store_min(res.min[dim], point[dim]);
store_max(res.max[dim], point[dim]);
}
}
}
return res;
}
KDTree::KDTree(const std::vector<Point>& points)
{
m_rootAABB = computeBoundingBox(points);
m_root = std::make_unique<Node>();
std::stack<SplitStack> stack;
stack.push(SplitStack{0, points, m_root.get(), m_rootAABB});
split(stack);
}
void KDTree::split(std::stack<SplitStack>& stack)
{
// Split recursively in x, y, z, x, y, z...
// Split at the center
// dim axis -->
// 0 --------- aabb[dim].min --------------------------- aabb[dim].max --------- +inf
// ------------------|--------------------|-------------------|-------------------
// ---------------------- left node ----------- right node -----------------------
// <-----------------> <--------------->
// splitDistance: if left if right
while (!stack.empty())
{
std::vector<Point> points = std::move(stack.top().points);
Node& node = *stack.top().node;
int dim = stack.top().dim;
AABB aabb = stack.top().aabb;
stack.pop();
// Stop condition
if (points.size() > 100)
{
node.splitDim = dim;
// Absolute position in the dimension of the split
node.splitDistance = (aabb.max[dim] + aabb.min[dim]) / 2.0f;
AABB leftAABB = aabb;
leftAABB.max[dim] = node.splitDistance;
AABB rightAABB = aabb;
rightAABB.min[dim] = leftAABB.max[dim];
std::vector<Point> leftPoints, rightPoints;
for (const Point& p: points)
{
if (leftAABB.inside(p))
{
leftPoints.push_back(p);
}
else
{
rightPoints.push_back(p);
}
}
const int nextDim = (dim + 1) % 3;
node.right = std::make_unique<Node>();
stack.push(SplitStack{nextDim, std::move(rightPoints), node.right.get(), rightAABB});
node.left = std::make_unique<Node>();
stack.push(SplitStack{nextDim, std::move(leftPoints), node.left.get(), leftAABB});
}
else
{
// Leaf
node.points = std::move(points);
}
}
}
KDTree::Point KDTree::computeNearestNeighbor(const KDTree::Point& pos) const
{
// Are we left or right?
const Node *node = m_root.get();
AABB aabb = m_rootAABB;
float dist = FLT_MAX;
Point res;
searchRecursive(pos, m_root.get(), dist, res);
return res;
}
void KDTree::searchRecursive(const Point& pos, Node *node, float& currentDist, Point& currentNeighbor) const
{
// Are we on a leaf?
if (node->leaf())
{
// We are on a leaf
// Search brute force into the leaf node
for (const auto& other: node->points)
{
const float d = other.distanceSquared(pos);
if (d < currentDist)
{
currentDist = d;
currentNeighbor = other;
}
}
}
else
{
Node *front, *back;
// Are we on the left side?
if (pos[node->splitDim] < node->splitDistance)
{
// Pos is on the left side
front = node->left.get();
back = node->right.get();
}
else
{
// Pos is on the right side
front = node->right.get();
back = node->left.get();
}
searchRecursive(pos, front, currentDist, currentNeighbor);
// If the current closest point is closer than the closest point of the back face, no need to search in the back
// face because it will be always further.
// If not, we save half of the time for the current node
const float backDist = fabsf(node->splitDistance - pos[node->splitDim]);
// Do not forget all distances all squared
if (backDist * backDist <= currentDist)
{
// If it can be closer, search also in this node
searchRecursive(pos, back, currentDist, currentNeighbor);
}
}
}
main.cpp
#include <iostream>
#include <vector>
#include <random>
#include "KDTree.h"
#include "viewer.h"
#include <chrono>
class Timer {
public:
Timer(const std::string& title) : title_(title), beg_(clock_::now()) {}
~Timer() {
std::cout << title_ << " elapsed: " << elapsed() << "s" << std::endl;
}
void reset() { beg_ = clock_::now(); }
double elapsed() const {
return std::chrono::duration_cast<second_> (clock_::now() - beg_).count();
}
private:
std::string title_;
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<double, std::ratio<1> > second_;
std::chrono::time_point<clock_> beg_;
};
std::vector<KDTree::Point> randomPoints(int size, float bounds = 10.0f)
{
std::vector<KDTree::Point> points;
std::uniform_real_distribution<float> dist(-bounds, bounds);
std::mt19937 engine;
for(int i = 0; i < size; i++)
{
KDTree::Point point;
for(int dim = 0; dim < 3; dim++) {
point[dim] = dist(engine);
}
points.push_back(point);
}
return points;
}
int main()
{
auto points = randomPoints(1'000'000);
for(int i = 0; i < points.size(); i++) {
auto& point = points[i];
}
auto aabb = KDTree::computeBoundingBox(points);
KDTree kdtree;
{
Timer timer("KDTree build");
kdtree = KDTree(points);
}
{
const int N = 1'000;
auto testPts = randomPoints(N, 100.0f);
std::vector<KDTree::Point> resKD(N), resBrute(N);
{
Timer timer("KDTree");
for(int i = 0; i < testPts.size(); i++) {
resKD[i] = kdtree.computeNearestNeighbor(testPts[i]);
}
}
{
Timer timer("Bruteforce");
for(int i = 0; i < testPts.size(); i++) {
const auto& test = testPts[i];
// Brute force
KDTree::Point cur;
float curDist = FLT_MAX;
for(const auto& brute : points) {
if(brute.distanceSquared(test) < curDist) {
curDist = brute.distanceSquared(test);
cur = brute;
}
}
resBrute[i] = cur;
}
}
{
float delta = 0.0f;
for(int i = 0; i < N; i++) {
delta += resKD[i].x - resBrute[i].x;
delta += resKD[i].y - resBrute[i].y;
delta += resKD[i].z - resBrute[i].z;
}
std::cout << "delta = " << delta << std::endl;
}
}
return 0;
}
Output:
KDTree build elapsed: 0.190593s
KDTree elapsed: 2.69598s
Bruteforce elapsed: 2.34136s
delta = 0
When I lower to randomPoints(N, 10.0f):
KDTree build elapsed: 0.195519s
KDTree elapsed: 0.000914431s
Bruteforce elapsed: 2.35679s
delta = 0
As written on wikipedia:
Additionally, even in low-dimensional space, if the average pairwise distance between the k nearest neighbors of the query point is significantly less than the average distance between the query point and each of the k nearest neighbors, the performance of nearest neighbor search degrades towards linear, since the distances from the query point to each nearest neighbor are of similar magnitude. (In the worst case, consider a cloud of points distributed on the surface of a sphere centered at the origin. Every point is equidistant from the origin, so a search for the nearest neighbor from the origin would have to iterate through all points on the surface of the sphere to identify the nearest neighbor – which in this case is not even unique.)
So this is normal to see performance decrease in a KD Tree when the points are far.

C++, initialize a 2d array. error:subscript requires array or pointer

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

SFML: Exception thrown at 0x7767FF05 (ntdll.dll) in Demo.exe: 0xC0000005: Access violation writing location 0x00000004

I got a code on github. After I debug it, it gives me an error as shown belowI got a code on github. After I debug it, it gives me an error as shown: Exception thrown at 0x7767FF05 (ntdll.dll) in Demo.exe: 0xC0000005: Access violation writing location 0x00000004.
[img]https://i.imgur.com/y8QG7vk.png[/img]
Here is my code:
#include <iostream>
#include <math.h>
#include <algorithm>
#include <SFML/Graphics.hpp>
#define SFML_NO_DEPRECATED_WARNINGS
#pragma warning(suppress : 4996)
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
using namespace sf;
const int window_w = 1920;
const int window_h = 1080;
float wid = 1920;
int hei = 1080;
float wid_n = 1920;
float hei_n = 1080;
const int l_size = 80;
const int r_size = 30;
const int h_size = 100;
float speed = 50;
float del = 0;
const int scale = 1;
RenderWindow window(VideoMode(window_w, window_h), "AVL Tree");
Font font;
View view;
struct Node {
int c;
Node* l, * r;
int h;
Node(int cc) :c(cc), h(1), l(NULL), r(NULL) {}
};
typedef Node* Tree;
int get_h(Tree t) {
if (!t)return 0;
return t->h;
}
int balancefact(Tree t) {
if (!t)return 0;
return get_h(t->r) - get_h(t->l);
}
void update(Tree t) {
if (!t)return;
t->h = max(get_h(t->l), get_h(t->r)) + 1;
}
Tree rot_right(Tree t) {
Tree q = t->l;
t->l = q->r;
q->r = t;
update(t);
update(q);
return q;
}
Tree rot_left(Tree t) {
Tree q = t->r;
t->r = q->l;
q->l = t;
update(t);
update(q);
return q;
}
Tree balance(Tree t) {
if (!t)return t;
update(t);
if (balancefact(t) == 2) {
if (balancefact(t->r) < 0)
t->r = rot_right(t->r);
return rot_left(t);
}
if (balancefact(t) == -2) {
if (balancefact(t->l) > 0)
t->l = rot_left(t->l);
return rot_right(t);
}
return t;
}
Tree add(int c, Tree t) {
if (!t) {
t = new Node(c);
return t;
}
if (t->c == c)return t;
if (t->c > c) {
t->r = add(c, t->r);
}
else {
t->l = add(c, t->l);
}
return balance(t);
}
Tree get_min(Tree t) {
if (!t->l)return t;
return get_min(t->l);
}
Tree erase(int c, Tree t) {
if (!t)return t;
if (t->c > c) {
t->r = erase(c, t->r);
}
else if (t->c < c) {
t->l = erase(c, t->l);
}
else if (t->l && t->r) {
t->c = get_min(t->r)->c;
t->r = erase(t->c, t->r);
}
else if (t->l)
t = t->l;
else
t = t->r;
return balance(t);
}
void draw(int x, int y, int c) {
CircleShape cir;
Text text;
text.setFont(font);
cir.setOrigin(Vector2f(r_size, r_size));
cir.setRadius(r_size);
cir.setOutlineColor(Color::Blue);
cir.setOutlineThickness(3);
text.setCharacterSize(144);
text.setString(to_string(c));
text.setOrigin(text.getLocalBounds().left + text.getLocalBounds().width / 2,
text.getLocalBounds().top + text.getLocalBounds().height / 2);
float min_size = min((r_size * 1.5f) / text.getLocalBounds().width, (r_size * 1.5f / 2) / text.getLocalBounds().height);
text.setScale(Vector2f(min_size, min_size));
cir.setPosition(x, y);
text.setPosition(Vector2f(x, y));
text.setFillColor(Color::Black);
window.draw(cir);
window.draw(text);
}
void draw_edg(int x1, int y1, int x2, int y2) {
if (x1 == 0 && y1 == 0)return;
RectangleShape line(Vector2f(sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)), 6));
line.setFillColor(Color::Cyan);
line.setPosition(Vector2f(x1, y1));
line.rotate(atan2(y2 - y1, x2 - x1) * 180.0 / atan2(0, -1));
window.draw(line);
}
int get(Tree t, int l, int h) {
if (!t)return 0;
int r = l;
if (t->l)
r = get(t->l, l, h - 1);
else
r += l_size * scale;
if (t->r)
r = get(t->r, r, h - 1);
else
r += l_size * scale;
if (!t->l && !t->r)
r += l_size;
int x_cor = l + (r - l) / 2;
int y_cor = h * h_size;
draw(x_cor, y_cor, t->c);
return r;
}
pair<int, pair<int, int>> get_edg(Tree t, int l, int h) {
if (!t)return make_pair(0, make_pair(0, 0));
int r = l;
pair<int, int> left = make_pair(0, 0);
pair<int, int> right = make_pair(0, 0);
if (t->l) {
pair<int, pair<int, int>> res = get_edg(t->l, l, h - 1);
r = res.first;
left = res.second;
}
else
r += l_size * scale;
if (t->r) {
pair<int, pair<int, int>> res = get_edg(t->r, r, h - 1);
r = res.first;
right = res.second;
}
else
r += l_size * scale;
if (!t->l && !t->r)
r += l_size;
int x_cor = l + (r - l) / 2;
int y_cor = h * h_size;
draw_edg(left.first, left.second, x_cor, y_cor);
draw_edg(right.first, right.second, x_cor, y_cor);
return make_pair(r, make_pair(x_cor, y_cor));
}
int main() {
view.reset(FloatRect(0, 0, window_w, window_h));
srand(time(NULL));
Tree t = 0;
Clock clock;
font.loadFromFile("CyrilicOld.TTF");
bool change = true;
int tim = 0;
int kadr = 0;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event) || change) {
float del_tim = clock.getElapsedTime().asMicroseconds();
del = del_tim / 4e4;
clock.restart();
tim += del_tim;
kadr++;
if (tim > 1e6) {
tim -= 1e6;
// cout << kadr << endl;
kadr = 0;
}
if (event.type == Event::Closed || Keyboard::isKeyPressed(Keyboard::Escape)) {
window.close();
}
if (Keyboard::isKeyPressed(Keyboard::Dash)) {
view.zoom(1.03f);
speed = speed * 1.03f;
wid = wid * 1.03f;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Equal)) {
view.zoom(0.97f);
speed = speed * 0.97f;
wid = wid * 0.97f;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Left)) {
view.move(Vector2f(-speed * del, 0));
wid += speed * del;
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Down)) {
view.move(Vector2f(0, speed * del));
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Up)) {
view.move(Vector2f(0, -speed * del));
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::Right)) {
view.move(Vector2f(speed * del, 0));
wid += speed * del;
change = true;
}
if (Mouse::isButtonPressed(Mouse::Left)) {
for (int i = 0; i < 10; i++) {
int key = rand() - rand();
t = add(key, t);
}
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::A)) {
int key;
cin >> key;
t = add(key, t);
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::E)) {
int key;
cin >> key;
t = erase(key, t);
change = true;
}
if (Keyboard::isKeyPressed(Keyboard::N)) {
view.zoom(wid_n / wid);
speed *= wid_n / wid;
wid = wid_n;
}
if (change) {
window.setView(view);
window.clear(Color(128, 106, 89));
get_edg(t, 0, get_h(t));
wid_n = get(t, 0, get_h(t));
hei_n = get_h(t) * h_size;
//change = false;
window.display();
}
}
}
return 0;
}
You initialize your RenderWindow object as a global variable. This happens before the start of your program, but there's no fixed order between different global variables. You probably get an error because other variables need to be initialized before you can create RenderWindow objects.
In this case, the program tries to write into the address 0x00000004. A global pointer that RenderWindow needs, probably still points to zero and not to a valid memory location. Thus the program crashes.
This problem is often referred to as the Static Initialization Order Fiasco.
The solution in this case is to only initialize window after main() starts. A possible way to do this is to use std::optional:
std::optional<RenderWindow> window = std::nullopt;
//...
int main() {
window = RenderWindow(VideoMode(window_w, window_h), "AVL Tree");
//...
}
You can also use a singleton if you'd like to initialize window more implicitly. Personally, I like to use the Meyers singleton in those cases:
auto get_window() {
static RenderWindow window(VideoMode(window_w, window_h), "AVL Tree");
return window;
}

Invalid use of incomplete type "class"

I know there has been tons of questions like that, but unfortunately after hours of googling and browsing through all of them, none of the answers I read helped. Therefore I am making my own version of my question. The error message I get is: "error: invalid use of incomplete type ‘std::iterator_traits::value_type {aka class Cell}’" My code:
cell.h
#ifndef CELL_H
#define CELL_H
#include <QPushButton>
#include <QMouseEvent>
#include <vector>
class Padding;
class Cell : public QPushButton
{
Q_OBJECT
public:
friend class Padding;
Cell(int x, int y, Padding* padding, QWidget* parent = 0) : QPushButton(parent), x(x), y(y),
padding(padding)
{
setFixedSize(20, 20);
}
Cell(const Cell& object) : QPushButton(), x(object.x), y(object.y), padding(object.padding)
{
setFixedSize(20, 20);
}
int getX() { return x; };
int getY() { return y; };
bool hasMine() { return mine; };
void setHasMine(bool mine) { this -> mine = mine; };
bool isFlagged() { return flagged; };
bool didExplode() { return exploded; };
bool getHasBeenClicked() { return hasBeenClicked; };
void clicked();
~Cell() {};
Cell operator=(const Cell& object)
{
if(&object == this)
{
return *this;
}
padding = object.padding;
x = object.x;
y = object.y;
mine = object.mine;
flagged = object.flagged;
exploded = object.exploded;
hasBeenClicked = object.hasBeenClicked;
setFixedSize(20, 20);
return *this;
}
private:
Padding* padding;
int x;
int y;
bool mine = false;
bool flagged = false;
bool exploded = false;
bool hasBeenClicked = false;
void mousePressEvent(QMouseEvent* e);
void rightClicked();
};
#endif // CELL_H
cell.cpp
#include "cell.h"
#include "padding.h"
void Cell::mousePressEvent(QMouseEvent* event)
{
if(event -> button() == Qt::LeftButton)
{
clicked();
}
else if(event -> button() == Qt::RightButton)
{
rightClicked();
}
}
void Cell::clicked()
{
hasBeenClicked = true;
// TODO: Set the button frame to flat. DONE.
setFlat(true);
// TODO: Make the button not click able. DONE.
setEnabled(false);
// TODO: Display appropriate number on the button, or mine and end the game. DONE.
if(mine)
{
// TODO: Send game over signal and end the game.
//setIcon(QIcon("mine_clicked.png"));
setText("/");
exploded = true;
padding -> gameOver();
}
else
{
setText(QString::number(padding -> countMinesAround(this)));
}
if(padding -> countMinesAround(this) == 0)
{
// Trigger chain reaction; uncover many neighboring cells, if they are not mines.
padding -> triggerChainReactionAround(this);
}
}
void Cell::rightClicked()
{
if(text() != "f")
{
setText("f");
(padding -> minesLeft)--;
}
else
{
setText("");
(padding -> minesLeft)++;
}
flagged = !flagged;
}
padding.h
#ifndef PADDING_H
#define PADDING_H
#include <QWidget>
#include <QGridLayout>
#include <vector>
class Cell;
class Padding : public QWidget
{
Q_OBJECT
public:
friend class Cell;
enum class Difficulty
{
Beginner,
Intermediate,
Advanced,
Custom
};
Padding(QWidget* parent = 0);
void newGame();
void gameOver();
void setLevel(Padding::Difficulty difficulty) { this -> difficulty = difficulty; };
void setPaddingHeight(int height) { paddingHeight = height; };
void setPaddingWidth(int width) { paddingWidth = width; };
void setMines(int mines) { this -> mines = mines; };
int getMinesLeft() { return minesLeft; };
~Padding() {};
private:
struct DifficultyLevelsProperties
{
struct BeginnerProperties
{
const int PADDING_HEIGHT = 9;
const int PADDING_WIDTH = 9;
const int MINES = 10;
} Beginner;
struct IntermediateProperties
{
const int PADDING_HEIGHT = 16;
const int PADDING_WIDTH = 16;
const int MINES = 40;
} Intermediate;
struct AdvancedProperties
{
const int PADDING_HEIGHT = 16;
const int PADDING_WIDTH = 40;
const int MINES = 99;
} Advanced;
} LevelProperties;
Difficulty difficulty = Difficulty::Beginner;
int paddingHeight;
int paddingWidth;
int mines;
// Mines that are not flagged.
int minesLeft;
// Time in seconds since the game was started.
int secondsSinceStart;
std::vector<Cell> cells;
QGridLayout* paddingLayout;
const int CELLS_HEIGHT = 20;
const int CELLS_WIDTH = 20;
int countMinesAround(Cell*);
void triggerChainReactionAround(Cell*);
void updateSecondsSinceStart();
};
#endif // PADDING_H
padding.cpp
#include "padding.h"
#include <QGridLayout>
#include <QTimer>
#include <QTime>
#include <QDebug>
#include "cell.h"
Padding::Padding(QWidget* parent) : QWidget(parent)
{
newGame();
paddingLayout = new QGridLayout(this);
paddingLayout -> setSpacing(0);
}
void Padding::newGame()
{
if(difficulty == Padding::Difficulty::Beginner)
{
paddingHeight = LevelProperties.Beginner.PADDING_HEIGHT;
paddingWidth = LevelProperties.Beginner.PADDING_WIDTH;
mines = LevelProperties.Beginner.MINES;
}
else if(difficulty == Padding::Difficulty::Intermediate)
{
paddingHeight = LevelProperties.Intermediate.PADDING_HEIGHT;
paddingWidth = LevelProperties.Intermediate.PADDING_WIDTH;
mines = LevelProperties.Intermediate.MINES;
}
else if(difficulty == Padding::Difficulty::Advanced)
{
paddingHeight = LevelProperties.Advanced.PADDING_HEIGHT;
paddingWidth = LevelProperties.Advanced.PADDING_WIDTH;
mines = LevelProperties.Advanced.MINES;
}
minesLeft = mines;
cells.clear();
for(int i = 0; i < paddingHeight; i++)
{
for(int j = 0; j < paddingWidth; j++)
{
// TODO: Use smart pointers instead of raw pointers.
Cell* cell = new Cell(j + 1, i + 1, this);
cells.push_back(*cell);
delete cell;
}
}
qsrand(QTime::currentTime().msec());
for(int i = 0; i < mines; i++)
{
// TODO: Fix the randomness of the numbers. DONE.
cells[qrand() % (paddingHeight * paddingWidth) + 1].setHasMine(true);
}
for(int i = 0; i < cells.size(); i++)
{
paddingLayout -> addWidget(&cells[i], cells[i].getY(), cells[i].getX());
}
}
void Padding::gameOver()
{
for(int i = 0; i < cells.size(); i++)
{
cells[i].setEnabled(false);
if((cells[i].hasMine()) && (!cells[i].getHasBeenClicked()))
{
cells[i].clicked();
}
}
}
int Padding::countMinesAround(Cell*)
{
int minesCounter = 0;
for(int i = 0; i < cells.size(); i++)
{
qDebug() << QString::number(cells[i].getX());
if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
(cells[i].hasMine()))
{
minesCounter++;
}
}
return minesCounter;
}
void Padding::triggerChainReactionAround(Cell*)
{
for(int i = 0; i < cells.size(); i++)
{
if(((x - cells[i].getX() == 0) || (x - cells[i].getX() == 1) || (x -
cells[i].getX() == -1)) && ((y - cells[i].getY() == 0) || (y -
cells[i].getY() == 1) || (y - cells[i].getY() == -1)) &&
(!cells[i].getHasBeenClicked()))
{
cells[i].clicked();
}
}
}
Sorry for how long the whole thing, but I could not shorten it as I can't locate what causes the error. Also please ignore any TODO's or any lines that are commented out and I forgot to delete them. Please help!
When you forward declare a type, you can only use pointers or references to that type objects, so this line in padding.h is pretty much not compiling:
std::vector<Cell> cells;
I suppose the compiler complaint comes from where it is trying to decide how to build/destroy a Cell object in a vector. To do that, it needs information about the type, generally from the type declaration (i.e. the header file).