Im currently looking to turn something like this:
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............
into this:
.............
.............
..XXX.....O..
..XXX.....O..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
.............
with the user entering ./a.exe input4.txt floodfill 2 10 o
I believe im going to need to implement some recursion into the program to be able to only look at indexes that match that of the user pointer (including positions of up, down, left, and right) instead of reading the entire vector (which i wouldn't mind doing but dont see how i would begin doing so).
here is the code I have so far for the flood fill function:
void floodfilll(vector<vector<char>> &vec, int x, int y, char r, char dum)
{
int ii;
ii = 0;
int jj;
jj = 0;
for (int i = 0; i < vec.size(); i ++) {
for (int j = 0; j < vec[i].size(); j++) {
if (vec[i][j] == r) {
vec[i][j] == r;
if ((i + ii) > 0) {
if (vec[i-1][j] == r)
vec[i-1][j] = dum;
vec[i][j] == r;
ii--;
floodfilll(vec, x + ii, y, r, dum);
}
if ((j + jj) > 0) {
if(vec[i][j-1] != r)
vec[i][j-1] = dum;
vec[i][j] == r;
jj--;
floodfilll(vec, x, y + jj, r, dum);
}
if ((i + ii)<vec.size()) {
if (vec[i+1][j] != r)
vec[i+1][j] = dum;
vec[i][j] == r;
ii++;
floodfilll(vec, x + ii, y, r, dum);
}
if ((j + jj)<vec[i].size()) {
if (vec[i][j+1] != r)
vec[i][j+1] = dum;
vec[i][j] == r;
jj++;
floodfilll(vec, x, y + jj, r, dum);
}
}
}
replacee(vec, dum, r);
}
}
NOTE: Im using a function called replacee to replace Var dum, with Var R. Var dum is assigned 'i' and r is 'X'.
Also, the text file is parsed as a 2d vector of char's (char)**
Its just the way the rest of my program is based. Here is the replace function:
void replacee(vector<vector<char>> &vec, char oldd, char neww)
{
for (vector<char> &v : vec) // reference to innver vector
{
replace(v.begin(), v.end(), oldd, neww); // standard library algorithm
}
}
This is the int main file im using:
int main(int argc, char* argv[]) {
fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitary file.
string argument2 (argv[2]);
while(fin)
{
ch = fin.get();
if(ch!='\n') {
temp.push_back(ch);
}
else
{
data.push_back(temp);
temp.clear();
}
}
if (argument2 == "floodfill") {
string argument3 (argv[3]);
string argument4 (argv[4]);
string argument5 (argv[5]);
int x = 0;
int y = 0;
stringstream xx(argument3);
stringstream yy(argument4);
xx >> x;
yy >> y;
floodfilll(data, x, y, argument5[0], 'i');
for (int m = 0; m < data.size(); m ++) {
for (int n = 0; n < data[m].size(); n++) {
cout << data[m][n];
}
cout << endl;
}
}
fin.close();
}
Sorry if it looks like im just pasting code for grabs, this is incase anyone has a solution outside my mode of thought. The int main and replacee functions work as intended. I just need help coming up with a way to make floodfilll work correctly.
This is the output i get with my code:
$ ./a.exe input4.txt floodfill 2 10 o
.............
.............
..XXX.....X..
..XXX.....X..
..XXX........
..XXX........
..XXXXXXX....
..XXXXXXX....
..XXXXXXX....
.............
Why do you iterate over the whole field in each recursion?
Normally, flood filling works as follows:
You have a specific starting point.
You fill this starting point with the colour intended
You check for each of the four (or 8, if you consider diagonals as well) neighbours, if they have the same colour as the starting point originally had; if so, you continue with recursively.
So an implementation might look like this:
void floodfill
(
std::vector<std::vector<char>>& v,
unsigned int x, unsigned int y, char r
)
{
char p = v[x][y];
v[x][y] = r;
if(x > 0 && v[x - 1][y] == p)
floodfill(v, x - 1, y, r);
if(x + 1 < v.size() && v[x + 1][y] == p)
floodfill(v, x + 1, y, r);
if(y > 0 && v[x][y - 1] == p)
floodfill(v, x, y - 1, r);
if(y + 1 < v[x].size() && v[x][y + 1] == p)
floodfill(v, x, y + 1, r);
}
Note that I did not check for the case of colour to fill being the same as the one of the starting pixel, neither did I initially check the range check of x and y. For efficiency, I wouldn't add these checks in the recursive function, but in a specific entry function starting the recursion, so they are done only once when needed and not needlessly repeated.
One option is to use recursion, as suggested by the other answer. However, personally I prefer avoiding recursion where it is not necessary. An alternative, is a queue-based approach.
void floodfill (std::vector<std::vector<char>>& v, unsigned int x, unsigned int y, char r) {
char init = v[x][y];
if (init == r) return; //We don't want to get caught in an endless loop.
if (x >= v.size() || y >= v[x].size) return; //Index out of bounds.
std::queue<std::pair<unsigned int, unsigned int>> q;
q.push(std::make_pair(x, y)); //Push the initial position into the queue.
v[x][y] = r; //Replace the initial point.
while (!q.empty()) {//Keep looking at relevant neighbours so long as there is something in the queue.
auto pt = q.front(); //Collect the first entry.
q.pop(); //Remove it, we don't want to keep processing the same point.
//Now add neighbours if they match our initial point.
if(pt.first > 0 && v[pt.first - 1][pt.second] == init)
q.push(std::make_pair(pt.first - 1, pt.second);
v[pt.first - 1][pt.second] = r; //Replace the value here to avoid pushing the same point twice.
if(pt.first + 1 < v.size() && v[pt.first + 1][pt.second] == init)
q.push(std::make_pair(pt.first + 1, pt.second);
v[pt.first + 1][pt.second] = r;
if(pt.second > 0 && v[pt.first][pt.second - 1] == init)
q.push(std::make_pair(pt.first, pt.second - 1);
v[pt.first][pt.second - 1] = r;
if(pt.second + 1 < v[pt.first].size() && v[pt.first][pt.second + 1] == init)
q.push(std::make_pair(pt.first, pt.second + 1);
v[pt.first][pt.second + 1] = r;
}
}
This gives you a BFS-like flood-fill pattern without recursion. Alternatively you could also use a stack instead of the queue, then the flood-fill would behave more like a DFS (much more similar to what the recursive pattern will do). It might even perform a little better than the queue, given the data structure is a little simpler.
Related
How do i pass array b1 in the function dfs, b1 is a 2D integer array used to track whether the node was visited. Sorry for the poor code readability. i want to pass it by reference as it needs to be modified by the function called recursively.Currently getting this error.
Line 33: Char 94: error: 'b1' declared as array of references of type 'int &'
void dfs(int i,int j,vector<vector<char>>& board,string word,int k,bool& yellow,int& b1[][]){
^
1 error generated.
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
int m = board.size();
int n = board[0].size();
int b1[m][n];
list<pair<int,int>> mp;
bool yellow=false;
for(int i=0;i<board.size();i++){
for(int j=0;j<board[0].size();j++){
if(board[i][j]==word[0]){
mp.push_front({i,j});
}
}
}
for(auto itr=mp.begin();itr!=mp.end();itr++){
int i=itr->first;
int j=itr->second;
dfs(i,j,board,word,0,yellow,b1);
if(yellow==true){
return yellow;
}
memset(b1,0,sizeof(b1));
}
return yellow;
}
void dfs(int i,int j,vector<vector<char>>& board,string word,int k,bool& yellow,int& b1[][]){
int m = board.size()-1;
int n = board[0].size()-1;
b1[i][j]=1;
if(k==word.size()-1){
yellow=true;
}
if(i+1<=m && board[i+1][j]==word[k+1] &&b1[i+1][j]==0){
dfs(i+1,j,board,word,k+1,yellow,b1);
}
if(i-1>=0 && board[i-1][j]==word[k+1] &&b1[i-1][j]==0){
dfs(i-1,j,board,word,k+1,yellow,b1);
}
if(j+1<=n && board[i][j+1]==word[k+1]&& b1[i][j+1]==0){
dfs(i,j+1,board,word,k+1,yellow,b1);
}
if(j-1>=0 && board[i][j-1]==word[k+1] && b1[i][j-1]==0){
dfs(i,j-1,board,word,k+1,yellow,b1);
}
}
};
Since you already use vector<vector<char>>& board as one parameter, the simplest way to fix this error is to use vector<vector<int>> b1 instead of int b1[m][n].
Please take care of VLAs like int a[n][m], it's not easy to maintain and also not recommended. See more at Why aren't variable-length arrays part of the C++ standard?.
Here is my example to replace your b1 with a 2D vector.
class Solution {
public:
bool exist(vector<vector<char>> &board, string word) {
int m = board.size();
int n = board[0].size();
// int b1[m][n];
vector<vector<int>> b1(m, vector<int>(n, 0));
list<pair<int, int>> mp;
bool yellow = false;
for (int i = 0; i < board.size(); i++) {
for (int j = 0; j < board[0].size(); j++) {
if (board[i][j] == word[0]) {
mp.push_front({i, j});
}
}
}
for (auto itr = mp.begin(); itr != mp.end(); itr++) {
int i = itr->first;
int j = itr->second;
dfs(i, j, board, word, 0, yellow, b1);
if (yellow == true) {
return yellow;
}
// memset(b1, 0, sizeof(b1));
for (auto &row: b1) {
std::fill(row.begin(), row.end(), 0);
}
}
return yellow;
}
// void dfs(int i,int j,vector<vector<char>>& board,string word,int k,bool& yellow,int& b1[][]){
void dfs(int i, int j, vector<vector<char>> &board, string word, int k, bool &yellow, vector<vector<int>> &b1) {
int m = board.size() - 1;
int n = board[0].size() - 1;
b1[i][j] = 1;
if (k == word.size() - 1) {
yellow = true;
}
if (i + 1 <= m && board[i + 1][j] == word[k + 1] && b1[i + 1][j] == 0) {
dfs(i + 1, j, board, word, k + 1, yellow, b1);
}
if (i - 1 >= 0 && board[i - 1][j] == word[k + 1] && b1[i - 1][j] == 0) {
dfs(i - 1, j, board, word, k + 1, yellow, b1);
}
if (j + 1 <= n && board[i][j + 1] == word[k + 1] && b1[i][j + 1] == 0) {
dfs(i, j + 1, board, word, k + 1, yellow, b1);
}
if (j - 1 >= 0 && board[i][j - 1] == word[k + 1] && b1[i][j - 1] == 0) {
dfs(i, j - 1, board, word, k + 1, yellow, b1);
}
}
};
Are you moving from GNU to a more strict C++ compiler?
GNU historically allows passing 2D arrays with run-time variable dimensions. Don't remember the exact syntax, you may need to declare M,N as parameters so that compiler knows where are dimensions coming from.
It's an old FORTRAN trick and there were a lot of requests that C++ should have it as well so GNU did it on it's own (they also have FORTRAN compiler so it was also the matter of interoperability). C99 standard also changed to allow it => C++ is a solitary lame duck now.
If you actually are on GNU, dig around a bit how to declare it but keep in mind that it won't build on other C++ flavors.
Oh and you don't need an array of references to int. Array is always (implicit/hidden) pointer (aka reference). The whole reference frenzy came from arrays being historically "privileged" as pointers accessible without *. Keep in mind that reference is self-dereferencing pointer => you just declared an array of pointers - hidden :-)
When normal references are declared in the same scope with their usage compiler knows how to optimize out the hidden pointer aspect but if you cross a function call boundary they have to go as pointers. If you hide them in array compiler has to give up - but it has full right to scream since array of references is conceptual nonsense and you wouldn't be to initialize them => they would all be null bombs if compiler would allow them.
NB: In C++20 you can "reassign" a reference but not explicitly - only as a part of a larger object's self-mut(il)ation (don't try at home :-).
So there is a list of points (x1,y1,z1),(x2,y2,z2),...(xn,yn,zn).
You can perform an operation O on any number of these points.
Operation O results in (x,y,z)= (max(x1,x2,...xn),max(y1,y2,...yn),max(z1,z2,...zn)).
Given (x,y,z), you need to determine whether it is possible to perform operation O on some of the points in the list to get (x,y,z) as a result.
For eg: You are given points(1,2,1),(3,1,4),(5,2,1).
Can you perform O operation to get 1) (3,2,1) 2) (1,1,1)
First line contains n and q i.e the number of points and no. of queries
Next n lines contain the n points space seperated
Next q lines contain the q points which are the queries
1<=q<=10^5
1<=n<=10^5
x,y,z are integers
Input:
2 2
1 3 5
5 3 1
5 3 5
3 3 3
Expected Output:
YES
NO
My logic:
for (int i = 0; i < q; i++)
{
cin>>x>>y>>z;
for (int j = 0; j < n; j++)
{
if(arr[j][0]==x && arr[j][1]<=y && arr[j][2]<=z)
first=1;
if(arr[j][0]<=x && arr[j][1]==y && arr[j][2]<=z)
second=1;
if(arr[j][0]<=x && arr[j][1]<=y && arr[j][2]==z)
third=1;
if(first+second+third==3)
break;
}
if(first+second+third==3)
cout<<"YES\n";
else
{
cout<<"NO\n";
}
first=0;
second=0;
third=0;
}
Note: Here arr[][] contains the given coordinates.
for every x y z in queries q I am performing this operation.
Few test cases are failing giving me a runtime error (Time limit Exceeded). Is there a better way to do this.
Your solution is correct but slow, has O(q * n) complexity which is 10^10 at maximum, too much.
I've solved your task using sorting plus merging search, which has O(n log n + q log q) complexity.
The algorithm is as follows:
For each of three cases, (x, y, z), (y, x, z), (z, x, y), signified as coordinates (i0, i1, i2), we do next:
Sort all points and queries by tuple (i0, i1, i2).
Among each equal coordinates i0 compute cumulative minimum of i2.
Merge sorted points and queries next way: For each range of queries and points with equal i0 and i1 take rightmost minimal i2. If such minimal i2 for point is greater than query's i2 then answer for this query is NO, otherwise is probably YES (probably meaning that it should be YES for all 3 orderings of (x, y, z)/(y, x, z)/(z, x, y)).
Basically algorithm above does same thing as your algorithm does, it finds point with equal x, y, or z so that other two coordinates are not greater. But does it through fast algorithm of merging two sorted arrays. So that merging itself takes just O(q + n) time, while whole algorithm time is dominated by sorting algorithms taking O(q log q + n log n) time.
Try it online!
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
typedef int CoordT;
typedef tuple<CoordT, CoordT, CoordT> CoordsT;
typedef vector<CoordsT> CoordsVecT;
template <size_t i0, size_t i1, size_t i2>
static void Solve(CoordsVecT const & ps, CoordsVecT const & qs, vector<bool> & yes) {
auto Prep = [&](auto & s, auto const & o){
s.clear();
s.reserve(o.size());
for (size_t i = 0; i < o.size(); ++i)
s.push_back(make_tuple(get<0>(o[i]), get<1>(o[i]), get<2>(o[i]), i));
sort(s.begin(), s.end(), [](auto const & l, auto const & r) -> bool {
return get<i0>(l) < get<i0>(r) || get<i0>(l) == get<i0>(r) && (
get<i1>(l) < get<i1>(r) || get<i1>(l) == get<i1>(r) &&
get<i2>(l) < get<i2>(r)
);
});
};
vector< tuple<CoordT, CoordT, CoordT, size_t> > sps, sqs;
Prep(sps, ps);
Prep(sqs, qs);
vector<CoordT> mins2(sps.size());
CoordT cmin2 = 0;
for (size_t i = 0; i < sps.size(); ++i) {
if (i == 0 || get<i0>(sps[i - 1]) != get<i0>(sps[i]))
cmin2 = get<i2>(sps[i]);
cmin2 = std::min(cmin2, get<i2>(sps[i]));
mins2[i] = cmin2;
}
for (size_t iq = 0, ip = 0; iq < sqs.size(); ++iq) {
auto & cyes = yes[get<3>(sqs[iq])];
if (!cyes)
continue;
while (ip < sps.size() && get<0>(sps[ip]) < get<0>(sqs[iq]))
++ip;
if (ip >= sps.size() || get<0>(sps[ip]) != get<0>(sqs[iq])) {
cyes = false;
continue;
}
while (ip + 1 < sps.size() && get<0>(sps[ip + 1]) == get<0>(sqs[iq]) && get<1>(sps[ip + 1]) <= get<1>(sqs[iq]))
++ip;
if (ip >= sps.size() || get<1>(sps[ip]) > get<1>(sqs[iq]) || mins2[ip] > get<2>(sqs[iq])) {
cyes = false;
continue;
}
}
}
int main() {
size_t n = 0, q = 0;
cin >> n >> q;
auto Input = [](CoordsVecT & v, size_t cnt) {
v.reserve(v.size() + cnt);
for (size_t i = 0; i < cnt; ++i) {
CoordT x, y, z;
cin >> x >> y >> z;
v.push_back(make_tuple(x, y, z));
}
};
CoordsVecT ps, qs;
Input(ps, n);
Input(qs, q);
vector<bool> yes(qs.size(), true);
Solve<0, 1, 2>(ps, qs, yes);
Solve<1, 0, 2>(ps, qs, yes);
Solve<2, 0, 1>(ps, qs, yes);
for (size_t i = 0; i < qs.size(); ++i)
cout << (yes[i] ? "YES" : "NO") << endl;
return 0;
}
Input:
2 2
1 3 5
5 3 1
5 3 5
3 3 3
Output:
YES
NO
Basically i want to write a function that takes values from 0 to 6 and gives back a random assortment such as 2,3,4,5,0,1,6. Here is the code that i came up with. However the problem is that the integer prev (meaning previous) does not store all the old values of r (random number) and thus some values end up being repeated. How might i fix this?
int s(int b)
{
// b is 7
int h = b-1;
int prev = -1;// to store the previous r value
srand(time(0));
for (int i = 0; i < b; i++)
{
int r = rand()%(h - 0 + 1) + 0;
if (r != prev)
{
cout << r << endl;
prev = r;
}
else if (r == prev)
{
s(b);
}
}
return 0;
}
From the comments, this sounds more like a homework problem than a practical problem because you said "No arrays allowed". But I suppose it is an interesting problem.
Here's some code, in Java with only loops, if statements, and with no arrays, as required.
It outputs a random permutation of the set 0, 1, ..., N, shuffled with the Fisher-Yates algorithm.
void printRandom(int N) {
long used = 0;
for (int i = 0; i < N; i++) {
int randomIndex = ThreadLocalRandom.current().nextInt(N - Long.bitCount(used));
for (int j = 0; j < N; j++) {
if ((used & (1L << j)) == 0) {
if (randomIndex-- == 0) {
System.out.print(j + " ");
used = used | (1L << j);
break;
}
}
}
}
}
It is unfortunately limited to the size of a long on your system :)
I think the best way to solve this problem is by using an aux funtion that stores in a variable all the numbers printed until the moment, check if the new number is in the used numbers variable, if not add it to the variable (you can use strings? I know that they are arrays of char's but maybe you can)
Something like this:
function aux(int b, char *variables_printed, int iterations_left)
if (b = 0) then print variables_printed
else
int n = generate_random_number() %b
while (n in variables_printed)
n= (n+random_number) % b
variables_printed += n
aux(b, variables_printed, iterations_left-1)
And your other function:
function s(b)
if b < 0 return 0
else
char *variables_to_print
aux(b, variables_to_print, b)
If you can not use strings, you can do it with long as konsolas said.
I have the following recursive code which I want to change to iterative code. I am unsure of where to begin as the function is very complex with recursive calls at two locations. Any possible iterative implementations to the below function ?
int ncip(int dim, double R){
int n, r = (int)floor(R);
if (dim == 1)
return 1 + 2*r;
n = ncip(dim-1, R); // last coord 0
for (int i=1; i<=r; ++i){
n += 2*ncip(dim-1, sqrt(R*R - i*i) ); // last coord +- i
}
return n;
}
One common approach is to use a stack for the function calls. A simple implementation would be as follows and you can do some optimization on it
int ncip(int dim, double R){
typedef pair<int, double> data; // ties parameters into one unit
stack<data> s;
s.push(make_pair(dim,R)); // push the first set of parameters
int n = 0;
while(false == s.empty()) { // do the loop until stack is depleted
auto item = s.top(); // get the top item and pop it after
s.pop();
int r = static_cast<int>(floor(item.second));
if (item.first == 1) {
n += 1 + 2*r;
} else {
s.push(make_pair(item.first-1,item.second));
for (int i = 1; i <= r; ++i){
// since you have a multiplier 2 we push the same parameters twice
s.push(make_pair(item.first-1, sqrt(item.second*item.second - i*i) ));
s.push(make_pair(item.first-1, sqrt(item.second*item.second - i*i) ));
}
}
}
return n;
}
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.