void setPosition( std::vector< Block >& blocks, bool started )
Don't do that. Use something separate to set the initial position. Like, for example, constructor parameters for the blocks that you put into the vector the first time.
else { blocks[0].rect->x = POS_1; blocks[1].rect->x = POS_2; }
And here's why. What happens is, when 'started' is true, you use this code to set the start positions of the blocks, but then you go on ahead and do the rest of the function anyway, scrubbing out those values.
if( j == 0 ) temp = true; else temp = false;
This is needlessly complicated. You can map integers to booleans directly:
temp = static_cast<bool>(j);
But in fact, we can do much, much better if we first take a step back and write out what we want to do in pseudocode, and then select the appropriate tools.
The x position 0 corresponds to column 0; 220 to 1; 440 to 2.That is, we can multiply the column index by 220 to get its pixel position, anddivide pixel position by 220 to get the column.Repeat: Select as many columns as we have blocks.until our selection does not exactly correspond to the current positions.Put each block into the corresponding column, by setting its pixel position.
Now, you already know how to check if a two sequences of values are identical: with std::equal. Oh, wait, that's not std::equal you're using, judging by the arguments, but instead a function you whipped up quickly yourself to compare arrays of 3 booleans. Well, never mind that; the standard library provides a much more powerful comparer. :)
It so happens that the library also provides a function to select a specific number of elements from a sequence randomly: it's called random_sample. (Well, actually that will fill some output range with a sample, according to the size of that output range; but it's easy enough for us to just make a vector of the desired size and then fill the entire vector from .begin() to .end().) All we need to do let our values be column-indices, rather than Blocks. And then, the sequence we're "sampling" is just a set of numbers from 0 to N-1 in order. (The original STL provided a function to create that, too, but unfortunately it's one of the few things that didn't make it into the C++ standard library.)
It also provides a way to fill an output range with values corresponding to an input range, given the correspondence: it's called std::transform. We can define the process "given a block, figure out what column it's in" (trivially), and use that to get a vector giving the current column-indices.
The rest pretty much writes itself...
const int COLUMN_WIDTH = 220;int columnOf(Block& b){ return b.rect->x / 220;}std::vector<Block> initialBlocks(){ // Instead of trying to setPosition() outside the main loop, // we us a function that creates the initial vector with everything // already in position. std::vector<Block> result(2); result[0].rect->x = 0; result[1].rect->x = 1 * COLUMN_WIDTH; // or something like that, anyway. return result;}void setPosition(std::vector<Block>& blocks){ std::vector<int> current_positions(blocks.size()); std::transform(blocks.begin(), blocks.end(), current_positions.begin(), &columnOf); // For a small, known number of columns, this is easiest: int all_positions[3] = {0, 1, 2}; // We have serious problems if there are more blocks than columns! assert(blocks.size() <= 3); std::vector<int> new_positions(blocks.size()); do { std::random_sample( all_positions, all_positions + 3, new_positions.begin(), new_positions.end() ); } while (std::equal(new_positions.begin(), new_positions.end(), current_positions().begin)); // Now we have two "parallel" vectors to iterate over... in C++, // this is probably easiest with an old-fashioned for-loop for (int i = 0; i < blocks.size(); ++i) { blocks.rect->x = COLUMN_WIDTH * new_positions; blocks.rect->y = 0; }}
Yes, It's Really That Simple(TM).
We could probably do even better with a better-designed Block class, though.
In particular, why do you have a pointer to a rect? Why not just put the rect into the Block directly? Are you trying to share them or something?