trouble checking for overlap in a 2-D array of chars - c++

I am having trouble with a part of a program that takes a dynamically allocated object called userRect and checks for it overlapping on an array of chars arranged in the shape of a rectangle. The other rectangles rect[0] and rect[1] are randomly placed on a imaginary grid in a console window.
rect[0] prints out with '0'
rect[1] prints out with '1'
userRect prints out with '#' if no overlap is present.
userRect prints out with '+' at each char in the array that is overlapping another object.
The object userRect is movable with the w,a,s,d keys.
What is supposed to happen is when the user moves the userRect object and it overlaps another rect object. Each character that overlaps is replaced with a '+'.
The program is not printing a '+' when the userRect is overlapping another rectangle. Can anyone point out what is causing this?
Here is a sample of my code:
bool isOverlapping(Rect const & r) const
{
return !(min.x >= r.max.x || max.x <= r.min.x
|| min.y >= r.max.y || max.y <= r.min.y);
}
int main()
{
srand(time(NULL));
// initialization
Rect * userRect;
const int rectSize = 5;
Rect rect[rectSize];
const int ARRAY_SIZE = 13; // size of userRect
userRect = new Rect();
// set
rect[0].setRandom(rect[0]);
rect[1].setRandomByPointer(& rect[1]);
userRect->setMin(7, 5);
userRect->setMax(10, 9);
//rect0.setMin(10, 2);
//rect0.setMax(14, 4);
//rect1.setMin(1, 6);
//rect1.setMax(5, 15);
int userInput;
do
{
// draw
rect[0].draw('0');
rect[1].draw('1');
for (int i = 0; i < ARRAY_SIZE; i++)
{
if (userRect->isOverlapping(rect[i]))
{
userRect->draw('+');
}
else userRect->draw('#');
}

I have figured out what was wrong. The problem was in my for loop. If the userRect was within the boundaries of the rect[0] but not within the bounds of rect[1] the userRect->draw('#'); would overwrite the userRect->draw('+'); operation that was just executed before it. Thank you guys for all the help.

Related

C++ Getting neighbours of a cell in a grid, -1x throwing null exception when checked if != NULL

recently moved from C# to C++ so I'm new to pointers and references and so on.
I've a pointer-to-pointer array declared like this
enum Type
{
Void,
DeepWater,
Water,
... etc }
Tile::Type** tiles;
TileManager::TileManager(int width, int height)
{
this->tiles = new Tile::Type*[width];
for (int w = 0; w < width; w++)
{
tiles[w] = new Tile::Type[height];
for (int h = 0; h < height; h++)
{
tiles[w][h] = Tile::Type::Dirt;
}
}
}
Now I'm putting together a method that returns the neighbours of a cell in the tiles array and checking if each neighbour is not-equal to NULL.
However even when checking whether it's null or not seems to throw an error, so I'm stumped.
Tile::Type * TileManager::GetNeighbours(int x, int y)
{
Tile::Type neighbours[8];
if(tiles[x][y+1] != NULL)
neighbours[0] = tiles[x ][y + 1];
...etc
if (tiles[x - 1][y - 1] != NULL) //<-- Error fires here
neighbours[5] = tiles[x - 1][y - 1];
return neighbours;
}
I know why it's throwing the error but shy of checking X and Y to see if they go over the limit or below 0... I figure there's a more practical way to prevent this so thought I'd best ask.
Edit:
Thank you, user4581301. I found most of this code elsewhere and adapted it to reflect the changes you suggested.
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
tiles[x][y+1], if y is the maximum valid value, will not be NULL except by the grace of . This goes out of bounds and as soon as you go out of bounds all bets are off. You've invoked Undefined Behaviour and pretty much anything can happen. Even what you expected to happen.
The same applies to the reported crash site, tiles[x - 1][y - 1].
Edit: Left out solution. Not helpful.
The only way, short of taking off and nuking the entire site from orbit, is to test the index to make sure it does not puncture the array bounds before using the index on the array. You'll probably want a function to handle this.
void assign_if(Type & neighbour, int x, int y)
{
if(x >= 0 && x < width && y >= 0 && y < height)
neighbour = tiles[x][y];
}
and call it
assign_if(neighbours[0], x, y+1);
and later
assign_if(neighbours[0], x-1, y-1);
Edit: Stealing this from Bob__ for completeness
It is impossible to return a raw array from a function. The array goes out of scope and the pointer to it becomes invalid. Either pass in the array as another parameter or use a std::array or std::vector, both of which can be returned. Thanks to Copy Elision, a smart compiler will likely eliminate the copying costs.
Example:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int x, int y)
{
std::array<Tile::Type, 8> neighbours;
...
return neighbours;
}
Edit by original poster. Here is my solution:
std::array<Tile::Type, 8> TileManager::GetNeighbours(int c, int r)
{
std::array<Tile::Type, 8> neighbours;
const int y[] = { -1, -1, -1, 1, 1, 1, 0, 0 };// 8 shifts to neighbors
const int x[] = { -1, 0, 1, -1, 0, 1, -1, 1 };// used in functions
for (int i = 0; i < 8; ++i)// visit the 8 spaces around it
if (inField(r + y[i], c + x[i]))
neighbours[i] = tiles[r + y[i]][c + x[i]];
else
neighbours[i] = Tile::Type::Void;
return neighbours;
}
bool TileManager::inField(int r, int c)
{
if (r < 0 || r >= 25) return false;
if (c < 0 || c >= 25) return false;
return true;
}
Edit: Caveat
This answer deals directly with solving the problem as asked. See the answer by Kaz for a description of a more practical solution that trades a bit of memory to completely eliminate the need for testing and generating the neighbours array.
The more "practical" way (shorter code that avoids conditional checks) is to create the tile array so that it's it contains an additional "border" of tiles around the valid area. If any tile position is in the valid area, then is valid and so is .
You can have a special type for the border tiles which only they have, and simply include those tiles in the "neighbors" list. If your world has walls, then the border can consist of wall material.
Needless to say, you must never ask for the list of neighbors of a border tile. This is ensured by logic such as not allowing a border tile to be the valid position for anything.
This tile is in the valid area within the border" is a condition that is easier to check, in fewer places, and your program can be structured so that this check is actually just a removable assertion (a check for a situation that should not happen if the program is correct, rather than a check for an expected situation).
In C and C++, we can displace the pointers so that position [0][0] is still the corner of the valid area, yet the out-of-bounds coordinates [-1][-1] are valid indices, as are [w][h].
Firstly, the column array is allocated two elements larger than necessary, and the pointer is the incremented by one. Then the columns are allocated two elements larger, and each pointer is incremented by one before being assigned into the main array.
When freeing the arrays with delete [], you have to remember to decrement each pointer by one.

Chess Validation Move input wanted

So, I have gotten quite far in my mission to finish a chess game in c++. However, I have hit a bit of a small issue I would like to get some input on, please.
SITUATION:
My PAWN, KING, KNIGHT move validations work perfect. But;
When moving a piece(such as a white ROOK) it follows most of the rules. For example, it will only move vertical or horizontal, it will not pass another white piece, it will not replace a white piece, and lastly it WILL replace a black (opposing) piece.
The problem is when moving it past a another black piece, it allows passing in order to replace a piece that's past it. So lets say we have a white piece at x=2,y=6 and black piece at x=2,y=4, and another black piece at x=2,y=3. The White piece will be allowed to move to move to x=2,y=3, which should not be allowed. Would love to get some input on how to fix this. Current code below.
bool Rook:: canMove(int startx, int starty, int endx, int endy)
{
int i;
if(board[endx][endy] !=NULL && board[endx][endy]->color==color)
return false;
if (startx == ends) //Collision Detection...
{
// Horizontal move
if (starty < endy)
{
// Move down
for (i = starty + 1; i <= endy; ++i)
if (board[startx][i] != NULL && board[startx][i]->color==color)
return false;
}
else
{
// Move up
for (i = starty - 1; i >= endy; --i)
if (board[startx][i] != NULL && board[startx][i]->color==color) //cant allow passing of non color piece
return false;
}
}
else if (starty == endy)
{
// Vertical move
if (startx < endx)
{
// Move right
for (i = startx + 1; i <= endx; ++i)
if (board[i][starty] != NULL && board[i][starty]->color==color)
return false;
}
else
{
// Move left
for (i = startx - 1; i >= endx; --i)
if (board[i][starty] != NULL && board[i][starty]->color==color)
return false;
}
}
else
{
// Not a valid rook move (neither horizontal nor vertical)
return false;
}
return true;
}
your function has refers to a lot of member variables in the class, e.g. ends, color, board, which isn't good, and makes the function hard to test at a unit level
can you test that function standalone? No you can't.
but it looks like your loops aren't breaking when they should (when they have found a valid move perhaps?)
if the function is allowing move to (2,3) as well as (2,4), then it is looping past (2,4) to (2,3)
also, just using an array and ints for indexing the board isn't very good.
i would have expected a higher-level board class and maybe a coordinate class so you can easily iterate and index the board.

Beginner having an issue with classes and functions

I am a beginner programmer working on a program in c++ visual studio 2015 that takes an instance of a class titled rect and passes it to a function within rect that sets a rectangle of random size and position somewhere on a imaginary board in a console window. At the bottom of the code there are full instructions on what the code needs to do. The problem I am having is when the program prints the rectangles, the rectangle of "0's" is not printing but the rectangle of "1's" is. The rectangle rect0 is being passed by reference and the rect1 is being passed by pointer.
/*
iLab2: rectangles
*/
#define NOMINMAX // prevent Windows API from conflicting with "min" and "max"
#include <stdio.h> // C-style output. printf(char*,...), putchar(int)
#include <windows.h> // SetConsoleCursorPosition(HANDLE,COORD)
#include <conio.h> // _getch()
#include <time.h>
/**
* moves the console cursor to the given x/y coordinate
* 0, 0 is the upper-left hand coordinate. Standard consoles are 80x24.
* #param x
* #param y
*/
void moveCursor(int x, int y)
{
COORD c = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
struct Vec2
{
short x, y; // variables x and y for storing rectangle coordinates
Vec2() : x(0), y(0) { } // default constructor for vect2 if no parameters are specified
Vec2(int x, int y) : x(x), y(y) { } // default constructor for vect2 if parameters are given
void operator+=(Vec2 v) // function for adding or subtracting (if v is negative) to move the rectangle
{
x += v.x;
y += v.y;
}
};
class Rect
{
Vec2 min, max;
public:
Rect(int minx, int miny, int maxx, int maxy)
:min(minx, miny), max(maxx, maxy)
{}
Rect() {}
void draw(const char letter) const
{
for (int row = min.y; row < max.y; row++)
{
for (int col = min.x; col < max.x; col++)
{
if (row >= 0 && col >= 0)
{
moveCursor(col, row);
putchar(letter);
}
}
}
}
void setMax(int maxx, int maxy)
{
this->max.x = maxx;
this->max.y = maxy;
}
void setMin(int minx, int miny)
{
this->min.x = minx;
this->min.y = miny;
}
bool isOverlapping(Rect const & r) const
{
return !(min.x >= r.max.x || max.x <= r.min.x
|| min.y >= r.max.y || max.y <= r.min.y);
}
void translate(Vec2 const & delta)
{
min+=(delta);
max+=(delta);
}
void setRandom(Rect & r);
void setRandom(Rect* r);
};
void Rect::setRandom(Rect & r)
{
srand(time(NULL)); // added to make the random placement and size of the rect different each time program runs
int pos_x, pos_y, height, width;
pos_x = rand() % 51;
pos_y = rand() % 21;
height = 2 + rand() % 11;
width = 2 + rand() % 11;
height = height / 2;
width = width / 2;
r.min.x = pos_x - width;
r.min.y = pos_y - height;
r.max.x = pos_x + width;
r.max.y = pos_y + height;
}
void Rect::setRandom(Rect * r)
{
srand(time(NULL)); // added to make the random placement and size of the rect different each time program runs
int posX, posY, heightPoint, widthPoint;
posX = rand() % 51;
posY = rand() % 21;
heightPoint = 2 + rand() % 11;
widthPoint = 2 + rand() % 11;
heightPoint = heightPoint / 2;
widthPoint = widthPoint / 2;
this->min.x = posX - widthPoint;
this->min.y = posY - heightPoint;
this->max.x = posX + widthPoint;
this->max.y = posY + heightPoint;
}
int main()
{
// initialization
//Rect userRect(7, 5, 10, 9); // (x-min, y-min, x-max, y-max) x-min how far left the rectange can be
//Rect rect0(10, 2, 14, 4); // (x-min, y-min, x-max, y-max)
//Rect rect1(1, 6, 5, 15); // (x-min, y-min, x-max, y-max)
//Rect userRect;
Rect * userRect;
Rect rect0;
Rect rect1;
const int rectSize = 5;
Rect rect[rectSize];
userRect = new Rect();
// set
rect[0].setRandom(rect[0]);
rect[1].setRandom(& rect[1]);
userRect->setMin(7, 5);
userRect->setMax(10, 9);
//rect0.setMin(10, 2);
//rect0.setMax(14, 4);
//rect1.setMin(1, 6);
//rect1.setMax(5, 15);
int userInput;
do
{
// draw
rect[0].draw('0'); // drawing the 0 rectangle with an x width of 4 and a y height of 2
rect[1].draw('1'); // drawing the 1 rectangle with a x width of 4 and a y height of 9
moveCursor(0, 0); // re-print instructions
printf("move with 'w', 'a', 's', and 'd'");
userRect->draw('#'); // drawing the user rectangle in its starting location with a x width of 3 and a y height of 4
// user input
userInput = _getch();
// update
Vec2 move;
switch (userInput)
{
case 'w': move = Vec2(0, -1); break; // Moves the user Rectangle -y or up on the screen
case 'a': move = Vec2(-1, 0); break; // Moves the user Rectangle -x or left on the screen
case 's': move = Vec2(0, +1); break; // Moves the user Rectangle +y or down on the screen
case 'd': move = Vec2(+1, 0); break; // Moves the user Rectangle +x or right on the screen
}
userRect->draw(' '); // un-draw before moving
userRect->translate(move); // moves the user rectangle to the new location
} while (userInput != 27); // escape key
delete userRect; // delete dynamic object to release memory
return 0;
}
// INSTRUCTIONS
// ------------
// 3) Random rectangles, by reference and by pointer
// a) create a method with the method signature "void setRandom(Rect & r)".
// This function will give the passed-in Rect object a random location.
// The random x should be between 0 and 50 x. The random y should be
// between 0 and 20. Limit the possible width and height to a minimum of 2
// and a maximum of 10.
// b) test "void setRandom(Rect & r)" on the local Rect object "rect0".
// c) create a method with the method signature
// "void setRandomByPointer(Rect * r)", which functions the same as
// "void setRandom(Rect & r)", except that the argument is
// passed-by-pointer.
// d) test "void setRandomByPointer(Rect * r)" on the local Rect object
// "rect1".
// 4) Test and show overlap
// a) Using the existing function "isOverlapping(Rect const &)", test to see
// if userRect collides with any other Rect objects. If userRect is
// overlapping, draw it with '+' instead '#'.
// b) Create a Rect * pointer that points to the address if the Rect object
// that userRect collides with. It should point at NULL if userRect is
// colliding with no other Rect objects.
// c) Print to the screen the width and height of a Rect object that userRect
// collides with. If no collision is happening, print "no collision"
// instead.
// 5) Array of objects
// a) Replace the Rect objects rect0 and rect1 with an array of 2 Rect
// objects, "rect[2]".
// b) Make sure you replace every remaining "rect0" with "rect[0]", and every
// "rect1" with "rect[1]".
// c) Increase the size of the "rect" array to 5. Make sure all 5 Rect
// objects are randomized, drawn to the screen, and tested for collision.
// d) If you have not already done so, replace
// duplicate-code-using-array-elements with a for-loop. For example:
// If you have:
// rect[0].draw('0');
// rect[1].draw('1');
// rect[2].draw('2');
// rect[3].draw('3');
// rect[4].draw('4');
// Replace it with:
// for(int i = 0; i < NUMBER_OF_RECTS; i++)
// {
// rect[i].draw('0'+i);
// }
// Do this where objects are randomized, drawn, and tested for collision
You have two different setRandom() methods with three problems.
Each time either setRandom() gets called, srand() also gets called. srand() should only be called once, when the program starts -- read the first answer to that question, carefully.
Code duplication. The code in both setRandom() is nearly identical. Code duplication is bad. Duplicated code means that if the algorithm needs to be changed in some way, you will have to remember to do it in two places. Or three places. Or four places. Or however many duplicate chunks of code exist in the code. You have to remember them all, and find them. If you miss one, bugs galore.
Same problem as #2, but for the "nearly identical" part. The difference is: the first version of setRandom() takes a reference to another object and modifies another object that's passed by reference. The second version of setRandom() takes a pointer to another object instead of a reference, but ignores it completely, and instead initializes this, instead of the pointed object.
And, as a result of these bugs, we get the results you're seeing.
rect[0].setRandom(rect0);
This ends up initializing rect0. rect[0] is ignored completely, and not initialized at all.
rect[1].setRandom(& rect1);
This ends up initializing rect[1]. rect1 is ignored completely, and not initialized at all.
And that's why the rest of the code fails to draw rect[0]. It does not get initialized at all.
The shown code is completely confused because it has four, and not two, objects. rect0, rect1, and the rect[] array containing two more objects. After they are declared, rect0 and rect1 are completely ignored, except for the misfired initialization, and they serve apparently no purpose whatsoever.
Neither is there any real reason here for setRandom() to take either a pointer or a reference to some other object. The apparent purpose of setRandom() is to initialize an object's dimensions randomly.
So it should simply initialize this's dimensions randomly. Passing some other object, by pointer or reference, makes no sense at all.
Then, after getting rid of rect0 and rect1, and simply calling a single setRandom() method...
rect[0].setRandom();
rect[1].setRandom();
... the rest of the code will proceed and properly draw two randomly-initialized objects.
the code Rect rect[ rectSize ] will create 5 rects to array rect and all of those rects are with min(0,0) max(0,0)(initial state). when you call rect[ 0 ].setRandom( rect0 ) which will update rect0(you pass it by reference) and do nothing to rect[0].when you call rect[ 1 ].setRandom( &rect1 ) you update rect[1] (by this->min.x = posX - some value).so you get difference between rect[0] and rect[1].

Tallest tower with stacked boxes in the given order

Given N boxes. How can i find the tallest tower made with them in the given order ? (Given order means that the first box must be at the base of the tower and so on). All boxes must be used to make a valid tower.
It is possible to rotate the box on any axis in a way that any of its 6 faces gets parallel to the ground, however the perimeter of such face must be completely restrained inside the perimeter of the superior face of the box below it. In the case of the first box it is possible to choose any face, because the ground is big enough.
To solve this problem i've tried the following:
- Firstly the code generates the rotations for each rectangle (just a permutation of the dimensions)
- secondly constructing a dynamic programming solution for each box and each possible rotation
- finally search for the highest tower made (in the dp table)
But my algorithm is taking wrong answer in unknown test cases. What is wrong with it ? Dynamic programming is the best approach to solve this problem ?
Here is my code:
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstring>
struct rectangle{
int coords[3];
rectangle(){ coords[0] = coords[1] = coords[2] = 0; }
rectangle(int a, int b, int c){coords[0] = a; coords[1] = b; coords[2] = c; }
};
bool canStack(rectangle &current_rectangle, rectangle &last_rectangle){
for (int i = 0; i < 2; ++i)
if(current_rectangle.coords[i] > last_rectangle.coords[i])
return false;
return true;
}
//six is the number of rotations for each rectangle
int dp(std::vector< std::vector<rectangle> > &v){
int memoization[6][v.size()];
memset(memoization, -1, sizeof(memoization));
//all rotations of the first rectangle can be used
for (int i = 0; i < 6; ++i) {
memoization[i][0] = v[0][i].coords[2];
}
//for each rectangle
for (int i = 1; i < v.size(); ++i) {
//for each possible permutation of the current rectangle
for (int j = 0; j < 6; ++j) {
//for each permutation of the previous rectangle
for (int k = 0; k < 6; ++k) {
rectangle &prev = v[i - 1][k];
rectangle &curr = v[i][j];
//is possible to put the current rectangle with the previous rectangle ?
if( canStack(curr, prev) ) {
memoization[j][i] = std::max(memoization[j][i], curr.coords[2] + memoization[k][i-1]);
}
}
}
}
//what is the best solution ?
int ret = -1;
for (int i = 0; i < 6; ++i) {
ret = std::max(memoization[i][v.size()-1], ret);
}
return ret;
}
int main ( void ) {
int n;
scanf("%d", &n);
std::vector< std::vector<rectangle> > v(n);
for (int i = 0; i < n; ++i) {
rectangle r;
scanf("%d %d %d", &r.coords[0], &r.coords[1], &r.coords[2]);
//generate all rotations with the given rectangle (all combinations of the coordinates)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
if(j != k) //micro optimization disease
for (int l = 0; l < 3; ++l)
if(l != j && l != k)
v[i].push_back( rectangle(r.coords[j], r.coords[k], r.coords[l]) );
}
printf("%d\n", dp(v));
}
Input Description
A test case starts with an integer N, representing the number of boxes (1 ≤ N ≤ 10^5).
Following there will be N rows, each containing three integers, A, B and C, representing the dimensions of the boxes (1 ≤ A, B, C ≤ 10^4).
Output Description
Print one row containing one integer, representing the maximum height of the stack if it’s possible to pile all the N boxes, or -1 otherwise.
Sample Input
2
5 2 2
1 3 4
Sample Output
6
Sample image for the given input and output.
Usually you're given the test case that made you fail. Otherwise, finding the problem is a lot harder.
You can always approach it from a different angle! I'm going to leave out the boring parts that are easily replicated.
struct Box { unsigned int dim[3]; };
Box will store the dimensions of each... box. When it comes time to read the dimensions, it needs to be sorted so that dim[0] >= dim[1] >= dim[2].
The idea is to loop and read the next box each iteration. It then compares the second largest dimension of the new box with the second largest dimension of the last box, and same with the third largest. If in either case the newer box is larger, it adjusts the older box to compare the first largest and third largest dimension. If that fails too, then the first and second largest. This way, it always prefers using a larger dimension as the vertical one.
If it had to rotate a box, it goes to the next box down and checks that the rotation doesn't need to be adjusted there too. It continues until there are no more boxes or it didn't need to rotate the next box. If at any time, all three rotations for a box failed to make it large enough, it stops because there is no solution.
Once all the boxes are in place, it just sums up each one's vertical dimension.
int main()
{
unsigned int size; //num boxes
std::cin >> size;
std::vector<Box> boxes(size); //all boxes
std::vector<unsigned char> pos(size, 0); //index of vertical dimension
//gets the index of dimension that isn't vertical
//largest indicates if it should pick the larger or smaller one
auto get = [](unsigned char x, bool largest) { if (largest) return x == 0 ? 1 : 0; return x == 2 ? 1 : 2; };
//check will compare the dimensions of two boxes and return true if the smaller one is under the larger one
auto check = [&boxes, &pos, &get](unsigned int x, bool largest) { return boxes[x - 1].dim[get(pos[x - 1], largest)] < boxes[x].dim[get(pos[x], largest)]; };
unsigned int x = 0, y; //indexing variables
unsigned char change; //detects box rotation change
bool fail = false; //if it cannot be solved
for (x = 0; x < size && !fail; ++x)
{
//read in the next three dimensions
//make sure dim[0] >= dim[1] >= dim[2]
//simple enough to write
//mine was too ugly and I didn't want to be embarrassed
y = x;
while (y && !fail) //when y == 0, no more boxes to check
{
change = pos[y - 1];
while (check(y, true) || check(y, false)) //while invalid rotation
{
if (++pos[y - 1] == 3) //rotate, when pos == 3, no solution
{
fail = true;
break;
}
}
if (change != pos[y - 1]) //if rotated box
--y;
else
break;
}
}
if (fail)
{
std::cout << -1;
}
else
{
unsigned long long max = 0;
for (x = 0; x < size; ++x)
max += boxes[x].dim[pos[x]];
std::cout << max;
}
return 0;
}
It works for the test cases I've written, but given that I don't know what caused yours to fail, I can't tell you what mine does differently (assuming it also doesn't fail your test conditions).
If you are allowed, this problem might benefit from a tree data structure.
First, define the three possible cases of block:
1) Cube - there is only one possible option for orientation, since every orientation results in the same height (applied toward total height) and the same footprint (applied to the restriction that the footprint of each block is completely contained by the block below it).
2) Square Rectangle - there are three possible orientations for this rectangle with two equal dimensions (for examples, a 4x4x1 or a 4x4x7 would both fit this).
3) All Different Dimensions - there are six possible orientations for this shape, where each side is different from the rest.
For the first box, choose how many orientations its shape allows, and create corresponding nodes at the first level (a root node with zero height will allow using simple binary trees, rather than requiring a more complicated type of tree that allows multiple elements within each node). Then, for each orientation, choose how many orientations the next box allows but only create nodes for those that are valid for the given orientation of the current box. If no orientations are possible given the orientation of the current box, remove that entire unique branch of orientations (the first parent node with multiple valid orientations will have one orientation removed by this pruning, but that parent node and all of its ancestors will be preserved otherwise).
By doing this, you can check for sets of boxes that have no solution by checking whether there are any elements below the root node, since an empty tree indicates that all possible orientations have been pruned away by invalid combinations.
If the tree is not empty, then just walk the tree to find the highest sum of heights within each branch of the tree, recursively up the tree to the root - the sum value is your maximum height, such as the following pseudocode:
std::size_t maximum_height() const{
if(leftnode == nullptr || rightnode == nullptr)
return this_node_box_height;
else{
auto leftheight = leftnode->maximum_height() + this_node_box_height;
auto rightheight = rightnode->maximum_height() + this_node_box_height;
if(leftheight >= rightheight)
return leftheight;
else
return rightheight;
}
}
The benefits of using a tree data structure are
1) You will greatly reduce the number of possible combinations you have to store and check, because in a tree, the invalid orientations will be eliminated at the earliest possible point - for example, using your 2x2x5 first box, with three possible orientations (as a Square Rectangle), only two orientations are possible because there is no possible way to orient it on its 2x2 end and still fit the 4x3x1 block on it. If on average only two orientations are possible for each block, you will need a much smaller number of nodes than if you compute every possible orientation and then filter them as a second step.
2) Detecting sets of blocks where there is no solution is much easier, because the data structure will only contain valid combinations.
3) Working with the finished tree will be much easier - for example, to find the sequence of orientations of the highest, rather than just the actual height, you could pass an empty std::vector to a modified highest() implementation, and let it append the actual orientation of each highest node as it walks the tree, in addition to returning the height.

Odd output from a for loop

I'm using a for loop to iterate through some arrays I've created representing regions that the mouse can hover over. Then when the loop confirms the mouse is in a region it saves the iteration variable to a public variable that is used later in the main function to highlight the region the mouse is over. The problem is that the for loop is not giving the right value for the first iteration through.
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid <= sizeof(grid_region); grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
}
grid_region is is made via "int grid_region[9];" and the strange part is that when I later do a print statement to see what "highlight" is when it's in grid_region[0] is prints 72. How is it possible that the iteration variable becomes 72 at any point in the loop??? Any help here? I later use highlight to apply a sprite in the grid_region and it's being applied incorrectly so this is a problem.
sizeof(grid_region) is the size in multiples of char, not the number of elements.
That is, it is sizeof(int) * 9, not nine, and apparently your int is 8 chars wide since you ended up at 72.
You can loop to < sizeof(grid_region) / sizeof(grid_region[0]) or, better, step into the 21st century and use std::vector, or std::array if your compiler is hip enough.