C++ Passing 2D Arrays - c++

I am trying to create a minesweeper game that loads the board from a flat file (no, it's not random). As per the assignment instructions, I am to pass a 2d array to a load function which will then parse the file which was passed as a command-line arguement.
Anyway, my problem is passing the 2D array. What is the proper way to go about doing it? Below is the code that I have thus-far:
#include <iostream>
using namespace std;
struct Tile
{
bool mine, visible;
int danger;
};
bool loadBoard( Tile **board, string filename );
const int gridSize = 6;
int main( int argc, char* argv[] )
{
Tile board[ gridSize ][ gridSize ];
loadBoard( board, argv[ 1 ] );
system("PAUSE");
return EXIT_SUCCESS;
}
bool loadBoard( Tile **board, string filename ) {
}

Since you're using C++, why not use
std::vector<std::vector<Tile>>
in preference to a C-style array?
Since you seem to need to use C-style arrays, you could use the approach arpanchaudhury suggests or you could pass Tile* and do something like
static void loadBoard(Tile *board, int rows, int cols, string filename) {
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
Tile* tile = &board[(row*gridSize)+col];
// populate Tile
}
}
}

In case you want to to pass the 2d-array please specify number of columns in the array.
bool loadBoard( Tile board[][size], string filename ) {}
though it is preferable to use vectors instead of simple arrays since you need not specify a pre-defined size

As long as you're using C++...
#include <iostream>
using namespace std;
struct Tile
{
bool mine, visible;
int danger;
};
// load a square board of declared-size.
template<size_t N>
void loadboard( Tile (&board)[N][N], const std::string& filename)
{
// load board here.
cout << "Loading from file: " << filename << endl;
for (size_t i=0;i<N;++i)
{
cout << "board[" << i << "]: [ ";
for (size_t j=0;j<N;++j)
{
// load element board[i][j] here
cout << j << ' ';
}
cout << ']' << endl;
}
cout << endl;
}
int main()
{
Tile board[6][6];
loadboard(board, "yourfilename.bin"); // OK dims are the same
Tile smaller[3][3];
loadboard(smaller, "anotherfile.bin"); // OK. dims are the same
// Tile oddboard[5][6];
// loadboard(oddboard, "anotherfile.bin"); // Error: dims are not the same.
return 0;
}
Output
Loading from file: yourfilename.bin
board[0]: [ 0 1 2 3 4 5 ]
board[1]: [ 0 1 2 3 4 5 ]
board[2]: [ 0 1 2 3 4 5 ]
board[3]: [ 0 1 2 3 4 5 ]
board[4]: [ 0 1 2 3 4 5 ]
board[5]: [ 0 1 2 3 4 5 ]
Loading from file: anotherfile.bin
board[0]: [ 0 1 2 ]
board[1]: [ 0 1 2 ]
board[2]: [ 0 1 2 ]
Of course, there are probably "specific instructions" to not use the templates feature of the language either. Then again, I bet those instructions don't include having SO users solve your problem either, so I don't take much stock in those being followed rigorously anytime soon.

Related

Creating a "#" border outside my 2d array

Hi I'm currently trying to create a border for my dynamic 2D array, I managed to create the left and right side border of my 2d array grid. But I currently have trouble figuring out on how to do it for the top and bottom side of the 2d array grid.
Is the method I'm currently trying a good way to achieve this? Any help or suggestion would be greatly appreciated thanks!
void displayCity(int minX, int maxX, int minY, int maxY)
{
//Allocate the array.
int** twod = new int* [maxX];
for (int i = 0; i < maxX; i++)
{
twod[i] = new int[maxY];
}
for (int i = 0; i< maxX; ++i)
{
cout << '#';
for (int j = 0; j < maxY; ++j)
{
twod[i][j] = 0;
cout << twod[i][j] << ' ';
}
cout << setw(1) << '#';
cout << endl;
}
//Deallocate the array.
for (int i = 0; i < maxX; ++i)
{
delete[] twod[i];
}
delete[] twod;
}
This is my current output.
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
#0 0 0 0 0 0 0 0 #
Don't use "new/delete" unless you really need to. (C++ core guidelines).
Instead rely on datastructures from stl, like std::vector (for dynamically allocated arrays). For example like this :
#include <vector>
#include <iostream>
#include <string>
// City class to hold city data (but not to render it).
class City
{
public:
City(std::size_t width, std::size_t height) :
m_width{ width },
m_height{ height },
m_city_blocks(height,std::vector<int>(width))
{
}
const auto& city_blocks() const noexcept
{
return m_city_blocks;
}
const auto width() const noexcept
{
return m_width;
}
const auto height() const noexcept
{
return m_height;
}
private:
std::size_t m_width;
std::size_t m_height;
// dynamically allocated arrays are best handled by vector
// not by using new (new/delete are no longer recommended)
// use STL containers or std::make_unique
std::vector<std::vector<int>> m_city_blocks;
};
// Seperate class for rendering cities
class Renderer
{
public:
void ShowCity(const City& city)
{
// make a string with enougn '#' to draw bottom and top line
std::string border(2ul * city.width() + 3ul, '#');
// output to screen
std::cout << border << "\n";
// loop over all rows in the city's blocks using a range based for loop
// use const since rendering should not modify the state of the city blocks
// only show them.
for (const auto& row : city.city_blocks())
{
std::cout << "# ";
// loop over all values and display them
for (const auto& value : row)
{
std::cout << value << " ";
}
std::cout << "#\n";
}
std::cout << border << "\n";
}
};
int main()
{
// make a 5*5 city
City city{ 5ul,5ul };
// create a renderer to display the city
Renderer renderer;
renderer.ShowCity(city);
return 0;
}
Your way of drawing the border is rather inflexible because you mix the data, and formatting and output of the data with formatting and output of the border.
Also your borders are not straight lines when the numbers have different number of digits.
I suggest you to first gather all the output to be printed inside borders, then inspect it to see how many lines there are and how long the lines are. Then you know where to print the border:
#include <sstream>
#include <iomanip>
#include <vector>
#include <iostream>
void print_with_border(std::stringstream& str,char border='#') {
std::vector<std::string> output;
size_t max_len = 0;
std::string line;
while(std::getline(str,line)) {
output.push_back(line);
max_len = std::max(max_len,line.size());
}
std::cout << std::string(max_len+4,border) << "\n";
for (const auto& l : output) {
std::cout << border << " " << std::setw(max_len) << std::left << l << " " << border << "\n";
}
std::cout << std::string(max_len+4,border) << "\n";
}
int main() {
std::stringstream ss;
ss <<"hello \n world";
print_with_border(ss);
}
Output:
##########
# hello #
# world #
##########
To print contents of a 2d array you just have to pipe the contents of the array with desired formatting into a stringstream.

find position of a 2D vector which is an element of a class C++

I am working on a class that I have some problems in finding positions of values in one of elements of the class. I have defined my class as follows:
typedef class Chrom
{
public:
vector<vector < int>> bit;
vector<vector < bool>> jobisconsidered;
vector<vector <float>> WaitingTime;
void variablesresize()
{
int i = 0, j, k;
float a;
std::vector<float> datapoints;
std::ifstream myfile("Input.dat", std::ios_base::in);
i = 0; //making zero counter of characters
myfile.open("Input.dat");//now we reread numerical values
while (!myfile.eof())
{
myfile >> a;
// cout << "i=" << i << '\n';
if (!myfile) // not an int
{
myfile.clear(); // clear error status
myfile.ignore(1); // skip one char at input
}
else
{
datapoints.push_back(a);
++i;
}
}
myfile.close();
Jobs = datapoints[0];
Machines = datapoints[1];
WaitingTime.resize(Machines);
bit.resize(Machines);
for (int i = 0; i < Machines - 1; ++i) WaitingTime[i].resize(Jobs);
bit[i].resize(Jobs);
}
}
} c;
c popcurrent[50];
In the class, bit is a 2D element and if I define it as m*n, all values in the rows are the same. However, when I want to find position in bit, for example if popcurrent[0].bit for 2 rows and 3 columns is = { {3,2,1},{3,2,1} }, and I want to find position of the first "3" in the vector is 0 and popcurrent[0].bit[0][0]=3 , I have problems.
Specificaly I tried c++ search a vector for element first seen position with the following commands:
auto p = std::lower_bound(popcurrent[0].bit.begin(), popcurrent[0].bit.end(), 1);
int position = p - popcurrent[0].bit.begin();
But I get following error:
Error 109 error C2893: Failed to specialize function template
'unknown-type std::less<void>::operator ()(_Ty1 &&,_Ty2 &&) const'
I know one way is to use for and if loops. But I wonder is there any more automated way to do this such as build in functions.
I didn't notice it at first - there's too much irrelevant code - but the problem is quite simple: you're trying to find the first element of type std::vector<int> not less than value of type int.
popcurrent[0].bit.begin() points to the first element of std::vector<std::vector<int>>, that is a vector. There's no "less than" operator for comparing a vector of ints and an int.
I want to find position of the first "3" in the vector is 0 and
popcurrent[0].bit[0][0] = 3 , I have problems. Specificaly I tried
c++ search a vector for element first seen position with the following
commands:
auto p=std::lower_bound(popcurrent[0].bit.begin(), popcurrent[0].bit.end(), 1);
int position = p - popcurrent[0].bit.begin();
There are mainly two problems:
Problem - 1: std::lower_bound takes parameters first, last, which are forward-iterator types which defining the partially-ordered range. In your case(popcurrent[0].bit.begin()), you are passing a iterator which has the pointed element as a vector of integers (remember std::vector<std::vector<int>> is an array of vectors(vector<int>) not integers) for which std::lower_bound, could not find any definition for operator<. This is the reason of your error, where compiler complaining that:
" Hey, I don't have a specialisation for operator< your given range
or vectors, to instantiate the template "
Problem - 2: You can not use std::lower_bound here, as it needs a strictly sorted array to binary search the value which has been provided. As you provided an unsorted vectors to check, the result won't be correct. See above link to read more:
Solution: You can use std::find_if which has a time complexity, up to linear in the distance between first and last iterator, according to the predicate provided, which will search for each element until a match is found. This could be an alternative if you do not want to sort each vector in the class, which is actually a 3-dimensional array of vectors.
Following is a sample solution: SEE LIVE HERE
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
typedef std::vector<std::vector < int>> Type ;
struct Chrom // to demonstrate
{
Type bit;
};
std::tuple<int, int, int> findPosition(const std::vector<Chrom>& vec3D, const int& val)
{
int First = 0, Second = 0, Third = -1; // initilize the positions
for(const Chrom& each_chrom: vec3D)
{
for(const std::vector<int>& innerVec: each_chrom.bit)
{
std::vector <int>::const_iterator get_pos;
get_pos = std::find(innerVec.cbegin(), innerVec.cend(), val);
Third = (*get_pos == val) ? get_pos - innerVec.cbegin(): -1; // check val found otherwise -1
if(Third != -1) return std::make_tuple(First, Second, Third); // if found return them
++Second;
}
Second = 0;
Third = -1;
++First;
}
return std::make_tuple(First, Second, Third);
}
int main()
{
// this is a 3 dimensional vector
std::vector<Chrom> popcurrent(2); // position inside the popcurrent
popcurrent[0].bit = { {3,2,1}, // (0,0,0) (0,0,1) (0,0,2)
{3,10,1} }; // (0,1,0) (0,1,1) (0,1,2)
popcurrent[1].bit = { {5,8,11}, // (1,0,0) (1,0,1) (1,0,2)
{4,7,1} }; // (1,1,0) (1,1,1) (1,1,2)
int pos_popcurrent, pos_bit, pos_inner_vec;
for(int val = 1; val <= 12; ++val)
{
std::cout << "\nCurrently looking for: " << val ;
std::tie(pos_popcurrent, pos_bit, pos_inner_vec) = findPosition(popcurrent, val);
(pos_inner_vec != -1) ?
std::cout << " found # popcurrent[ " << pos_popcurrent << " ].bit[ " << pos_bit << " ][ " << pos_inner_vec <<" ]":
std::cout << " Not found";
}
return 0;
}
Output:
Currently looking for: 1 found # popcurrent[ 0 ].bit[ 0 ][ 2 ]
Currently looking for: 2 found # popcurrent[ 0 ].bit[ 0 ][ 1 ]
Currently looking for: 3 found # popcurrent[ 0 ].bit[ 0 ][ 0 ]
Currently looking for: 4 found # popcurrent[ 1 ].bit[ 1 ][ 0 ]
Currently looking for: 5 found # popcurrent[ 1 ].bit[ 0 ][ 0 ]
Currently looking for: 6 Not found
Currently looking for: 7 found # popcurrent[ 1 ].bit[ 1 ][ 1 ]
Currently looking for: 8 found # popcurrent[ 1 ].bit[ 0 ][ 1 ]
Currently looking for: 9 Not found
Currently looking for: 10 found # popcurrent[ 0 ].bit[ 1 ][ 1 ]
Currently looking for: 11 found # popcurrent[ 1 ].bit[ 0 ][ 2 ]
Currently looking for: 12 Not found

Compress a 2D array into a 1D Array

i have a quad (2D array) which is composed of numbers which ranges from 0 to 255
and the most frequent value of the array ( in my case 2) is the background value
i have to put all the values of the array except the background value ( i have to ignore all cases that contains a 2) in a 1D array with this arrangement
the line,the column,the value,the line,the next column,the next value
for example i have
{2,3,2,2},
{2,2,2,2},
in the 1D array it will be like { 1,2,3,}
i added spaces to make it more readable
here is my array
int image1[MAXL][MAXC]=
{
{2,3,2,2},
{2,2,2,2},
{2,255,2,2},
{255,2,2,2},
{2,255,2,2}
};
and the loop
for (int i = 0; i<nbc;i++)
{
for (int j=0; j<nbl;j++)
{
if (image1[j][i]==BackColor)
{
}
else
}
}
nbc and nbl are respectively the number of columns and lines
thanks you for your help
EDIT : i completely failed my example i didn't ignored the 2, should be fine now
A simple approach using std::vector
std::vector<int> result;
for (int i = 0; i<MAXL;i++)
{
for (int j=0; j<MAXC;j++)
{
if (image1[i][j] != BackColor) // Notice !=
{
result.push_back(i+1);
result.push_back(j+1);
result.push_back(image1[i][j]);
}
}
}
for (auto x : result)
{
std::cout << x << " ";
}
std::cout << endl;
Output:
1 2 3 3 2 255 4 1 255 5 2 255
http://ideone.com/yJawu5

Knight's tour abnormal behavior

So here is my code for the knight's tour problem, and I have been pulling my hair out trying to figure out what is wrong with it.
#include <iostream>
#include <vector>
using namespace std;
void Knights_tour(int x, int y, int move_count);
bool isSafe(int x, int y);
int m,n,start_x,start_y;
int valid_x [8] = {2,2,-2,-2,1,1,-1,-1};
int valid_y [8] = {1,-1,1,-1,2,-2,2,-2};
vector<vector<int>> board;
int main(int argc, char* argv[])
{
m=atoi(argv[1]);
n=atoi(argv[2]);
start_x=atoi(argv[3]);
start_y=atoi(argv[4]);
board.resize(m);
for(int i=0; i<m; i++)
board[i].resize(n);
Knights_tour(start_x, start_y, 1);
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
cout<<"[ "<<board[i][j]<<" ]";
}
cout << endl;
}
return(0);
}
void Knights_tour(int x, int y, int move_count)
{
board[x][y]=move_count;
if(move_count==(m*n))
{
cout << "Success!" << endl;
return;
}
for(int i=0; i<8; i++)
{
if(isSafe((valid_x[i]+x), (valid_y[i]+y)))
{
move_count++;
Knights_tour((valid_x[i]+x), (valid_y[i]+y), move_count);
}
}
}
bool isSafe(int x, int y)
{
if(x>=0 && x<n && y>=0 && y<m && board[x][y]==0)
return true;
else
return false;
}
It takes the dimensions of the board as well as the starting coordinates through the command line. For example, running "./Knight 5 5 0 0" yields a 5x5 matrix and starts at coordinate 0. Here is what that looks like
[ 1 ][ 18 ][ 16 ][ 12 ][ 15 ]
[ 17 ][ 13 ][ 13 ][ 7 ][ 15 ]
[ 17 ][ 2 ][ 9 ][ 4 ][ 11 ]
[ 14 ][ 18 ][ 6 ][ 14 ][ 8 ]
[ 8 ][ 16 ][ 3 ][ 10 ][ 5 ]
As you can see it works perfectly up until 13, when it begins repeating itself. I cannot figure out why my recursive function would do this. Any help would be appreciated. Thank you
If I understand your code correctly, you are trying to find one Knights tour of an mxn board using recursive bruteforce trying every possible solution.
The error probably happens because recursive calls not leading to a solution still modifies the board, but doesn't backtrack to clear up the modified board values. Other recursive calls then fail to find a solution since board[x][y]==0 fails.
One solution is to pass a copy of the board onto every recursive call, and then return the board at the end.
Also: using bruteforce, you can probably not expect to find a tour for much larger boards since the running time increases exponentially asymptotically.
edit: typos
edit2: added possible solution
Creating a whole copy of the board on each call would use a lot of memory. I think you can avoid it by having Knights_tour return a bool which is true when a solution is found. The return value can be used when you unwind the stack to decide on if you should unset board[x][y].
if(!Knights_tour((valid_x[i]+x), (valid_y[i]+y), move_count))
{
board[x][y] = 0;
}

How to fill a 2D array with Every Possible Combination? C++ Logic

I can't figure out the logic behind this one... here's what I have so far:
#include <iostream>
using namespace std;
int thearray[4][4];
int NbPos = 4;
int main() {
int i2;
int q2;
for(int i = 1; i < 4; i++) {
for(int q = 1; q < 4; q++) {
for(int c = 0; c < NbPos; c++) {
thearray[i][q] = c;
}
}
}
}
This is filling the array up to the end is still:
3 3 3
3 3 3
3 3 3
but it's doing so without hitting anywhere near every possible combination.
Ideally once it gets to:
0 0 0
0 0 0
0 0 3
the next step SHOULD be:
0 0 0
0 0 0
0 1 0
so it hits a TON of combinations. Any ideas on how to make it hit them all? I'm stumped on the logic!
with the way you're iterating over this, a 1-dimensional array would make the looping simpler. you can still mentally treat it to have rows and columns, however they are just layed out end-to-end in the code.
you could try something like this; however if you want it in a 2D format specifically that challenge is left to you ;)
#include <iostream>
using namespace std;
#define rows 4
#define columns 4
int main() {
int thearray[rows * columns] = {0};
int NbPos = 4;
int lastPos = rows * columns - 1;
while (true) {
thearray[lastPos]++;
int pos = lastPos;
while (thearray[pos] == NbPos and pos >= 1) {
thearray[pos - 1]++;
thearray[pos] = 0;
pos--;
}
bool finished = true;
for (int i = 0; i < rows * columns; i++) {
if (thearray[i] != NbPos - 1) {
finished = false;
}
}
if (finished) {
break;
}
}
for (int i = 0; i < rows * columns; i++) {
std::cout << thearray[i] << " ";
if (i % rows == rows - 1) {
cout << endl; // makes it look like a 2D array
}
}
}
It makes sense to have the final form as all 3s , since you loop every element of the array and you assign it at the end with 3 .
So the next element will only take into account the combination with the final value of the previous element (which will be 3).
Thinking in math terms, your complexity is N^3 so to speak (actually is N^2 * 4 , but since your N is 3 ...).
Your approach is wrong, since you want to find permutations, which are defined by a factorial function , not a polinomial function.
The necessary complexity for the output doesn't match the complexity of your algorithm (your algorithm is incredbily fast for the amount of output needed).
What you are looking for is backtracking (backtacking will match the complexity needed for your output).
The recursion function should be something like this (thinking on a 1D array, with 9 elements):
RecursiveGeneratePermutations(int* curArray, int curIdx)
{
if (curIDX==9)
{
for (int i=0; i<9;i++)
{
// write the array
}
} else {
curArray[curIdx]=0;
RecursiveGeneratePermutations(curIdx+1);
curArray[curIdx]=1;
RecursiveGeneratePermutations(curIdx+1);
curArray[curIdx]=2;
RecursiveGeneratePermutations(curIdx+1);
curArray[curIdx]=3;
RecursiveGeneratePermutations(curIdx+1);
}
}
Now you only need to call the function for the index 0 :
RecursiveGeneratePermutations(arrayPtr,0);
Then wait...allot :).