The game board is stored as a 2D char array. The Player moves his cursor around the board using the numpad, and chooses with the enter key- current position of the cursor is stored in two ints.
After each move, the board is evaluated for a win using the below method.
void checkwin()
{
//look along lines from current position
int x = cursorPosX;
int y = cursorPosY;
int c = playerTurn ? 1 : 2; //which mark to look for
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
//look for diagonal
for (int i = 0; i <= 2; i++ )
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
//failed everything, return
winConditions = -1;
return;
}
}
break;
}
}
break;
}
}
//if we make it out of the loops, we have a winner.
winConditions = playerTurn ? 0 : 1;
}
I get wrong results- returning a draw or win when not appropriate. I'm almost certain x and y get wrong values at some point and start checking the wrong spots.
Visual Studio stops updating a watch on x and y after going into the yAxis loop- I'm not sure why, but it prevents me from keeping track of those values. Am I breaking a rule about scoping somewhere? This is the only place I use x and y as variable names.
Relevant wrap method below. My aim was to always be able to check the other 2 spaces by adding, no matter where I was on the board
int WrapValue(int min, int max, int value)
{
auto range = max - min;
while (value >= max)
{
value -= range;
}
while (value < min)
{
value += range;
}
return value;
}
I'd appreciate a trained eye to tell me what I did wrong here. Thanks so much for your time.
Nesting for loops was a terrible idea. I solved the problem by refactoring the code into multiple separate loops that each do 1 thing, rather than fall through each other into deeper levels of hell.
for (int xAxis = 0; xAxis <= 2; xAxis++) //look along x axis
{
x = WrapValue(0, sizeof(squares[0]), x + 1);
if (CheckPos(x, y) != c) //if we don't find the same mark, must not be a horizontal line, otherwise, break out.
{
x = cursorPosX; //reset x
break;
}
else if (xAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
for (int yAxis = 0; yAxis <= 2; yAxis++) //look along y axis
{
y = WrapValue(0, sizeof(squares[0]), y + 1);
if (CheckPos(x, y) != c)
{
y = cursorPosY;
break;
}
else if (yAxis == 2)
{
winConditions = playerTurn ? 0 : 1;
return;
}
}
...ect
This violates DRY, but it does work the way it's supposed to, I'm sure I can simplify it later.
While I'm not entirely sure why the previous way didn't work, I do realize that it was just bad design to start with.
Related
I am working on a 2D game using SDL. Recently I implemented various functions that put objects (and their rectangles) into motion, but encountered performance issues that are most likely caused by inefficient mapping of rectangle coordinates. Please see below:
2D coordinates of the rectangle are stored in an integer array whenever move() is called. For example, coordinate[0] is the first point on the x axis and coordinate[1] is the last point on the x axis. Coordinates [2] and [3] work for points on the y axis.
The map() function takes the coordinates of a rectangle and stores them in static std::map (Status class). Each x and y pair is either 0 or 1, depending on whether a rectangle is present or not. Player's coordinates are not mapped.
When the player moves, the bool function collide() checks whether the player's rectangle is adjacent to another recantgle in a particular direction. If there is no rectangle blocking the way, the player is allowed to move.
Everything works well, but it seems like all these for loops in the map() function are very CPU-heavy. When rectangles are being moved on the screen, the program lags horribly. How can I map rectangle coordinates more efficiently?
void move(int x, int y) {
dstRect.x = x;
dstRect.y = y;
coordinate[0] = dstRect.x;
coordinate[1] = dstRect.x + dstRect.w;
coordinate[2] = dstRect.y;
coordinate[3] = dstRect.y + dstRect.h;
}
void map() {
for (int x = coordinate[0]; x != coordinate[1]; x++) {
for (int y = coordinate[2]; y != coordinate[3]; y++) {
Status::map().insert(std::pair<std::vector<int>, int>({ x, y }, 1));
}
}
}
bool collide(DIRECTION direction) {
if (direction == UP || direction == DOWN) {
for (int x = texture.coordinate[0]; x != texture.coordinate[1]; x++) {
if (direction == UP) {
if (Status::map().find({ x, texture.coordinate[2] - 1 })->second == 1) { return true; }
}
if (direction == DOWN) {
if (Status::map().find({ x, texture.coordinate[3] + 1 })->second == 1) { return true; }
}
}
}
if (direction == RIGHT || direction == LEFT) {
for (int y = texture.coordinate[2]; y != texture.coordinate[3]; y++) {
if (direction == RIGHT) {
if (Status::map().find({ texture.coordinate[1] + 1, y })->second == 1) { return true; }
}
if (direction == LEFT) {
if (Status::map().find({ texture.coordinate[0] - 1, y })->second == 1) { return true; }
}
}
}
return false;
}
void moveRight() {
for (int i = 0; i < speed; i ++) {
if (!collide(RIGHT)) {
int x = texture.dstRect.x + 1;
int y = texture.dstRect.y;
texture.move(x, y);
}
}
}
Followed #FrançoisAndrieux advice and created multidimensional vector for storing the coordinates.
So I'm relatively new to coding in SFML, so apologies if I made some newbie mistake. My project is Space Invaders in SFML. When I was working on the shooting, a problem arose. How do I do collision? I was familiar with shape.getGlobalBounds().intersect(), and it worked on previous projects. It didn't work. So I tried simplifying it. I used RectangleShape for both the enemy shape, and the bullet shape.
Here is the actual for loop, for the collision:
for (int y = 0; y <= 2; ++y) {
for (int x = 0; x <= 6; ++x) {
if (shootShape.getPosition().x < e.aliensX[x] && shootShape.getPosition().x > e.aliensX[x] + 15 ||
shootShape.getPosition().y < e.aliensY[y] && shootShape.getPosition().y > e.aliensY[y] + 15) {
e.aliensX[x] = -10;
e.aliensY[y] = -10;
shooting = false;
reload = false;
}
}
}
This is the shooting function:
void Player::shoot() {
if (reload) {
shootX = posX + 5;
shootY = posY - 50;
shootShape.setPosition(shootX, shootY);
shooting = true;
reload = false;
}
if (shooting) {
shootY -= 150 * 2 * deltaTime;
shootShape.setPosition(shootX, shootY);
}
}
And this is how I draw the enemies (I don't know how to create multiple enemies):
void Enemy::drawAliens() {
for (int j = 0; j <= arraySizeY; ++j) {
for (int i = 0; i <= arraySizeX; ++i) {
actualShape.setPosition(aliensX[i], aliensY[j]);
if (aliensY[i] <= p.shootY && aliensY[i] >= p.shootY) {
aliensX[i] = -10;
aliensY[i] = -10;
}
else {
win.draw(actualShape);
}
}
}
}
Explanation behind some of the variables:
aliensX is an array which contains the different x positions for the enemies.
aliensY is an array which contains the different y positions for the enemies.
shooting is a bool variable, which is true when the bullet is travelling.
reload is whether you can shoot.
EDIT:
Intersect will not work because of the way I created my enemies. They are all in ONE shape. I need it to work with specific coordinates, because I don't know a better way to create multiple enemies all at once. If there is a way to do that, advice would be appreciated!
It's rather easy, if you rely on SFML's templated sf::Rect class. Just retrieve the rectangle for both objects as global boundaries and try to intersect them:
const bool collides = firstDrawable.getGlobalBounds().intersect(secondDrawable.getGlobalBounds());`
Same can be done with a small temporary rectangle you can fill with dynamic values not directly associated with a sf::Drawable:
const sf::FloatRect bullet(x - width / 2, y - height / 2, width, height);
const bool collides = firstDrawable.getGlobalBounds().intersect(bullet);`
Your if statement is never true. You have
shootShape.getPosition().x < e.aliensX[x] && shootShape.getPosition().x > e.aliensX[x] + 15.
Your shootShape.getPosition().x can never be smaller than e.aliensX[x] and bigger than e.aliensX[x] + 15 at the same time. That's impossible. The same for y position. Change your if statement to
for (int y = 0; y <= 2; ++y) {
for (int x = 0; x <= 6; ++x) {
if (shootShape.getPosition().x > e.aliensX[x] && shootShape.getPosition().x < e.aliensX[x] + 15 ||
shootShape.getPosition().y > e.aliensY[y] && shootShape.getPosition().y < e.aliensY[y] + 15) {
e.aliensX[x] = -10;
e.aliensY[y] = -10;
shooting = false;
reload = false;
}
}
}
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...
I'm working on a project that's going to print out to a bitmap(more specifically a RAW, but that's not important to the question), but I'm working in a 2-D array in-program.
I want to be able to draw a line from point (a,b) to point (x,y) for any arbitrary values of a,b,x, and y. I don't need anything fancy like anti-aliasing; at this point nearest-neighbor is fine. for the sake of example, let's assume I've got a 5x5 2d array, like so:
00,10,20,30,40
01,11,21,31,41
02,12,22,32,42
03,13,23,33,43
04,14,24,34,44
now, lets assume I want to draw a line between 04 and 42. I want a way of reliably coming up with something like this:
0,0,0,0,0
0,0,0,0,0
0,0,0,1,1
0,1,1,1,0
1,1,0,0,0
I'm sure there's someone thinking "guh, is this guy retarded? did he fail here?", but humor me, please!
I'm working in C++, but that should be secondary to the actual question.
Bresenham's line algorithm is what you need:
Illustration of the result of Bresenham's line algorithm.
Like Simucal said, Bresenham is the way to go. Here is a naive implementation.
Not perfect C code, and you have to do some magic if you want thickness on the line segments. Also, you should traverse along x, instead of y like I do here. It is more cache-friendly. If you want anti-aliasing, search for "Wu-lines". It's a clever trick to use the fraction from the positions as a gradient.
Tips for line thickness:
Calculate the normalized vector V(-y,x) from v1 - v0 if your vertices are in counter-clockwise order, or V(y,-x) if your vertices are in clockwise order. Then you have four points defined by: v0, v0 + V * linewidth, v1 and v1 + V * linewidth. Rasterize that quadrangle by interpolating along the edges. But if you already want to go that far, you would probably code a triangle rasterizer instead.
typedef struct Point
{
int x, y;
} Point;
typedef struct Color {
unsigned char r,g,b;
} Color;
#define RGB(x) (x->r << 16) | (x->g << 8) | (x->b)
int DrawLinestrip(int width, int height, unsigned int* buffer,
Color* color, Point* verts, int count)
{
int i, x,y,xbegin, xdelta, ydelta, xdiff, ydiff, accum, sign;
Point *p1, *p2;
if(!verts || count < 2)
return -1;
for(i=1; i<count; ++i){
if(verts[i].y > verts[i-1].y){ /* sort by y */
p1 = &verts[i-1];
p2 = &verts[i];
} else {
p1 = &verts[i];
p2 = &verts[i-1];
}
xdelta = p2->x - p1->x;
ydelta = p2->y - p1->y;
accum = 0;
sign = 0;
if(!xdelta && !ydelta)
continue;
else if(!xdelta && ydelta){ /* Special case: straight vertical line */
x = p1->x;
for(y=p1->y; y<(p1->y + ydelta); ++y){
buffer[x + y*width] = RGB(color);
}
}
else if(xdelta && !ydelta){ /* Special case: straight horisontal line */
y = p1->y;
xbegin = (p1->x < p2->x ? p1->x : p2->x);
for(x=xbegin; x<=xbegin+abs(xdelta); ++x){
buffer[x + y*width] = RGB(color);
}
}
else {
xdiff = (xdelta << 16) / ydelta;
ydiff = (ydelta << 16) / xdelta;
if( abs(xdiff) > abs(ydiff) ){ /* horizontal-major */
y = p1->y;
if(xdelta < 0){ /* traversing negative x */
for(x=p1->x; x >= p2->x; --x){
buffer[x + y*width] = RGB(color);
accum += abs(ydiff);
while(accum >= (1<<16)){
++y;
accum -= (1<<16);
}
}
} else { /* traversing positive x */
for(x=p1->x; x <= p2->x; ++x){
buffer[x + y*width] = RGB(color);
accum += abs(ydiff);
while(accum >= (1<<16)){
++y;
accum -= (1<<16);
}
}
}
} else if( abs(ydiff) > abs(xdiff) ){ /* vertical major */
sign = (xdelta > 0 ? 1 : -1);
x = p1->x;
for(y=p1->y; y <= p2->y; ++y){
buffer[x + y*width] = RGB(color);
accum += abs(xdiff);
while(accum >= (1<<16)){
x += sign;
accum -= (1<<16);
}
}
} else if( abs(ydiff) == abs(xdiff) ){ /* 45 degrees */
sign = (xdelta > 0 ? 1 : -1);
x = p1->x;
for(y=p1->y; y <= p2->y; ++y){
buffer[x + y*width] = RGB(color);
x+= sign;
}
}
}
}
return 0;
}
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)