Placing random numbers in a grid - c++
I need to place numbers within a grid such that it doesn't collide with each other. This number placement should be random and can be horizontal or vertical. The numbers basically indicate the locations of the ships. So the points for the ships should be together and need to be random and should not collide.
I have tried it:
int main()
{
srand(time(NULL));
int Grid[64];
int battleShips;
bool battleShipFilled;
for(int i = 0; i < 64; i++)
Grid[i]=0;
for(int i = 1; i <= 5; i++)
{
battleShips = 1;
while(battleShips != 5)
{
int horizontal = rand()%2;
if(horizontal == 0)
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != j)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row+k)*8+(column)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row+k)*8+(column)] = 1;
battleShipFilled = true;
}
battleShips++;
}
else
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row)*8+(column+k)] = 1;
battleShipFilled = true;
}
battleShips++;
}
}
}
}
But the code i have written is not able to generate the numbers randomly in the 8x8 grid.
Need some guidance on how to solve this. If there is any better way of doing it, please tell me...
How it should look:
What My code is doing:
Basically, I am placing 5 ships, each of different size on a grid. For each, I check whether I want to place it horizontally or vertically randomly. After that, I check whether the surrounding is filled up or not. If not, I place them there. Or I repeat the process.
Important Point: I need to use just while, for loops..
You are much better of using recursion for that problem. This will give your algorithm unwind possibility. What I mean is that you can deploy each ship and place next part at random end of the ship, then check the new placed ship part has adjacent tiles empty and progress to the next one. if it happens that its touches another ship it will due to recursive nature it will remove the placed tile and try on the other end. If the position of the ship is not valid it should place the ship in different place and start over.
I have used this solution in a word search game, where the board had to be populated with words to look for. Worked perfect.
This is a code from my word search game:
bool generate ( std::string word, BuzzLevel &level, CCPoint position, std::vector<CCPoint> &placed, CCSize lSize )
{
std::string cPiece;
if ( word.size() == 0 ) return true;
if ( !level.inBounds ( position ) ) return false;
cPiece += level.getPiece(position)->getLetter();
int l = cPiece.size();
if ( (cPiece != " ") && (word[0] != cPiece[0]) ) return false;
if ( pointInVec (position, placed) ) return false;
if ( position.x >= lSize.width || position.y >= lSize.height || position.x < 0 || position.y < 0 ) return false;
placed.push_back(position);
bool used[6];
for ( int t = 0; t < 6; t++ ) used[t] = false;
int adj;
while ( (adj = HexCoord::getRandomAdjacentUnique(used)) != -1 )
{
CCPoint nextPosition = HexCoord::getAdjacentGridPositionInDirection((eDirection) adj, position);
if ( generate ( word.substr(1, word.size()), level, nextPosition, placed, lSize ) ) return true;
}
placed.pop_back();
return false;
}
CCPoint getRandPoint ( CCSize size )
{
return CCPoint ( rand() % (int)size.width, rand() % (int)size.height);
}
void generateWholeLevel ( BuzzLevel &level,
blockInfo* info,
const CCSize &levelSize,
vector<CCLabelBMFont*> wordList
)
{
for ( vector<CCLabelBMFont*>::iterator iter = wordList.begin();
iter != wordList.end(); iter++ )
{
std::string cWord = (*iter)->getString();
// CCLog("Curront word %s", cWord.c_str() );
vector<CCPoint> wordPositions;
int iterations = 0;
while ( true )
{
iterations++;
//CCLog("iteration %i", iterations );
CCPoint cPoint = getRandPoint(levelSize);
if ( generate (cWord, level, cPoint, wordPositions, levelSize ) )
{
//Place pieces here
for ( int t = 0; t < cWord.size(); t++ )
{
level.getPiece(wordPositions[t])->addLetter(cWord[t]);
}
break;
}
if ( iterations > 1500 )
{
level.clear();
generateWholeLevel(level, info, levelSize, wordList);
return;
}
}
}
}
I might add that shaped used in the game was a honeycomb. Letter could wind in any direction, so the code above is way more complex then what you are looking for I guess, but will provide a starting point.
I will provide something more suitable when I get back home as I don't have enough time now.
I can see a potential infinite loop in your code
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
Here, nothing prevents row from being 0, as it was assignd rand%8 earlier, and k can be assigned a negative value (since j can be positive). Once that happens nothing will end the while loop.
Also, I would recommend re-approaching this problem in a more object oriented way (or at the very least breaking up the code in main() into multiple, shorter functions). Personally I found the code a little difficult to follow.
A very quick and probably buggy example of how you could really clean your solution up and make it more flexible by using some OOP:
enum Orientation {
Horizontal,
Vertical
};
struct Ship {
Ship(unsigned l = 1, bool o = Horizontal) : length(l), orientation(o) {}
unsigned char length;
bool orientation;
};
class Grid {
public:
Grid(const unsigned w = 8, const unsigned h = 8) : _w(w), _h(h) {
grid.resize(w * h);
foreach (Ship * sp, grid) {
sp = nullptr;
}
}
bool addShip(Ship * s, unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) { // if in valid range
if (s->orientation == Horizontal) {
if ((x + s->length) <= _w) { // if not too big
int p = 0; //check if occupied
for (int c1 = 0; c1 < s->length; ++c1) if (grid[y * _w + x + p++]) return false;
p = 0; // occupy if not
for (int c1 = 0; c1 < s->length; ++c1) grid[y * _w + x + p++] = s;
return true;
} else return false;
} else {
if ((y + s->length) <= _h) {
int p = 0; // check
for (int c1 = 0; c1 < s->length; ++c1) {
if (grid[y * _w + x + p]) return false;
p += _w;
}
p = 0; // occupy
for (int c1 = 0; c1 < s->length; ++c1) {
grid[y * _w + x + p] = s;
p += _w;
}
return true;
} else return false;
}
} else return false;
}
void drawGrid() {
for (int y = 0; y < _h; ++y) {
for (int x = 0; x < _w; ++x) {
if (grid.at(y * w + x)) cout << "|S";
else cout << "|_";
}
cout << "|" << endl;
}
cout << endl;
}
void hitXY(unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) {
if (grid[y * _w + x]) cout << "You sunk my battleship" << endl;
else cout << "Nothing..." << endl;
}
}
private:
QVector<Ship *> grid;
unsigned _w, _h;
};
The basic idea is create a grid of arbitrary size and give it the ability to "load" ships of arbitrary length at arbitrary coordinates. You need to check if the size is not too much and if the tiles aren't already occupied, that's pretty much it, the other thing is orientation - if horizontal then increment is +1, if vertical increment is + width.
This gives flexibility to use the methods to quickly populate the grid with random data:
int main() {
Grid g(20, 20);
g.drawGrid();
unsigned shipCount = 20;
while (shipCount) {
Ship * s = new Ship(qrand() % 8 + 2, qrand() %2);
if (g.addShip(s, qrand() % 20, qrand() % 20)) --shipCount;
else delete s;
}
cout << endl;
g.drawGrid();
for (int i = 0; i < 20; ++i) g.hitXY(qrand() % 20, qrand() % 20);
}
Naturally, you can extend it further, make hit ships sink and disappear from the grid, make it possible to move ships around and flip their orientation. You can even use diagonal orientation. A lot of flexibility and potential to harness by refining an OOP based solution.
Obviously, you will put some limits in production code, as currently you can create grids of 0x0 and ships of length 0. It's just a quick example anyway. I am using Qt and therefore Qt containers, but its just the same with std containers.
I tried to rewrite your program in Java, it works as required. Feel free to ask anything that is not clearly coded. I didn't rechecked it so it may have errors of its own. It can be further optimized and cleaned but as it is past midnight around here, I would rather not do that at the moment :)
public static void main(String[] args) {
Random generator = new Random();
int Grid[][] = new int[8][8];
for (int battleShips = 0; battleShips < 5; battleShips++) {
boolean isHorizontal = generator.nextInt(2) == 0 ? true : false;
boolean battleShipFilled = false;
while (!battleShipFilled) {
// Select a random row and column for trial
int row = generator.nextInt(8);
int column = generator.nextInt(8);
while (Grid[row][column] == 1) {
row = generator.nextInt(8);
column = generator.nextInt(8);
}
int lengthOfBattleship = 0;
if (battleShips == 0) // Smallest ship should be of length 2
lengthOfBattleship = (battleShips + 2);
else // Other 4 ships has the length of 2, 3, 4 & 5
lengthOfBattleship = battleShips + 1;
int numberOfCorrectLocation = 0;
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal && row + k > 0 && row + k < 8) {
if (Grid[row + k][column] == 1)
break;
} else if (!isHorizontal && column + k > 0 && column + k < 8) {
if (Grid[row][column + k] == 1)
break;
} else {
break;
}
numberOfCorrectLocation++;
}
if (numberOfCorrectLocation == lengthOfBattleship) {
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal)
Grid[row + k][column] = 1;
else
Grid[row][column + k] = 1;
}
battleShipFilled = true;
}
}
}
}
Some important points.
As #Kindread said in an another answer, the code has an infinite loop condition which must be eliminated.
This algorithm will use too much resources to find a solution, it should be optimized.
Code duplications should be avoided as it will result in more maintenance cost (which might not be a problem for this specific case), and possible bugs.
Hope this answer helps...
Related
Conway's Game of Life help me understand this unexpected output
I would like some help understanding why my program is printing a grid of .................... .................... .................... .................... .................... ...............OOOOO OOOOOOOOOOOOO....... .................... .................... .................... The correct output would be so: .................... .................... .................... .................... .................... .................... .................... .............O.O.... ..............OO.... ..............O..... The way I wrote it is to create a copy of the old state and manipulate it using the rules of the game. After I check every cell, I store count of the number of neighbors alive for that cell. IF the count is greater than 3 or less than two, the cell will die. If a cell has a count of 2 or 3 neighbors, it remains alive. If a dead cell has a count of 3, it becomes alive. These rules are directly applied to the copy version instead of the old and then print the copy. I've tried using a debugger but I'm still unsure of how to use it properly. I haven't notice any red flags as of yet. Here's my code: #include <iostream> #include <vector> using std::vector; using std::cout; vector<vector<bool> > world = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }; void generate(const vector<vector<bool> >&g,vector<vector<bool> >&newworld) { int count = 0; newworld = g; for(size_t i = 0; i < g.size();i++) { for(size_t j = 0; j < g[i].size();j++) { int x = g.size(); //I rows int y = g[i].size(); //J columns //wrap the edges with formula (x+n)%n where n = NumOfRows or NumOfCol if(g[(((i+1)+x)%x)][(((j-1)+y)%y)]==true){//top left count++; } else if(g[(((i+1)+x)%x)][j]==true){//top middle count++; } else if(g[(((i+1)+x)%x)][(((j+1)+y)%y)]==true){//top right count++; } else if(g[i][(((j-1)+y)%y)]==true){//left cell count++; } else if(g[i][(((j+1)+y)%y)]==true){//right cell count++; } else if(g[(((i-1)+x)%x)][(((j-1)+y)%y)]==true){ //bottom left count++; } else if(g[(((i-1)+x)%x)][j]==true){//bottom middle count++; } else if(g[(((i-1)+x)%x)][(((j+1)+y)%y)]==true){//bottom right count++; } if (g[i][j]) { if(count > 3 || count < 2) {//if alive cell has more than 3 or less than 2, die newworld[i][j] = false; } else if (count == 2 || count == 3) { //remain the same newworld[i][j] = g[i][j]; } } else if (g[i][j] == false) {//dead come alive if(count == 3) { newworld[i][j] = true; } } } } } void display(vector<vector<bool> >&a) { for(size_t row = 0; row <a.size(); row++) { for(size_t column = 0; column <a[row].size(); column++){ if (a[row][column]) { cout << 'O'; } else { cout << '.'; } } cout << '\n'; } } int main() { vector<vector<bool> > newworld; generate(world,newworld); display(newworld); return 0; }
The function generate has (at least) two problem. count is initialized outside the nested loops, so it's never reset to zero (as it should, for every cell) and keeps growing. All the conditions are mutually exclusive, so whenever one it's met, the others are skipped. There shouldn't be any else if, but only ifs. Keeping the data structure you chose, you can rewrite that function as using gof_t = std::vector<std::vector<bool>>; void generate(gof_t& g, gof_t& newworld) { for(size_t i = 0, x = g.size(); i < x; i++) { for(size_t j = 0, y = g[i].size(); j < y; j++) { size_t i_prev = (i + x - 1) % x; size_t i_next = (i + 1) % x; size_t j_prev = (j + y - 1) % y; size_t j_next = (j + 1) % y; int count = g[i_prev][j_prev] + g[i_prev][j] + g[i_prev][j_next] + g[i ][j_prev] + g[i ][j_next] + g[i_next][j_prev] + g[i_next][j] + g[i_next][j_next]; newworld[i][j] = g[i][j] ? (count == 2 || count == 3) : (count == 3); } } std::swap(g, newworld); // <-- Passing by non const reference, we can swap without copying } Live (pun intended), here.
Intuition behind starting from the bottom right (instead of the top left) in this DP
I was solving Dungeon Game on LeetCode. While I was able to come up with the recurrence relation (and determine that it was a DP question in the first place), what is the intuition behind starting from the bottom right, as shown in a highly upvoted solution: class Solution { public: int calculateMinimumHP(vector<vector<int> > &dungeon) { int M = dungeon.size(); int N = dungeon[0].size(); // hp[i][j] represents the min hp needed at position (i, j) // Add dummy row and column at bottom and right side vector<vector<int> > hp(M + 1, vector<int>(N + 1, INT_MAX)); hp[M][N - 1] = 1; hp[M - 1][N] = 1; for (int i = M - 1; i >= 0; i--) { for (int j = N - 1; j >= 0; j--) { int need = min(hp[i + 1][j], hp[i][j + 1]) - dungeon[i][j]; hp[i][j] = need <= 0 ? 1 : need; } } return hp[0][0]; } }; I thought it to be pretty similar to the Unique Paths question, and hence started solving from the top left (but it doesn't retrieve correct results). My solution (if at all required) is: class Solution { public int calculateMinimumHP(int[][] dungeon) { if(dungeon==null || dungeon.length==0 || dungeon[0]==null || dungeon[0].length==0) return -1; int maxVal = 0; int[][] dp = new int[dungeon.length][dungeon[0].length]; dp[0][0] = dungeon[0][0]; for(int i=1; i<dungeon.length; i++) dp[i][0] = dp[i-1][0] + dungeon[i][0]; for(int i=1; i<dungeon[0].length; i++) dp[0][i] = dp[0][i-1] + dungeon[0][i]; int chosenOne=0; for(int i=1; i<dungeon.length; i++) { for(int j=1; j<dungeon[0].length; j++) { if(dp[i-1][j] < 0 && dp[i][j-1] < 0) { chosenOne = Math.max(dp[i-1][j], dp[i][j-1]); } else { if(dp[i-1][j] > 0 && dp[i][j-1] > 0) { chosenOne = Math.min(dp[i-1][j], dp[i][j-1]); } else { chosenOne = (dp[i-1][j]>0?dp[i-1][j]:dp[i][j-1]); } } dp[i][j] = dungeon[i][j] + chosenOne; maxVal = Math.min(maxVal, dp[i][j]); } } return maxVal+1; } } One of the comments here by 'JaiMataDi' mentions that it is so because we don't know the initial health point of the knight. But how about the approach that I used? To be precise, could some one please point out the intuition behind why we start at the bottom right and not the top left? Thanks!
Loop through 2D array diagonally with random board size
I was wondering how I can loop through a two dimentional array if the size of the array is random, e.g 6x6 or 10x10 etc. The idea is to search for four of the same kind of characters, 'x' or 'o'. This is typically needed for a board game. int main() { int array_size = 5; // Size of array int array_height = array_size; bool turn = true; // true = player 1, false = player 2 bool there_is_a_winner = false; char** p_connect_four = new char*[array_size]; for (int i = 0; i < array_size; i++) // Initialise the 2D array { // At the same time set a value "_" as blank field p_connect_four[i] = new char[array_size]; for (int j = 0; j < array_size; j++) { p_connect_four[i][j] = '_'; } } } This is what I have so far, checking from [3][0] to [0][3]. But this requires me to add 2 more for loops to check [4][0] to [0][4] and [4][1] to [1][4] IF the size of the board was 5x5. for (int i = 3, j = 0; i > 0 && j < array_size; i--, j++ ) {// CHECK DOWN up right from 3,0 -> 0,3 if (p_connect_four[i][j] == p_connect_four[i - 1][j + 1] && p_connect_four[i][j] != '_' ) { check_diagonalRight++; if (check_diagonalRight == 3) { there_is_a_winner = true; break; } } else { check_diagonalRight = 0; } } if (there_is_a_winner) { // Break while loop of game. break; } Obviously I want to check the whole board diagonally to the right regardless of the size of the board. Is there any other way than having 3 separate for loops for checking [3][0] -> [0][3] , [4][0] -> [0][4] and [4][1]-> [1][4] ?
for (i = array_size - 1, j = array_size - 2; i < array_size && i >= 0, j < array_size && j >= 0; j--) { // starts from [4][3] and loops to the left if arraysize = 5x5 // but works on any size int k = i, l = j; for (k, l; k < array_size && k > 0, l < array_size && l > 0; k--, l++) { // checks diagonally to the right if (check_diagonalRight == 3) { there_is_a_winner = true; break; } if (p_connect_four[k][l] == p_connect_four[k - 1][l + 1] && p_connect_four[k][l] != '_') { //check up one square and right one square check_diagonalRight++; } else { check_diagonalRight = 0; // if its not equal, reset counter. } } if (there_is_a_winner) { break; // break for loop } } if (there_is_a_winner) { break; // break while loop of game } This checks up and right no matter the size, implement it for the other angles as well and it will work for any board size. You could potentially check right and left diagonal at once with nested loops.
This will work perfectly fine for your program! I hope so! int arraySize = 8; for(int i=0, j=0; i<arraySize && j<arraySize; i++, j++) { if((i == 0 && j == 0) || (i == arraySize - 1 && j == arraySize - 1)) { continue; } else { int k = i; int l = j; //This Loop will check from central line (principal diagonal) to up right side (like slash sign / (representing direction)) for(k, l; k>0 && l < arraySize - 1; k--, l++) { //Here check your condition and increment to your variable. like: if (p_connect_four[k][l] == p_connect_four[k - 1][l + 1] && p_connect_four[k][l] != '_' ) { check_diagonalRight++; } } //You can break the loop here if check_diagonalRight != k then break k = i; l = j; //This Loop will check from central line (principal diagonal) to down left side (like slash sign / (representing direction)) for(k, l; k<arraySize - 1 && l > 0; k++, l--) { //Here check your condition and increment to your variable. like: if (p_connect_four[k][l] == p_connect_four[k + 1][l - 1] && p_connect_four[k][l] != '_' ) { check_diagonalRight++; } } if(check_diagonalRight == i+j+1) { there_is_a_winner = true; break; } } }
I suggest to surround your board with extra special cases to avoid to check the bound. To test each direction I suggest to use an array of offset to apply. Following may help: #include <vector> using board_t = std::vector<std::vector<char>>; constexpr const std::size_t MaxAlignment = 4; enum Case { Empty = '_', X = 'X', O = 'O', Bound = '.' }; enum class AlignmentResult { X, O, None }; // Create a new board, valid index would be [1; size] because of surrounding. board_t new_board(std::size_t size) { // Create an empty board board_t board(size + 2, std::vector<char>(size + 2, Case::Empty)); // Add special surround. for (std::size_t i = 0; i != size + 2; ++i) { board[0][i] = Case::Bound; board[size + 1][i] = Case::Bound; board[i][0] = Case::Bound; board[i][size + 1] = Case::Bound; } return board_t; } // Test a winner from position in given direction. AlignmentResult test( const board_t& board, std::size_t x, std::size_t y, int offset_x, int offset_y) { if (board[x][y] == Case::Empty) { return AlignmentResult::None; } for (std::size_t i = 1; i != MaxAlignment; ++i) { // Following condition fails when going 'out of bound' thanks to Case::Bound, // else you have also to check size... if (board[x][y] != board[x + i * offset_x][y + i * offset_y]) { return AlignmentResult::None; } } if (board[x][y] == Case::X) { return AlignmentResult::X; } else { return AlignmentResult::O; } } // Test a winner on all the board AlignmentResult test(const board_t& board) { // offset for direction. Use only 4 direction because of the symmetry. const int offsets_x[] = {1, 1, 1, 0}; const int offsets_y[] = {-1, 0, 1, 1}; const std::size_t size = board.size() - 1; for (std::size_t x = 1; x != size; ++x) { for (std::size_t y = 1; y != size; ++y) { for (std::size_t dir = 0; dir != 4; ++dir) { // for each directions auto res = test(board, x, y, offsets_x[dir], offsets_y[y]); if (res != AlignmentResult::None) { return res; } } } } return AlignmentResult::None; }
A* bug (A star search algorithm)
I have started to study algorithms and software development and, as a small self evaluation project I have decided to write the A* search algorithm in C++. It uses Qt and OpenGL for the visual part (but that is not important). Using mostly this source: A* Pathfinding for Beginners I have write a small app, however I am have found a bug that I cant fix. It appears that for some reason the parent of a node close to the wall is set to the wall.(?) And the parent of the wall is set to the the start point(?) because of the way I am storing the info. I have used a stateMatrix[][] where 1 = entrance green; 2 = exit; 3 = wall and; 4 = path; I have also used matrix to represent openNodes and closedNode. The closedNodes matrix is bool matrix the openNode matrix also stores some info: The openNodes instructions are: openNodes[100][100][6]; 0 - bool open or closed 1 - F 2 - G 3 - H 4 - parentX 5 - parentY I know that there are better ways to code this but I have not yet got to this lesson ;) Here is the code of the astar file: #include <math.h> #include "apath.h" aPath::aPath() { gridSize = 100; int i, j, k; for(i = 0; i < gridSize; i++) for(j = 0; j < gridSize; j++) { stateMatrix[i][j] = 0; for(int k = 0; k < 6; k++) openNodes[i][j][k] = 0; closedNodes[i][j] = 0; } targetX = targetY = openX = openY = entranceX = entranceY = 0; } void aPath::start() { bool testOK = false; int G = 0; openNodes[entranceX][entranceY][0] = 1; openNodes[entranceX][entranceY][2] = 14; openNodes[entranceX][entranceY][3] = euclidean(entranceX, entranceY); openNodes[entranceX][entranceY][1] = openNodes[entranceX][entranceY][2] + openNodes[entranceX][entranceY][3]; openNodes[entranceX][entranceY][4] = entranceX; openNodes[entranceX][entranceY][5] = entranceY; int i, j, x, y; while(closedNodes[targetX][targetY] == 0) { searchLessOpen(); closedNodes[openX][openY] = 1; openNodes[openX][openY][0] = 0; //Check the 8 squares around for(i = openX - 1; i <= openX + 1; i++) for(j = openY - 1; j <= openY + 1; j++) { //check if the square is in the limits, //is not a wall and is not in the closed list if((i >= 0) && (j >= 0) && (i < gridSize) && (j < gridSize) && (stateMatrix[i][j] != 3) && (closedNodes[i][j] == 0)) { //G calculus. If it is in the edge it costs more x = i - openX + 1; y = j - openY + 1; if((x == 0 && y == 0) || (x == 0 && y == 2) || (x == 2 && y == 0) || (x == 2 && y == 2)) { G = 14; } else G = 10; //check if node is already open if(openNodes[i][j][0] == 0) { openNodes[i][j][0] = 1; openNodes[i][j][2] = G; openNodes[i][j][3] = euclidean(i,j); openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3]; openNodes[i][j][4] = openX; openNodes[i][j][5] = openY; } else //if node is open, check if this path is better { if(G < openNodes[i][j][2]) { openNodes[i][j][2] = G; openNodes[i][j][1] = openNodes[i][j][2] + openNodes[i][j][3]; openNodes[i][j][4] = openX; openNodes[i][j][5] = openY; } } } } } reconstruct(); } void aPath::reconstruct() { bool test = false; int x = openNodes[targetX][targetY][4]; int y = openNodes[targetX][targetY][5]; do { stateMatrix[x][y] = 4; x = openNodes[x][y][4]; y = openNodes[x][y][5]; if(x == entranceX && y == entranceY) test = true; } while(test == false); } int aPath::euclidean(int currentX, int currentY) { int dx = targetX - currentX; int dy = targetY - currentY; return 10*sqrt((dx*dx)+(dy*dy)); } void aPath::searchLessOpen() { int F = 1000000; int i, j; for(i = 0; i < gridSize; i++) for(j = 0; j < gridSize; j++) { if(openNodes[i][j][0] == 1) { if(openNodes[i][j][1] <= F) { F = openNodes[i][j][1]; openX = i; openY = j; } } } } Does anyone know what I am doing wrong? Thanks. Edit: Here are some pictures:
In aPath::start(), you have: openNodes[entranceX][entranceY][0] = 1; openNodes[entranceX][entranceY][2] = 14; openNodes[entranceX][entranceY][3] = euclidean(entranceX, entranceY); openNodes[entranceX][entranceY][3] = openNodes[entranceX][entranceY][2] + openNodes[entranceX][entranceY][3]; openNodes[entranceX][entranceY][4] = entranceX; openNodes[entranceX][entranceY][5] = entranceY; Why is there no value for subscript [1]? And why do you assign two different values to subscript [3]? Also, to be honest, the entranceX and entranceY names are too long for the job they're doing; they make the code less readable (though I'm sure you were told to use good meaningful names). For these array indexes, I'd probably use just x and y. At the code: //Check the 8 squares around for(i = openX - 1; i <= openX + 1; i++) for(j = openY - 1; j <= openY + 1; j++) { I would probably ensure that neither i nor j took on invalid values with code such as: //Check the 8 squares around (openX, openY) int minX = max(openX - 1, 0); int maxX = min(openX + 1, gridsize); int minY = max(openY - 1, 0); int maxY = min(openY + 1, gridsize); for (i = minX; i <= maxX; i++) for (j = minY; j <= maxY; j++) { I am not sure whether you need to explicitly check for the case where i == openX && j == openY (the current cell); it is not one of the 8 cells around the current cell (because it is the current cell), but the other conditions may already deal with that. If not: if (i == openX && j == openY) continue; I note that we have no definitions of openX and openY or a number of other non-local variables. This makes it hard to work out whether they are class member variables or global variables of some sort. We also can't see how they're initialized, nor the documentation on what they represent. Most plausible source of trouble In aPath::SearchLessOpen(), you have: if(openNodes[i][j][0] == 1) { if(openNodes[i][j][6] <= F) { F = openNodes[i][j][7]; You indicated in your description that the subscripts on openNodes in the last place ranged over 0..5; your code, though, is accessing subscripts 6 and 7. This could easily lead to the sort of confusion you describe - you are accessing data out of bounds. I think this might easily be the root of your trouble. When you access openNodes[i][j][6], this is technically undefined behaviour, but the most likely result is that it is reading the same data as if you'd written openNodes[i][j+1][0] (when j < gridsize - 1). Similarly, openNodes[i][j][7] is equivalent to accessing openNodes[i][j+1][1], with the same caveats.
C++ time spent allocating vectors
I am trying to speed up a piece of code that is ran a total of 150,000,000 times. I have analysed it using "Very Sleepy", which has indicated that the code is spending the most time in these 3 areas, shown in the image: The code is as follows: double nonLocalAtPixel(int ymax, int xmax, int y, int x , vector<nodeStructure> &nodeMST, int squareDimension, Mat &inputImage) { vector<double> nodeWeights(8,0); vector<double> nodeIntensities(8,0); bool allZeroWeights = true; int numberEitherside = (squareDimension - 1) / 2; int index = 0; for (int j = y - numberEitherside; j < y + numberEitherside + 1; j++) { for (int i = x - numberEitherside; i < x + numberEitherside + 1; i++) { // out of range or the centre pixel if (j<0 || i<0 || j>ymax || i>xmax || (j == y && i == x)) { index++; continue; } else { int centreNodeIndex = y*(xmax+1) + x; int thisNodeIndex = j*(xmax+1) + i; // add to intensity list Scalar pixelIntensityScalar = inputImage.at<uchar>(j, i); nodeIntensities[index] = ((double)*pixelIntensityScalar.val); // find weight from p to q float weight = findWeight(nodeMST, thisNodeIndex, centreNodeIndex); if (weight!=0 && allZeroWeights) { allZeroWeights = false; } nodeWeights[index] = (weight); index++; } } } // find min b int minb = -1; int bCost = -1; if (allZeroWeights) { return 0; } else { // iteratate all b values for (int i = 0; i < nodeWeights.size(); i++) { if (nodeWeights[i]==0) { continue; } double thisbCost = nonLocalWithb(nodeIntensities[i], nodeIntensities, nodeWeights); if (bCost<0 || thisbCost<bCost) { bCost = thisbCost; minb = nodeIntensities[i]; } } } return minb; } Firstly, I assume the spent time indicated by Very Sleepy means that the majority of time is spent allocating the vector and deleting the vector? Secondly, are there any suggestions to speed this code up? Thanks
use std::array reuse the vectors by passing it as an argument of the function or a global variable if possible (not aware of the structure of the code so I need more infos) allocate one 16 vector size instead of two vectors of size 8. Will make your memory less fragmented use parallelism if findWeight is thread safe (you need to provide more details on that too)