c++ Sudokou Grid initialisation - c++

So I'm very new to c++, studying it at present and have a piece of work to do that's stumping me. You guys are the first port of call.
I need to make what is essentially a 2d array of objects. The header file includes Cell objects for rows, columns and blocks. The idea that I have a 9x9 array of objects, with relevant pointers based on column, row and internal 3x3 block therein. What I'm stuck on is that the below line fills out the 9x9 but how am I pointing to each Cell?
Or is that in something separate and this is all I need to do for just setting up that grid??
void SudokuPuzzle::InitialiseGrid()
{
for (int row = 0; row < 9; row++)
{
for (int column = 0; column < 9; column++)
{
m_gridRows[row].SetCell(column, new SudokuSquare());
// have the cell point to both it's position in the column and block
}
}
}

Maybe try to create the 2d array of the Type "SudokuSquare".
SudokuSquare sSquare [9][9];
So you can acces any object by
sSquare[row][column];

If your array is fixed size e.g. 3x3 just use std::array:
#include <array>
using std::array;
int main()
{
array<array<int, 3>, 3> sudoku_squares{};
sudoku_squares[0][1] = 1; // sets cell at first row, second column to 1
return 0;
}
In your case you can store 9 of those 3x3 arrays in another array or just use 9x9 array and you don't need to use any pointers. I used int in my example but you can store SudokuSquare exactly the same way.

Related

Implementing a 2d array for an object

Creating a crossword puzzle generator. The grid size is chosen by input and the grid will be generated. I'd like the grid to be an object with rows and columns but also a 2d array which will allow me to divide the grid into smaller sections for randomising between blank and numbered squares. I am not sure where to implement it.
It has to be a 2d array as I will do dividing and inverting the layout.
Here is my Grid class with some methods. (And the rest)
class Grid
{
int rows; //x
int columns; //y
Square field;
public:
void SetXY(int x, int y)
{
rows = x;
columns = y;
return;
}
public:
void DisplaySize()
{
cout << "Rows = ", rows, "Columns = ", columns;
}
};
The simplest way to implement a 2D array is to use a std::array<std::array<>> or std::vector<std::vector<>> - depending on whether it needs to be a static or dynamically sized array.
But, you can also just use a one dimensional std::array or std::vector and then just get the second dimension by indexing like row*size_of_row+column.

C++ : Create 3D array out of stacking 2D arrays

In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
Is there any way to do this in C++?
In particular, I have loaded a image into a Mat variable with OpenCV like:
cv::Mat im = cv::imread("image.png", 0);
I would like to make a 3D array/Mat of N layers by stacking copies of that Mat variable.
EDIT: This new 3D matrix has to be "travellable" by adding an integer to any of its components, such that if I am in the position (x1,y1,1) and I add +1 to the last component, I arrive to (x1,y1,2). Similarly for any of the coordinates/components of the 3D matrix.
SOLVED: Both answers from #Aram and #Nejc do exactly what expected. I set #Nejc 's answer as the correct one for his shorter code.
The Numpy function vstack returns a contiguous array. Any C++ solution that produces vectors or arrays of cv::Mat objects does not reflect the behaviour of vstack in this regard, becase separate "layers" belonging to individual cv::Mat objects will not be stored in contiguous buffer (unless a careful allocation of underlying buffers is done in advance of course).
I present the solution that copies all arrays into a three-dimensional cv::Mat object with a contiguous buffer. As far as the idea goes, this answer is similar to Aram's answer. But instead of assigning pixel values one by one, I take advantage of OpenCV functions. At the beginning I allocate the matrix which has a size N X ROWS X COLS, where N is the number of 2D images I want to "stack" and ROWS x COLS are dimensions of each of these images.
Then I make N steps. On every step, I obtain the pointer to the location of the first element along the "outer" dimension. I pass that pointer to the constructor of temporary Mat object that acts as a kind of wrapper around the memory chunk of size ROWS x COLS (but no copies are made) that begins at the address that is pointed-at by pointer. I then use copyTo method to copy i-th image into that memory chunk. Code for N = 2:
cv::Mat img0 = cv::imread("image0.png", CV_IMREAD_GRAYSCALE);
cv::Mat img1 = cv::imread("image1.png", CV_IMREAD_GRAYSCALE);
cv::Mat images[2] = {img0, img1}; // you can also use vector or some other container
int dims[3] = { 2, img0.rows, img0.cols }; // dimensions of new image
cv::Mat joined(3, dims, CV_8U); // same element type (CV_8U) as input images
for(int i = 0; i < 2; ++i)
{
uint8_t* ptr = &joined.at<uint8_t>(i, 0, 0); // pointer to first element of slice i
cv::Mat destination(img0.rows, img0.cols, CV_8U, (void*)ptr); // no data copy, see documentation
images[i].copyTo(destination);
}
This answer is in response to the question above of:
In Python I normally use functions like vstack, stack, etc to easily create a 3D array by stacking 2D arrays one onto another.
This is certainly possible, you can add matrices into a vector which would be your "stack"
For instance you could use a
std::vector<cv::Mat>>
This would give you a vector of mats, which would be one slice, and then you could "layer" those by adding more slices vector
If you then want to have multiple stacks you can add that vector into another vector:
std::vector<std::vector<cv::Mat>>
To add matrix to an array you do:
myVector.push_back(matrix);
Edit for question below
In such case, could I travel from one position (x1, y1, z1) to an immediately upper position doing (x1,y1,z1+1), such that my new position in the matrix would be (x1,y1,z2)?
You'll end up with something that looks a lot like this. If you have a matrix at element 1 in your vector, it doesn't really have any relationship to the element[2] except for the fact that you have added it into that point. If you want to build relationships then you will need to code that in yourself.
You can actually create a 3D or ND mat with opencv, you need to use the constructor that takes the dimensions as input. Then copy each matrix into (this case) the 3D array
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main() {
// Dimensions for the constructor... set dims[0..2] to what you want
int dims[] = {5, 5, 5}; // 5x5x5 3d mat
Mat m = Mat::zeros(5, 5, CV_8UC1);
for (size_t i = 0; i < 5; i++) {
for (size_t k = 0; k < 5; k++) {
m.at<uchar>(i, k) = i + k;
}
}
// Mat with constructor specifying 3 dimensions with dimensions sizes in dims.
Mat 3DMat = Mat(3, dims, CV_8UC1);
// We fill our 3d mat.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
3DMat.at<uchar>(i, k, j) = m.at<uchar>(k, j);
}
}
}
// We print it to show the 5x5x5 array.
for (size_t i = 0; i < m2.size[0]; i++) {
for (size_t k = 0; k < m2.size[1]; k++) {
for (size_t j = 0; j < m2.size[2]; j++) {
std::cout << (int) 3DMat.at<uchar>(i, k, j) << " ";
}
std::cout << endl;
}
std::cout << endl;
}
return 0;
}
Based on the question and comments, I think you are looking for something like this:
std::vector<cv::Mat> vec_im;
//In side for loop:
vec_im.push_back(im);
Then, you can access it by:
Scalar intensity_1 = vec_im[z1].at<uchar>(y, x);
Scalar intensity_2 = vec_im[z2].at<uchar>(y, x);
This assumes that the image is single channel.

Inserting values to a multidimensional-vector in C++

I've got a minor problem.
I'm using multidimensional-vectors and I want to insert some values to it at a given position. I'm making a sudoku in wxWidgets and i'm getting the tiles the player have put in and wanting to store them in my mVector.
The mVector looks like this.
vector< vector<string> > board{9, vector<string>(9)};
And at first i've added values just like this.
board[row][col] = value;
"value" is a string and row/col are ints.
Is this a legit way of adding values to the mVector? I'm asking this because when I update the board, by doing this above, I for some reason can't run my other functions where i'm solving the board, giving a hint to the board and so on. Before i store the new values to it all the functions works correkt. Do I maby need to use some other type of build in functions for the vector like insert, push_back or something instead?
Since you declared the vector as size 9x9, yes that is a valid way of assigning values.
Otherwise you could declare the board as
vector<vector<string>> board;
Then fill it with
for (int i = 0; i < 9; ++i)
{
vector<string> row;
for (int j = 0; j < 9; ++j)
{
row.push_back(value); // where value is whatever you want
}
board.push_back(row);
}
But again, once the board is of size 9x9, you can simply assign a value at any cell for example
board[2][4] = "hello";
Working example

Access an element of a 2d dynamic array--c++

I created a dynamic array.
typedef float* DynamicMatrix[MAT_SIZE];
DynamicMatrix matDyn;
// allocate rows and initialize to 0
for (r = 0; r < MAT_SIZE; r++) {
matDyn[r] = new float[MAT_SIZE];
for (c = 0; c < MAT_SIZE; c++) {
(matDyn[r])[c] = 0; // IS THIS CORRECT???
}
}
The whole idea was that I create an array of pointers which is my spine of a matrix I am creating. This spine is the leftmost-vertical part of the matrix. Each row of this array will point to another array of floats, therefore making it a dynamic 2d array.
I am unsure how to access an element of this matrix. Please let me know how to.
You can access it just like a "normal" matrix:
matDyn[r][c].
You can just access it by stating matDyn[r][c]
My error was that later in my program(not shown), I was trying to set matDyn[MAT_SIZE][MAT_SIZE] which isn't possible (it can only be matDyn[MAT_SIZE-1][MAT_SIZE-1]) and that is why I was getting my segmentation error.

2D object array in c++?

2D arrays such as:Cell **scoreTable.After allocating:
scoreTable = new Ceil*[10];
for(int i = 0 ;i<10;i++)
scoreTable[i] = new Ceil[9];
And I want to save the value like this:scoreTable[i][j]= new Ceil(i,j) in heap,and this can not work in c++.Thanks for help.
scoreTable[i][j]= new Ceil(i,j). You are trying to put Cell* into Cell.
You have to create 2d array of pointers:
auto scoreTable = new Ceil**[10];
for(int i = 0 ;i<10;i++)
scoreTable[i] = new Ceil*[9];
But much better is to use vector:
std::vector< std::vector<Ceil*> > table;
table.resize(10);
for (int i = 0; i < 10; ++i)
{
table[i].resize(9, NULL);
}
table[3][4] = new Ceil();
Once you've allocated your array like this, you'll already have a 2D array of Cell, so you don't need to use the new keyword to change the value.
If you give your Cell class a method like SetValue(i,j), then you can use it like this: scoreTable[i][j].SetValue(i,j);
I want to suggest using std::vector instead. It is much easier to keep track of.
You can replace all of the code above with
std::vector< std::vector< Cell> > scoreTable(10, std::vector<Cell>(9));
This will create scoreTable, which is a vector containing 10 elements of vector<Cell>, each containing 9 cells. In other word, the desired 2D table.
You access the elements in the same way. scoreTable[i][j], where i goes fron 0 to 9, and j from 0 to 8.
If you want to expand with a new row, just say:
scoreTable.push_bach(std::vector<Cell>(9));
For a new column:
for(size_t row = 0; row < scoreTable.size(); ++row) {
scoreTable[row].push_back(Cell());
}
No need for new or delete.