Loop through 2D array diagonally with random board size - c++

I was wondering how I can loop through a two dimentional array if the size of the array is random, e.g 6x6 or 10x10 etc. The idea is to search for four of the same kind of characters, 'x' or 'o'. This is typically needed for a board game.
int main() {
int array_size = 5; // Size of array
int array_height = array_size;
bool turn = true; // true = player 1, false = player 2
bool there_is_a_winner = false;
char** p_connect_four = new char*[array_size];
for (int i = 0; i < array_size; i++) // Initialise the 2D array
{ // At the same time set a value "_" as blank field
p_connect_four[i] = new char[array_size];
for (int j = 0; j < array_size; j++) {
p_connect_four[i][j] = '_';
}
}
}
This is what I have so far, checking from [3][0] to [0][3]. But this requires me to add 2 more for loops to check [4][0] to [0][4] and [4][1] to [1][4] IF the size of the board was 5x5.
for (int i = 3, j = 0; i > 0 && j < array_size; i--, j++ ) {// CHECK DOWN up right from 3,0 -> 0,3
if (p_connect_four[i][j] == p_connect_four[i - 1][j + 1] && p_connect_four[i][j] != '_' ) {
check_diagonalRight++;
if (check_diagonalRight == 3) {
there_is_a_winner = true;
break;
}
}
else {
check_diagonalRight = 0;
}
}
if (there_is_a_winner) { // Break while loop of game.
break;
}
Obviously I want to check the whole board diagonally to the right regardless of the size of the board. Is there any other way than having 3 separate for loops for checking
[3][0] -> [0][3] , [4][0] -> [0][4] and [4][1]-> [1][4] ?

for (i = array_size - 1, j = array_size - 2;
i < array_size && i >= 0, j < array_size && j >= 0; j--)
{ // starts from [4][3] and loops to the left if arraysize = 5x5
// but works on any size
int k = i, l = j;
for (k, l; k < array_size && k > 0, l < array_size && l > 0; k--, l++)
{ // checks diagonally to the right
if (check_diagonalRight == 3)
{
there_is_a_winner = true;
break;
}
if (p_connect_four[k][l] == p_connect_four[k - 1][l + 1] &&
p_connect_four[k][l] != '_')
{ //check up one square and right one square
check_diagonalRight++;
}
else
{
check_diagonalRight = 0;
// if its not equal, reset counter.
}
}
if (there_is_a_winner)
{
break; // break for loop
}
}
if (there_is_a_winner)
{
break; // break while loop of game
}
This checks up and right no matter the size, implement it for the other angles as well and it will work for any board size. You could potentially check right and left diagonal at once with nested loops.

This will work perfectly fine for your program! I hope so!
int arraySize = 8;
for(int i=0, j=0; i<arraySize && j<arraySize; i++, j++)
{
if((i == 0 && j == 0) || (i == arraySize - 1 && j == arraySize - 1))
{
continue;
}
else
{
int k = i;
int l = j;
//This Loop will check from central line (principal diagonal) to up right side (like slash sign / (representing direction))
for(k, l; k>0 && l < arraySize - 1; k--, l++)
{
//Here check your condition and increment to your variable. like:
if (p_connect_four[k][l] == p_connect_four[k - 1][l + 1] && p_connect_four[k][l] != '_' )
{
check_diagonalRight++;
}
}
//You can break the loop here if check_diagonalRight != k then break
k = i;
l = j;
//This Loop will check from central line (principal diagonal) to down left side (like slash sign / (representing direction))
for(k, l; k<arraySize - 1 && l > 0; k++, l--)
{
//Here check your condition and increment to your variable. like:
if (p_connect_four[k][l] == p_connect_four[k + 1][l - 1] && p_connect_four[k][l] != '_' )
{
check_diagonalRight++;
}
}
if(check_diagonalRight == i+j+1)
{
there_is_a_winner = true;
break;
}
}
}

I suggest to surround your board with extra special cases to avoid to check the bound.
To test each direction I suggest to use an array of offset to apply.
Following may help:
#include <vector>
using board_t = std::vector<std::vector<char>>;
constexpr const std::size_t MaxAlignment = 4;
enum Case {
Empty = '_',
X = 'X',
O = 'O',
Bound = '.'
};
enum class AlignmentResult { X, O, None };
// Create a new board, valid index would be [1; size] because of surrounding.
board_t new_board(std::size_t size)
{
// Create an empty board
board_t board(size + 2, std::vector<char>(size + 2, Case::Empty));
// Add special surround.
for (std::size_t i = 0; i != size + 2; ++i) {
board[0][i] = Case::Bound;
board[size + 1][i] = Case::Bound;
board[i][0] = Case::Bound;
board[i][size + 1] = Case::Bound;
}
return board_t;
}
// Test a winner from position in given direction.
AlignmentResult test(
const board_t& board,
std::size_t x, std::size_t y,
int offset_x, int offset_y)
{
if (board[x][y] == Case::Empty) {
return AlignmentResult::None;
}
for (std::size_t i = 1; i != MaxAlignment; ++i) {
// Following condition fails when going 'out of bound' thanks to Case::Bound,
// else you have also to check size...
if (board[x][y] != board[x + i * offset_x][y + i * offset_y]) {
return AlignmentResult::None;
}
}
if (board[x][y] == Case::X) {
return AlignmentResult::X;
} else {
return AlignmentResult::O;
}
}
// Test a winner on all the board
AlignmentResult test(const board_t& board)
{
// offset for direction. Use only 4 direction because of the symmetry.
const int offsets_x[] = {1, 1, 1, 0};
const int offsets_y[] = {-1, 0, 1, 1};
const std::size_t size = board.size() - 1;
for (std::size_t x = 1; x != size; ++x) {
for (std::size_t y = 1; y != size; ++y) {
for (std::size_t dir = 0; dir != 4; ++dir) { // for each directions
auto res = test(board, x, y, offsets_x[dir], offsets_y[y]);
if (res != AlignmentResult::None) {
return res;
}
}
}
}
return AlignmentResult::None;
}

Related

Problem when inserting in a Sparse Matrix

I have to implement the CSR matrix data structure in C++ using 3 dynamic arrays (indexing starts at 0) and I've got stuck. So I have to implement 2 functions:
1) modify(int i, int j, TElem e) - modifies the value of (i,j) to e or adds if (if it does not exist) or deletes it if e is null.
2) element(int i, int j) const - returns the value found on (i,j)
I wanted to test my code in the next way:
Matrix m(10, 10);
for (int j = 0; j < m.nrColumns(); j++) {
m.modify(4, j, 3);
}
for (int i = 0; i < m.nrLines(); i++)
for (int j = 0; j < m.nrColumns(); j++)
if (i == 4)
assert(m.element(i, j) == 3);
else
assert(m.element(i, j) == NULL_TELEM);
And I got a surprise to see that m.element(4,j) will be 0 for j in the range (0,8) and only 3 for j=9.
This is my implementation of element(int i, int j) :
int currCol;
for (int pos = this->lines[i]; pos < this->lines[i+1]; pos++) {
currCol = this->columns[pos];
if (currCol == j)
return this->values[pos];
else if (currCol > j)
break;
}
return NULL_TELEM;
The constructor looks like this:
Matrix::Matrix(int nrLines, int nrCols) {
if (nrLines <= 0 || nrCols <= 0)
throw exception();
this->nr_lines = nrLines;
this->nr_columns = nrCols;
this->values = new TElem[1000];
this->values_capacity = 1;
this->values_size = 0;
this->lines = new int[nrLines + 1];
this->columns = new TElem[1000];
this->columns_capacity = 1;
this->columns_size = 0;
for (int i = 0; i <= nrLines; i++)
this->lines[i] = NULL_TELEM;
}
This is the "modify" method:
TElem Matrix::modify(int i, int j, TElem e) {
if (i < 0 || j < 0 || i >= this->nr_lines || j >= nr_columns)
throw exception();
int pos = this->lines[i];
int currCol = 0;
for (; pos < this->lines[i + 1]; i++) {
currCol = this->columns[pos];
if (currCol >= j)
break;
}
if (currCol != j) {
if (!(e == 0))
add(pos, i, j, e);
}
else if (e == 0)
remove(pos, i);
else
this->values[pos] = e;
return NULL_TELEM;
}
And this is the inserting method:
void Matrix::add(int index, int line, int column, TElem value)
{
this->columns_size++;
this->values_size++;
for (int i = this->columns_size; i >= index + 1; i--) {
this->columns[i] = this->columns[i - 1];
this->values[i] = this->values[i - 1];
}
this->columns[index] = column;
this->values[index] = value;
for (int i = line + 1; i <= this->nr_lines; i++)
this->lines[i]++;
}
Can somebody help me, please? I can't figure out why this happens and I really need to finish this implementation these days. It's pretty weird that is sees those positions having the value 0.
So having the next test that starts in the next way, I get a memory acces violation:
Matrix m(200, 300);
for (int i = m.nrLines() / 2; i < m.nrLines(); i++) {
for (int j = 0; j <= m.nrColumns() / 2; j++)
{
int v1 = j;
int v2 = m.nrColumns() - v1 - 1;
if (i % 2 == 0 && v1 % 2 == 0)
m.modify(i, v1, i * v1);
else
if (v1 % 3 == 0)
m.modify(i, v1, i + v1);
if (i % 2 == 0 && v2 % 2 == 0)
m.modify(i, v2, i * v2);
else
if (v2 % 3 == 0)
m.modify(i, v2, i + v2);
}
The error is thrown in the method "modify" at currCol = this->column[pos];
And if I look into the debugger it looks like:i=168, lines[i]=-842150451, lines[i+1]=10180,pos=-842150451.
Does anybody have any ideas why it looks this way?
Your code has two small errors.
When you try to find the insertion position in modify, you loop over the non-empty elements in the row:
int currCol = 0;
for (; pos < this->lines[i + 1]; i++) {
currCol = this->columns[pos];
if (currCol >= j)
break;
}
Here, you must update pos++ in each iteration instead of i++.
The second error occurs when you insert an element into column 0. The currCol will be zero, but your condition for adding a new element is
if (currCol != j) {
if (!(e == 0))
add(pos, i, j, e);
}
But j is zero, too, so nothing will be inserted. You can fix this by starting with a non-existing column:
int currCol = -1;

Sparse matrix compressed on rows in C++

I have to implement the CSR matrix data structure in C++ using 3 dynamic arrays (indexing starts at 0) and I've got stuck. So I have to implement 2 functions:
1) modify(int i, int j, TElem e) - modifies the value of (i,j) to e or adds if (if it does not exist) or deletes it if e is null.
2) element(int i, int j) const - returns the value found on (i,j)
I wanted to test my code in the next way:
Matrix m(4,4); m.print(); It will print:
Lines: 0 0 0 0 0
Columns:
Values:
(And this is fine)
Now if I want to modify: m.modify(1,1,5); //The element (1,1) will be set to 5
The output of m.print(); will be:
Lines: 0 1 1 1 1
Columns: 1
Values: 5 (which again is fine)
And now if I want to print m.element(1, 1) it will return 0 and m.element(0, 1) will return 5.
This is my implementation of element(int i, int j) :
int currCol;
for (int pos = this->lines[i]; pos < this->lines[i+1]; pos++) {
currCol = this->columns[pos];
if (currCol == j)
return this->values[pos];
else if (currCol > j)
break;
}
return NULL_TELEM;
The constructor looks like this:
Matrix::Matrix(int nrLines, int nrCols) {
if (nrLines <= 0 || nrCols <= 0)
throw exception();
this->nr_lines = nrLines;
this->nr_columns = nrCols;
this->values = new TElem[100];
this->values_capacity = 1;
this->values_size = 0;
this->lines = new int[nrLines + 1];
this->columns = new TElem[100];
this->columns_capacity = 1;
this->columns_size = 0;
for (int i = 0; i <= nrLines; i++)
this->lines[i] = NULL_TELEM;
}
This is the "modify" method:
TElem Matrix::modify(int i, int j, TElem e) {
if (i < 0 || j < 0 || i >= this->nr_lines || j >= nr_columns)
throw exception();
int pos = this->lines[i];
int currCol = 0;
for (; pos < this->lines[i + 1]; i++) {
currCol = this->columns[pos];
if (currCol >= j)
break;
}
if (currCol != j) {
if (!(e == 0))
add(pos, i, j, e);
}
else if (e == 0)
remove(pos, i);
else
this->values[pos] = e;
return NULL_TELEM;
}
And this is the inserting method:
void Matrix::add(int index, int line, int column, TElem value)
{
this->columns_size++;
this->values_size++;
for (int i = this->columns_size; i >= index + 1; i--) {
this->columns[i] = this->columns[i - 1];
this->values[i] = this->values[i - 1];
}
this->columns[index] = column;
this->values[index] = value;
for (int i = line; i <= this->nr_lines; i++) //changed to i = line + 1;
this->lines[i]++;
}
Can somebody help me, please? I can't figure out why this happens and I really need to finish this implementation these days.
It just can't pass the next test. And if I want to print the elements i have (4,0)=0 (4,1)=0 ... (4,8)=0 and (4,9)=3. Now this looks pretty weird why it happens.
void testModify() {
cout << "Test modify" << endl;
Matrix m(10, 10);
for (int j = 0; j < m.nrColumns(); j++)
m.modify(4, j, 3);
for (int i = 0; i < m.nrLines(); i++)
for (int j = 0; j < m.nrColumns(); j++)
if (i == 4)
assert(m.element(i, j) == 3);
//cout << i << " " << j << ":" << m.element(i, j)<<'\n';
else
assert(m.element(i, j) == NULL_TELEM);
}
When you call modify(1, 1, 5) with an empty matrix (all zeros), that results in a call to add(0, 1, 1, 5). That increments columns_size and values_size (both to 1), the for loop body will not execute, you update columns[0] to 1 and values[0] to 5, then increment all the lines values starting at element lines[1], setting them all to 1 (lines[0] will still be 0). But lines[1] should indicate the element we just added, so it should be 0, since the value is found using columns[0].
The for loop at the end of add should start at element line + 1.

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

How to calculate bit transitions using bitset < >

I am new to C++. I want to calculate the no of transitions from 0 to 0, 0 to 1, 1 to 0 and 1 to 1 in a 9 bit sequence. I have written the following code;
int main {
srand((unsigned)time(0));
unsigned int x;
for (int i=0:i<=512;i++) // loop-1
{
x=rand()%512;
bitset<9>bitseq(x);
for(int j=0;j<=bitseq.size();j++) // loop-2
{
bool a= bitseq.test(j);
bool b= bitseq.test(j+1)
if ((a==0)&(b==0)==0)
{
transition0_0 = transition0_0 + 1; // transition from 0 to 0
}
else if ((a==0)&(b==1)==0)
{
transition0_1 = transition0_1 + 1;
else if ((a==1)&(b==0)==0)
{
transition1_0 = transition1_0 + 1;
else
{
transition1_1 = transition1_1 + 1;
cout<<transition0_0<<" "<<transition0_1<<endl;
cout<<transition1_0<<" "<<transition1_1<<endl;
}
}
Somebody please guide me on the following
how to save the last bit value in loop-2 to check the transition from last bit of the last bitset output to the 1st bit of the next bitset output?
If this does not work, How I can save it in vector and use iterators to check the transitions?
First of all, the loop index j is running past the end of the bitset. Indices go from 0 to bitseq.size()-1 (inclusive). If you're going to test j and j+1 the largest value j can take is bitseq.size()-2.
Second, the ==0 part that appears in your ifs is strange, you should just use
if( (a==0)&&(b==0) )
Notice the use of two &&. While a single & works for this code, I think it's better to use the operator that correctly conveys your intentions.
And then to answer your question, you can keep a "last bit" variable that is initially set to a sentinel value (indicating you're seeing the first bitseq just now) and compare it to bitseq[0] before the start of loop 2. Here's a modified version of your code that should do what you ask.
int main {
srand((unsigned)time(0));
unsigned int x;
int transition0_0 = 0,
transition0_1 = 0,
transition1_0 = 0,
transition1_1 = 0;
int prev = -1;
for (int i=0:i<=512;i++) // loop-1
{
x=rand()%512;
bitset<9> bitseq(x);
if( prev != -1 ) // don't check this on the first iteration
{
bool cur = bitseq.test(0);
if( !prev && !cur )
++transition0_0;
else if( !prev && cur )
++transition0_1;
else if( prev && !cur )
++transition1_0;
else
++transition1_1;
}
for(int j=0;j+1<bitseq.size();j++) // loop-2
{
bool a= bitseq.test(j);
bool b= bitseq.test(j+1)
if ((a==0)&&(b==0))
{
transition0_0 = transition0_0 + 1; // transition from 0 to 0
}
else if ((a==0)&&(b==1))
{
transition0_1 = transition0_1 + 1;
}
else if ((a==1)&&(b==0))
{
transition1_0 = transition1_0 + 1;
}
else
{
++transition1_1 = transition1_1 + 1;
}
} // for-2
prev = bitseq.test(bitseq.size()-1); // update prev for the next iteration
cout<<transition0_0<<" "<<transition0_1<<endl;
cout<<transition1_0<<" "<<transition1_1<<endl;
} // for-1
} // main
Would something like this be better for you? Use an array of 4 ints where [0] = 0->0, [1] = 0->1, [2] = 1->0, [3] = 1->1.
int main {
int nTransition[] = { 0,0,0,0 };
bool a,b;
unsigned int x;
int j;
srand ((unsigned)time(0));
for (int i = 0: i < 512; i++) {
x = rand () % 512;
bitset<9> bitseq(x);
if (i == 0) {
a = bitseq.test (0);
j = 1;
} else
j = 0;
for (; j < bitseq.size (); j++) {
b = bitseq.test(j);
int nPos = (a) ? ((b) ? 3 : 2) : ((b) ? 1 : 0);
nTransition[nPos]++;
a = b;
}
}
}