Buddy Allocation Algorithm - Heap Extension - c++

This is a second inquiry towards my implementation of a Buddy Allocation scheme, the first question is here, which also explains what Buddy Allocation actually is. In the standard implementation, one starts with a large block of 2^i where i is an integer, which works with a static heap size (the entire heap is the largest block in this case).
My question hinges on an implementation that deals with a dynamically sizing heap, where the heap size starts at 0. Currently, when the highest order i, cannot find a block in a free list (a list of free blocks), I make a call to extend the heap size in order to appropriate this highest order block.
The problem is that I am not sure if this derivative breaks the invariant within the buddy system, which is the calculation of the buddy block's address given an address. This simply can be computed via flipping the ith order bit. The explanation of this calculation is in my previous question. When I implement this scheme sometimes I return the wrong buddy address.

I'm not absolutely sure if you can increase the heap size after some blocks have already been allocated. I think you will have to increase your heap and reallocate all the blocks again, following the allocation algorithm, but now considering your new heap size.

#include <stdio.h>
typedef struct X
{
unsigned int address;
int empty;
int id_req;//id_req
int allow;
} Block;
typedef struct Y
{
int enz;
int id_req;//req_id
int ok;
} Defer;
unsigned int block_sizes[8] = {0};
unsigned int memSize;
unsigned int allcSize;
Block blocks[8][128];
int num_blocks[8];
int defer_pointer = 0;
Defer defers[100];
int main(int argc, char **argv)
{
int x, y, z;
for(x = 0;x < 100;x++)
defers[x].ok = 1;
for(x = 0;x < 8;x++)
for(y = 0;y < 128;y++)
blocks[x][y].empty = blocks[x][y].allow = 0;
scanf("%u", &memSize);
scanf("%u", &allcSize);
block_sizes[0] = allcSize;
for(x = 0;x+1 < 8;x++)
if(block_sizes[x] == memSize)
break;
else
block_sizes[x+1] = block_sizes[x]*2;
blocks[x][0].address = 0;
blocks[x][0].empty = 1;
num_blocks[x] = 1;
for(;x > 0;x--)
{
num_blocks[x-1] = num_blocks[x]*2;
for(y=0;y < num_blocks[x];y++)
{
blocks[x-1][2*y].address = blocks[x][y].address;
blocks[x-1][2*y+1].address = blocks[x][y].address + block_sizes[x-1];
}
}
while(scanf("%d", &z) != EOF)
{
char op = getchar();
while(op != '-' && op != '+') op = getchar();
if(op == '+')
{
unsigned int size;
scanf("%u", &size);
printf("Request ID %d: allocates %u byte%s.\n", z, size, size == 1 ? "" : "s");
int enz = 0;
while(block_sizes[enz] < size)
enz++;
unsigned int address;
if(allocate(enz, z, &address))
{
printf("\tSuccess; addr = 0x%08x.\n", address);
}
else
{
printf("\tRequest deferred.\n");
defers[defer_pointer].ok = 0;
defers[defer_pointer].enz = enz;
defers[defer_pointer].id_req = z;
defer_pointer++;
}
}
else
{
printf("Request ID %d: deallocate.\n", z);
int success = 0;
for(x = 0;x < 8 && block_sizes[x] != 0 && success != 1;x++)
for(y = 0;y < num_blocks[x] && success != 1;y++)
if(blocks[x][y].allow)
if (blocks[x][y].id_req == z)
{
blocks[x][y].allow = 0;
blocks[x][y].empty = 1;
success = 1;
}
x--;y--;
if(success)
printf("\tSuccess.\n");
else
continue;
// the buddy system
while(x < 8 && num_blocks[x] > 1)
{
int buddy = (blocks[x][y].address / block_sizes[x]) %2 == 0 ? (y+1) : (y- 1);
if(blocks[x][buddy].empty)
{
blocks[x][y].empty = 0;
blocks[x][buddy].empty = 0;
blocks[x+1][y/2].empty = 1;
x++;
y /= 2;
}
else
{
break;
}
}
for(x = 0;x < defer_pointer;x++)
if(!defers[x].ok)
{
unsigned int address;
if(allocate(defers[x].enz, defers[x].id_req, &address))
{
defers[x].ok = 1;
printf("\tDeferred request %d allocated; addr = 0x%08x\n", defers[x].id_req, address);
}
}
}
}
return 0;
}
int allocate(int enz, int id_req, unsigned int *address)
{
int x, y, ret = 0;
for(x = enz;x < 8 && block_sizes[x] != 0 && ret == 0;x++)
for(y = 0;y < num_blocks[x] && ret == 0;y++)
if(blocks[x][y].empty)
ret = 1;
x--;y--;
if(ret == 0)
return 0;
while(x != enz)
{
blocks[x][y].empty = 0;
blocks[x-1][2*y].empty = 1;
blocks[x-1][2*y+1].empty = 1;
x = x-1;
y = 2*y;
}
blocks[x][y].empty = 0;
blocks[x][y].id_req = id_req;
blocks[x][y].allow = 1;
*address = blocks[x][y].address;
}

Related

Corrupted memory issue when deleting allocated memory

I am trying to store a sparse vector using a bit mask. I allocate a char* to represent the bit mask. However, when I delete [] the mask, I get a memory corruption error. Upon investigation, I'm seeing that it's because I'm freeing memory that I'm not supposed to. This is confusing, since I don't see how this could be the case.
When I run this on my case, it prints out "ALLOCATED" and "DEALLOCATING" but nothing further.
void set_i_bit(char* mask, int i) {
int field_num = floor(i/8);
int bit_num = i %8;
mask[field_num] = (1 << bit_num) | mask[field_num];
}
int write_sparse_with_bitmask(vector<float> arr, ofstream* fout) {
int mx_sz = arr.size() - 1;
float tol = 0.5;
char* mask = 0;
for(int i = arr.size() -1; i>=0; i-=1) {
if (fabs(arr[i]) > tol) break;
mx_sz = i;
}
int sprse_cnt = 0;
for(int i = 0; i<=mx_sz; i+=1) {
if (fabs(arr[i]) < tol) sprse_cnt++;
}
int bitmask_sz = ceil(mx_sz/8);
if (sprse_cnt*sizeof(int16_t) + sizeof(int16_t) > bitmask_sz) {
cout<<"ALLOCATED"<<endl;
mask = new char[bitmask_sz];
for (int i =0; i<bitmask_sz; i++) mask[i] = 0;
for(int i = 0; i<=mx_sz; i+=1) {
if (fabs(arr[i]) > coef_tol) {
set_i_bit(mask, i);
}
}
}
else {
bitmask_sz = 0;
}
uint16_t sz = mx_sz + 1;
uint16_t bt_msk = bitmask_sz + 1;
char flag = 0;
if (bitmask_sz > 0) {
flag = flag | 1;
}
fout->write((char*)&sz, sizeof(uint16_t));
fout->write((char*)&flag, sizeof(char));
int w_size = sizeof(uint16_t) + sizeof(char);
if (flag & 1) {
fout->write((char*)&bt_msk, sizeof(uint16_t));
fout->write(mask, sizeof(char)*bt_msk);
cout<<"DEALLOCATING"<<endl;
delete [] mask;
cout<<"THIS DOESN'T PRINT"<<endl;
w_size += sizeof(uint16_t) + sizeof(char)*bt_msk;
}
for(int i = 0; i<=mx_sz; i+=1) {
if (fabs(arr[i]) > tol || !(flag & 1)) {
int16_t vl = arr[i];
fout->write((char*) &vl, sizeof(int16_t));
w_size += sizeof(int16_t);
}
}
return w_size;
}

Tetris Game array issue

So I'm trying to make a Tetris game and I've come across something odd that I'm unsure about.
I have an array called bottom which stores the value of the lowest block - so, if there is no block in the first column, "bottom" will be 20.
If there's a square block occupying that first column, bottom would be 18. The weird thing is, when I set a breakpoint in my code to try to view the values for bottom, it says there is only one value in the array. In addition, my board, which is a 25 by 10 array, has the same problem, it only displays one dimension.
It seems the problem has to do with some kind of pointer issue, because it says (int (*)[10]) and (int *), where I think it should be a (int [25][10]) and (int [10]). I tried looking up array pointers and references, but the main thing I found was how to make an array of pointers and I'm not really quite sure how to word my searches.
If someone might know what's going wrong please let me know!
main.cpp
#include <chrono>
#include "makeboard.h"
int main() {
//declares and defines board
int board[24][10];
for (int y = 0; y < 24; y++) {
for (int x = 0; x < 10; x++) {
board[y][x] = 0;
}
}
makeboard(board);
}
tiles.h
#ifndef tiles_h
#define tiles_h
class O {
int board[24][10];
int x, y;
public:
void set_O (int[24][10], int, int);
};
void O::set_O (int board[24][10], int y, int x) {
board[y][x] = 1;
board[y][x+1] = 1;
board[y-1][x] = 1;
board[y-1][x+1] = 1;
}
class I {
int board[24][10];
int x, y, d;
public:
void set_I (int[24][10], int, int, int);
};
void I::set_I (int board[24][10], int d, int y, int x) {
if (d == 1 || d == 3) {
board[y-3][x] = 1;
board[y-2][x] = 1;
board[y-1][x] = 1;
board[y][x] = 1;
}
if (d == 2 || d == 4) {
board[y][x-1] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
board[y][x+2] = 1;
}
}
class S {
int board[24][10];
int x, y, d;
public:
void set_S (int[24][10], int, int, int);
};
void S::set_S (int board[24][10], int d, int y, int x) {
if (d == 1 || d == 3) {
board[y-1][x] = 1;
board[y-1][x+1] = 1;
board[y][x] = 1;
board[y][x-1] = 1;
}
if (d == 2 || d == 4) {
board[y-2][x] = 1;
board[y-1][x] = 1;
board[y-1][x+1] = 1;
board[y][x+1] = 1;
}
}
class Z {
int board[24][10];
int x, y, d;
public:
void set_Z (int[24][10], int, int, int);
};
void Z::set_Z (int board[24][10], int d, int y, int x) {
if (d == 1 || d == 3) {
board[y][x] = 1;
board[y][x-1] = 1;
board[y+1][x] = 1;
board[y+1][x+1] = 1;
}
if (d == 2 || d == 4) {
board[y-1][x+1] = 1;
board[y][x+1] = 1;
board[y][x] = 1;
board[y+1][x] = 1;
}
}
class T {
int board[24][10];
int d, x, y;
public:
void set_T (int[24][10], int, int, int);
};
void T::set_T (int board[24][10], int d, int y, int x) {
if (d == 1 && (board[y+1][x-1] != 1 || board[y+1][x] != 1 || board[y+1][x+1] != 1)) {
board[y-1][x] = 1;
board[y][x-1] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
}
if (d == 2 && (board[y+2][x] != 1 || board[y+1][x+1] != 1)) {
board[y-1][x] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
board[y+1][x] = 1;
}
if (d == 3 && (board[y+1][x-1] != 1 || board[y+2][x] != 1 || board[y+1][x+1] != 1)) {
board[y][x-1] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
board[y+1][x] = 1;
}
if (d == 4 && (board[y+1][x-1] != 1 || board[y+2][x] != 1)) {
board[y-1][x] = 1;
board[y][x-1] = 1;
board[y][x] = 1;
board[y+1][x] = 1;
}
}
class J {
int board[24][10];
int d, x, y;
public:
void set_J (int[24][10], int, int, int);
};
void J::set_J (int board[24][10], int d, int y, int x) {
if (d == 1) {
board[y-1][x-1] = 1;
board[y-1][x] = 1;
board[y-1][x+1] = 1;
board[y][x+1] = 1;
}
if (d == 2) {
board[y-2][x] = 1;
board[y-1][x] = 1;
board[y][x] = 1;
board[y][x-1] = 1;
}
if (d == 3) {
board[y][x-1] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
board[y-1][x-1] = 1;
}
if (d == 4) {
board[y-2][x] = 1;
board[y-2][x+1] = 1;
board[y-1][x] = 1;
board[y][x] = 1;
}
}
class L {
int board[24][10];
int d, x, y;
public:
void set_L (int[24][10], int, int, int);
};
void L::set_L (int board[24][10], int d, int y, int x) {
if (d == 1) {
board[y-1][x-1] = 1;
board[y-1][x] = 1;
board[y-1][x+1] = 1;
board[y][x-1] = 1;
}
if (d == 2) {
board[y-2][x] = 1;
board[y-1][x] = 1;
board[y][x] = 1;
board[y][x-1] = 1;
}
if (d == 3) {
board[y-1][x-1] = 1;
board[y-1][x] = 1;
board[y-1][x+1] = 1;
board[y][x+1] = 1;
}
if (d == 4) {
board[y-2][x] = 1;
board[y-1][x] = 1;
board[y][x] = 1;
board[y][x+1] = 1;
}
}
#endif
makeboard.cpp
#include <iostream>
#include <limits>
#include <thread>
#include "makeboard.h"
#include "clearscreen.h"
#include "isBottom.h"
#include "isPressed.h"
#include "tiles.h"
using namespace std;
string icon[3] = { " ", " o ", " o " };
void makeboard(int board[24][10]) {
time_t srand( time(NULL) );
int block = srand % 7 ;
block = 3;
//declares pieces
O o;
I i;
S s;
Z z;
T t;
J j;
L l;
//declares and defines initial bottom
int bottom[10];
for (int i = 0; i < 10; i++) bottom[i] = 23;
//declares and defines initial block position
int y = 3;
int x = 4;
int d = 1;
while (!isBottom(board, block, y, x, d, bottom)) {
if (isPressed(0) && x > 0) {
x--;
}
if (isPressed(2) && x < 10) {
x++;
}
if (isPressed(1)) {
d += 1;
if (d == 4) {
d = 1;
}
}
//moves tile down
y++;
//clears screen
clearscreen();
//clears non set pieces
for (int i = 0; i < 24; i++) {
for (int j = 0; j < 10; j++) {
if (board[i][j] == 1) {
board[i][j] = 0;
}
}
}
//adds blocks to board
switch (block) {
case 1:
o.set_O(board, y, x);
break;
case 2:
i.set_I(board, d, y, x);
break;
case 3:
s.set_S(board, d, y, x);
break;
case 4:
z.set_Z(board, d, y, x);
break;
case 5:
t.set_T(board, d, y, x);
break;
case 6:
j.set_J(board, d, y, x);
break;
case 7:
l.set_L(board, d, y, x);
break;
}
//builds board
cout << "╔══════════════════════════════╗" << endl;
for (int i = 4; i < 24; i++) {
cout << "║";
for (int j = 0; j < 10; j++) {
cout << icon[board[i][j]] ;
}
cout << "║" << endl;
}
cout << "╚══════════════════════════════╝" << endl;
cout << " 0 1 2 3 4 5 6 7 8 9 " << endl;
//resets initial tile position
if (isBottom(board, block, y, x, d, bottom)) {
y = 2;
//block = srand % 7;
}
//ends game
if (isBottom(board, block, 3, x, d, bottom)) {
cout << "You lose!";
return;
}
//delay
this_thread::sleep_for (chrono::milliseconds(100));
}
return;
}
clearscreen.cpp
#include <unistd.h>
#include <term.h>
#include <stdlib.h>
#include "clearscreen.h"
void clearscreen()
{
if (!cur_term)
{
void *a;
int result;
setupterm( NULL, STDOUT_FILENO, &result );
a = malloc(sizeof(int) *result);
free (a);
if (result <= 0) free (a); return;
}
putp( tigetstr( "clear" ) );
}
isBottom.cpp
#include "isBottom.h"
bool isBottom(int board[24][10], int block, int y, int x, int d, int bottom[10]) {
switch (block) {
case 1:
if (y == bottom[x] || y == bottom[x+1]) {
board[y][x] = 2;
board[y][x+1] = 2;
board[y-1][x] = 2;
board[y-1][x+1] = 2;
bottom[x] -= 2;
bottom[x+1] -= 2;
return true;
}
return false;
break;
case 2:
if (d == 1 || d == 3) {
if (y == bottom[x]) {
board[y-3][x] = 2;
board[y-2][x] = 2;
board[y-1][x] = 2;
board[y][x] = 2;
bottom[x] -= 4;
return true;
}
return false;
break;
}
if (d == 2 || d == 4) {
if (y == bottom[x-1] || y == bottom[x] || y == bottom[x+1] || y == bottom[x+2]) {
board[y][x-1] = 2;
board[y][x] = 2;
board[y][x+1] = 2;
board[y][x+2] = 2;
bottom[x-1]--;
bottom[x]--;
bottom[x+1]--;
bottom[x+2]--;
return true;
}
return false;
break;
}
case 3:
if (d == 1 || d == 3) {
if (y == bottom[x-1] || y == bottom[x] || y == bottom[x+1]) {
board[y-1][x] = 2;
board[y-1][x+1] = 2;
board[y][x] = 2;
board[y][x-1] = 2;
bottom[x-1] = 23 - y;
bottom[x] -= 2;
bottom[x+1] -= 2;
return true;
break;
}
return false;
break;
}
if (d == 2 || d == 4) {
if (y == bottom[x-1] || y == bottom[x]) {
board[y-2][x] = 2;
board[y-1][x] = 2;
board[y-1][x+1] = 2;
board[y][x+1] = 2;
bottom[x-1]--;
bottom[x] -= 1;
return true;
break;
}
return false;
break;
}
/*
case 3:
s.set_S(board, d, y, x);
break;
case 4:
z.set_Z(board, d, y, x);
break;
case 5:
t.set_T(board, d, y, x);
break;
case 6:
j.set_J(board, d, y, x);
break;
case 7:
l.set_L(board, d, y, x);
break;
*/
}
return true;
}
isPressed.cpp
#include <Carbon/Carbon.h>
#include "isPressed.h"
bool isPressed( unsigned short inKeyCode )
{
unsigned char keyMap[16];
GetKeys((BigEndianUInt32*) &keyMap);
return (0 != ((keyMap[ inKeyCode >> 3] >> (inKeyCode & 7)) & 1));
}
It depends on the scope of your array. For example:
int GetBottom(int* bottom);
int GetBottom2(const int (&bottom)[20]);
int main()
{
int localArray1d[20] = {};
int localArray2d[10][25] = {};
// putting a breakpoint here will allow you to see the full dimensions of the array because this function KNOWS what the object is (e.g. a 1d and 2d array respectively)
int lastBrick = GetBottom(localArray1d);
// When the array is passed to GetBottom, it's passed just as a pointer. Although it IS an array, the function GetBottom doesn't know that. We could just as simply pass it a single int*
int n = 0;
GetBottom(&n); // here we are only passing a single int pointer. GetBottom has no idea that your object is an array, it only knows it has an int*
lastBrick = GetBottom2(localArray1d);
// GetBottom2 only takes an array of 20 elements, so inspecting the object in that function allows you to see all the elements.
return 0;
}
int GetBottom(int* bottom)
{
// Having a breakpoint here will not allow you to see all the elements in an array since this function doesn't even know bottom IS an array.
}
int GetBottom2(const int (&bottom)[20])
{
// A breakpoint here will allow you to fully inspect bottom.
}
It's a little tricky when you refer to arrays the way you do, but an array like int array[5] degrades to int* array when you branch outside the scope in which it is defined. It's because arrays are r-values and need to degrade into a reference or pointer l-value (which lacks that info about how many elements there are) to pass them around. The gotcha part here is that you can still write a function which accepts int parameter[5] and the compiler will accept it, but will silently treat it like int* parameter. The same goes for the debugger.
So depending on your debugger, there's different ways to look at all the elements through a pointer anyway. For example, with this code:
int* ptr = some_array;
... in MSVC, I can only see the first element pointed to by ptr in the watch window. However, if I know that some_array has 10 elements, I can type ptr,10 in the watch window and it'll show me all 10 elements.
Also, again this is debugger-specific, but some debuggers are conveniently programmed to show the contents of standard containers no matter what in a beautifully-readable format. So if you can use contaners like std::vector, it'll make your debugging life easier if you're using such a debugger.

Placing random numbers in a grid

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...

C++ Not Counting white beands

I need some help. I'm writing a code in C++ that will ultimately take a random string passed in, and it will do a break at every point in the string, and it will count the number of colors to the right and left of the break (r, b, and w). Here's the catch, the w can be either r or b when it breaks or when the strong passes it ultimately making it a hybrid. My problem is when the break is implemented and there is a w immediately to the left or right I can't get the program to go find the fist b or r. Can anyone help me?
#include <stdio.h>
#include "P2Library.h"
void doubleNecklace(char neck[], char doubleNeck[], int size);
int findMaxBeads(char neck2[], int size);
#define SIZE 7
void main(void)
{
char necklace[SIZE];
char necklace2[2 * SIZE];
int brk;
int maxBeads;
int leftI, rightI, leftCount = 0, rightCount=0, totalCount, maxCount = 0;
char leftColor, rightColor;
initNecklace(necklace, SIZE);
doubleNecklace(necklace, necklace2, SIZE);
maxBeads = findMaxBeads(necklace2, SIZE * 2);
checkAnswer(necklace, SIZE, maxBeads);
printf("The max number of beads is %d\n", maxBeads);
}
int findMaxBeads(char neck2[], int size)
{
int brk;
int maxBeads;
int leftI, rightI, leftCount = 0, rightCount=0, totalCount, maxCount = 0;
char leftColor, rightColor;
for(brk = 0; brk < 2 * SIZE - 1; brk++)
{
leftCount = rightCount = 0;
rightI = brk;
rightColor = neck2[rightI];
if(rightI == 'w')
{
while(rightI == 'w')
{
rightI++;
}
rightColor = neck2[rightI];
}
rightI = brk;
while(neck2[rightI] == rightColor || neck2[rightI] == 'w')
{
rightCount++;
rightI++;
}
if(brk > 0)
{
leftI = brk - 1;
leftColor = neck2[leftI];
if(leftI == 'w')
{
while(leftI == 'w')
{
leftI--;
}
leftColor = neck2[leftI];
}
leftI = brk - 1;
while(leftI >= 0 && neck2[leftI] == leftColor || neck2[leftI] == 'w')
{
leftCount++;
leftI--;
}
}
totalCount = leftCount + rightCount;
if(totalCount > maxCount)
{
maxCount = totalCount;
}
}
return maxCount;
}
void doubleNecklace(char neck[], char doubleNeck[], int size)
{
int i;
for(i = 0; i < size; i++)
{
doubleNeck[i] = neck[i];
doubleNeck[i+size] = neck[i];
}
}
I didn't study the code in detail, but something is not symmetric: in the for loop, the "left" code has an if but the "right" code doesn't. Maybe you should remove that -1 in the for condition and add it as an if for the "right" code:
for(brk = 0; brk < 2 * SIZE; brk++)
{
leftCount = rightCount = 0;
if (brk < 2 * SIZE - 1)
{
rightI = brk;
rightColor = neck2[rightI];
//...
}
if(brk > 0)
{
leftI = brk - 1;
leftColor = neck2[leftI];
//...
}
//...
Just guessing, though... :-/
Maybe you should even change those < for <=.

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)