Data structure for a crossword puzzle grid? - c++

I'd like to design a crossword puzzle editor in C++. It is a grid of blocks, each block containing a letter (or being black between two words), possibly a number and a thick or thin border line.
The block is therefore a container class for them. The grid is a container of blocks. But how would I structure the grid?
A raw 2d array: Block grid[row][column]?
Vector of Vectors: vector<vector<Block>>?
Two vectors, one for the rows and one for the columns: vector<Block> row; vector<Block> column?
A map, which keys are the row/column pairs and the values are the blocks: map<int[2], Block>?

By default, plain static/dynamic arrays (or their wrappers) are the most preferable: they are the most comfortable for both the programmer (random access API etc) and the processor (memory locality etc).
The easiest-to-implement Block layout in an array/a vector is [first row Blocks..., second row Blocks..., etc] - a 1D array which acts as a 2D array. It can be indexed like crossword[x + y * crossword.width()], which isn't pretty, so you might want to use a library/self-written wrapper with API like crossword(x, y) which performs that xy-to-i-index conversion under the hood.
Maybe something like this:
class Crossword {
std::vector<Block> raw;
size_t length{}; // can't name it "width" because there's a "width()" member function below
public:
Crossword() {}
Crossword(size_t x, size_t y): raw(x * y), length{x} {}
Crossword(Crossword&& other) noexcept { *this = std::move(other); }
Crossword& operator=(Crossword&& other) noexcept {
std::swap(raw, other.raw);
std::swap(length, other.length);
return *this;
}
auto size() const { return raw.size(); }
auto width() const { return length; }
auto height() const { return size() / length; }
auto& operator()(size_t x, size_t y) const { return raw[x + y * length]; }
auto& operator()(size_t x, size_t y) { return raw[x + y * length]; }
};

Related

What causes this vector subscript out of range Error?

I am currently mapping a Graph to a Minesweeper like grid, where every Block represents a node.
Here is my Graph class:
class Graph : public sf::Drawable
{
public:
Graph(uint32_t numNodesWidth, uint32_t numNodesHeight);
[[nodiscard]] std::vector<Node> & operator[](std::size_t i)
{ return data[i]; }
[[nodiscard]] sf::Vector2u dimension() const
{ return {static_cast<uint32_t>(data.size()),
static_cast<uint32_t>(data[0].size())};}
...
...
private:
std::vector<std::vector<Node>> data;
};
here is the implementation of the constructor:
Graph::Graph(uint32_t numNodesWidth, uint32_t numNodesHeight)
{
data.resize(numNodesHeight);
for(auto & row : data)
{
row.resize(numNodesWidth);
}
}
Somewhere in another class I read mouse coordinates and convert them to "Graph Coordinates":
sf::Vector2u translatedCoords = toGraphCoords(sf::Mouse::getPosition(window), nodeSize_);
bool inBounds = checkGraphBounds(translatedCoords, graph.dimension());
Here are the helper functions:
sf::Vector2u toGraphCoords(sf::Vector2i mouseCoord, sf::Vector2f nodeSize)
{
return {static_cast<uint32_t>(mouseCoord.y / nodeSize.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize.x)};
}
bool checkGraphBounds(sf::Vector2u mouseCoord, sf::Vector2u bounds)
{
return mouseCoord.x >= 0 &&
mouseCoord.y >= 0 &&
mouseCoord.x < bounds.x &&
mouseCoord.y < bounds.y ;
}
Somehow I get the vector subscript out of range 1655 error when I try to use these new checked Coordinates which is somehow strange, can someone explain to me what I am doing wrong. This error always shows when I try to hover beyond the "Bounds" of the Interactive area, slightly behind or in front the first or the last Node.
Thanks in advance.
There is no guarantee that bounds <= num_nodes * node_size. This is especially risky since there are integer divisions involved, which means that you are at the mercy of rounding.
You could shuffle code around until such a guarantee is present, but there's a better way.
If the checkGraphBounds() function operated on the same math that the grid does, you could be sure that the result would be consistent with grid, no matter how that relates to the bounds.
The ideal way to do so would be to actually use toGraphCoords() as part of it:
bool checkGraphBounds(sf::Vector2u mouseCoord, const Graph& graph,
sf::Vector2f nodeSize)
{
auto coord = toGraphCoords(mouseCoord, nodeSize);
return coord.x >= 0 &&
coord.y >= 0 &&
coord.x < graph.dimensions().x &&
coord.y < graph.dimensions().y) ;
}
With this, you can formally guarantee that should a mouseCoord pass that test, static_cast<uint32_t>(mouseCoord.x / nodeSize.x)} will for certain return a value no greater than graph.dimensions().x.
Personally, I would combine both functions as a method of Graph like so:
class Graph : public sf::Drawable {
// Make nodeSize a member of the Graph
sf::Vector2f nodeSize_;
// This is one of the cases where caching an inferable value is worth it.
sf::Vector2u dimensions_;
public:
std::optional<sf::Vector2u> toGraphCoords(sf::Vector2i mouseCoord) {
sf::Vector2u coord{
static_cast<uint32_t>(mouseCoord.y / nodeSize_.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize_.x)};
};
// No need to compare against 0, we are dealing with unsigned ints
if(coord.x < dimensions_.x &&
coord.y < dimensions_.y ) {
return coord;
}
return std::nullopt;
}
// ...
};
Usage:
void on_click(sf::Vector2i mouse_loc) {
auto maybe_graph_coord = the_graph.toGraphCoords(mouse_loc);
if(maybe_graph_coord) {
sf::Vector2u graph_coord = *maybe_graph_coord;
// ...
}
}

Storing data in a 2d matrix with interchangeable x/y coordinates

I have a list of nodes in C++, and I wish to store the distance between each pair of nodes in some kind of data structure dist
For example, 5 nodes: (0, 1, 2, 3, 4)
I want to store the distance between each of them.
I could store them in a 2d matrix, but then I am storing redundant data.
dist[1][3], which stores the distance between node 1 and 3, would hold the same value as dist[3][1]
Furthermore dist[0][0], dist[1][1], dist[2][2], .. are not needed and also waste data.
I considered a 1d array with a mapping function that maps [x][y] coordinates to an array index, but it could become hard to read and understand when revisiting the code.
What is a good way to store some values between arbitrarily-ordered indices like this in C++?
The right abstraction is a class, which wraps data access for you.
#include <algorithm>
#include <array>
template <typename TNumber, std::size_t Dimension>
class triangular_matrix
{
public:
// It's common/friendly to make a value_type for containers
using value_type = TNumber;
// Overloading operator() is fairly common and looks pretty decent
value_type operator()(std::size_t row, std::size_t col) const
{
return _data.at(index_of(row, col));
}
// A non-const overload allows users to edit using regular assignment (=)
value_type& operator()(std::size_t row, std::size_t col)
{
return _data.at(index_of(row, col));
}
private:
// You're storing 1 less than the dimensions
static constexpr stored_dim = Dimension - 1;
// Use sum of arithmetic series:
static constexpr data_size = stored_dim / 2U;
static std::size_t index_of(std::size_t row, std::size_t col)
{
// I'm not sure what you want to do for this case -- you said these
// indexes aren't needed, but I don't know if you mean they won't be
// accessed or what...so just throw!
if (row == col)
throw std::invalid_argument("row and column can't be the same!");
// flip
if (row > col)
std::swap(row, col);
// This is probably not the fastest way to do this...
--row;
std::size_t index = 0U;
for (; row > 0U; --row)
index += row;
return index + col;
}
// Store using a flat array
std::array<TNumber, data_size> _data;
};
Usage looks like this:
triangular_matrix<double, 4> m;
m(1, 3) = 5.2;
m(2, 1) = 9.1;
assert(m(2, 1) == m(1, 2));

A vector of unique_ptr at specific positions in vector

I have a class called Grid which is composed of Cells. Each cell can have its own format (the concept is similar to MS Excel).
The format in the Grid is kept in a vector std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable which owns all the formatting, so whenever I need to read a Cells format, I read it from the vector and whenever there is a change, it is reported back to the vector. Sorry, I am quite new to C++11 standards so my thinking might be wrong.
Since a grid is a matrix and each cell belongs to a different part of the matrix when there is a change in a cell's format it should be reflected in the correct part of the matrix, namely positioned correctly in the vector (CellFormatTable). Therefore, at this stage I cannot use the push_back method of the vector.
The CellFormat class:
struct CellFormat
{
wxFont m_Font;
wxColor m_BackgroundColor, m_TextColor;
int m_HorizontalAlignment, m_VerticalAlignment;
CellFormat(Grid* ws) {
m_BackgroundColor = ws->GetDefaultCellBackgroundColour();
m_TextColor=ws->GetDefaultCellTextColour();
int horizontal = 0, vertical = 0;
ws->GetDefaultCellAlignment(&horizontal, &vertical);
}
CellFormat(const CellFormat& other) {
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
}
CellFormat& operator=(const CellFormat& other) {
if (this == &other) return *this;
m_Font = other.m_Font;
m_BackgroundColor = other.m_BackgroundColor;
m_TextColor = other.m_TextColor;
m_HorizontalAlignment = other.m_HorizontalAlignment;
m_VerticalAlignment = other.m_VerticalAlignment;
return *this;
}
};
In the Grid.h
class Grid{
std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable;
//
CellFormat* GetCellFormat(int row, int column);
void SetCellFormat(int row, int column, CellFormat format);
void ApplyCellFormat(int row, int column, const CellFormat* format);
CellFormat* CreateCellFormat(int row, int column);
//rest is omitted
}
In Grid.cpp
Grid(some arguments){
m_CellFormatTable.resize(nrows*ncols);
//rest is omitted
}
CellFormat* Grid::GetCellFormat(int row, int column)
{
int ncols= GetNumberCols();
return m_CellFormatTable[row*ncols+ column].get();
}
void Grid::SetCellFormat(int row, int column, CellFormat other)
{
CellFormat* format = GetCellFormat(row, column);
if (format == 0) format = CreateCellFormat(row, column);
*format = other;
}
void Grid::ApplyCellFormat(int row, int column, const CellFormat * format)
{
if (format == 0) {
int ncols= GetNumberCols();
//Set everything to default values
//Omitted
m_CellFormatTable[row*ncols+ column].reset();
}
else {
wxColor bgcolor = format->m_BackgroundColor;
if (bgcolor.IsOk()) SetCellBackgroundColour(row, column, bgcolor);
SetCellTextColour(row, column, format->m_TextColor);
SetCellFont(row, column, format->m_Font);
SetCellAlignment(row, column, format->m_HorizontalAlignment, format->m_VerticalAlignment);
}
}
CellFormat* Grid::CreateCellFormat(int row, int column)
{
int ncols= GetNumberCols();
CellFormat* format = new CellFormat(this);
m_CellFormatTable.emplace(m_CellFormatTable.begin() + row*ncols+ column, std::move(format));
return format;
}
Whenever I format a cell, say its background color is changed, I use the following attempt:
CellFormat* format = ws->GetCellFormat(row, col);
if (format == 0) format = ws->CreateCellFormat(row, col);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(row, col, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
The code fails at ApplyCellFormat function at the point of format->m_BackgroundColor since the color which should have been Cell's background color is not valid. This tells me that most and highly likely CreateCellFormat does not place CellFormat in the right location. I try to use insert rather than emplace but compiler (VS 2015) complained all my attempts.
Any ideas appreciated.
You have several problems.
One is that you add a CellFormat* but your vector stores unique_ptr ;so you need std::make_uniquewith the new format.
Question: are you sure you need a vector of pointers instead of objects?
Other is that you presume the vector to have all data for all cells, being 0 if they are not set yet. That's wrong. The vector only have as many elements as you have 'pushed' or 'emplaced'.
Let's say you have 'pushed' the format for cell (0,0). Now you want to set the format for (5,2) which is (say you have 10 cols) the 52th element in the vector, but you have only one. So vector[51] is undefined (vector.at(51) will raise an error).
Add all cell formats first, with some value = 0 to tell it has not been set yet. Or re-think your strategy.
By the way, you can use wxGridCellAttr which provides what you are coding on your own.
From the fact that you use a vector of unique_ptr (rather than of objects), I deduce that not all elements of the matrix are actually occupied. In this case, it may be better to use a std::map (or std::unordered_map if the matrix is very large) of objects (not unique_ptrs).
template<typename T>
struct grid
{
using index = std::pair<unsigned, unsigned>;
// insert element if not already present
// returns if insertion occurred
template<typename...Args>
bool insert(index const&i, Args&&...args)
{
return data.emplace(std::forward<Args>(args)...).second;
}
// remove element (if it exists)
void remove(index const&i)
{
data.erase(i);
}
// get pointer to element, may be nullptr
T* get(index const&i)
{
auto it = data.find(i);
return it==data.end() ?
nullptr : std::addressof(*it);
}
private:
std::map<index,T> data;
};
The reason I see that your code is failing in this section of your code:
CellFormat* format = ws->GetCellFormat(row, col);
if (format == 0) format = ws->CreateCellFormat(row, col);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(row, col, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}
Is due to how your class is defined:
class Grid{
std::vector<std::unique_ptr<CellFormat>> m_CellFormatTable;
//
CellFormat* GetCellFormat(int row, int column);
void SetCellFormat(int row, int column, CellFormat format);
void ApplyCellFormat(int row, int column, const CellFormat* format);
CellFormat* CreateCellFormat(int row, int column);
//rest is omitted
}
By Default your class has it's members and functions set as private:
Change your class to this:
class Grid {
public:
typedef std::vector<std::unique_ptr<CellFormat>> Format;
private:
Format m_CellFormatTable;
public:
CellFormat* getCellFormat( int row, int column );
void setCellFormat( int row, int column, const CellFormat& format );
void applyCellFormat( int row, int column, const CellFormat& format );
// Add This Function If Needed
Format getCellFormatTable() const { return m_CellFormatTable; }
};
So your class's member functions are declared as public: Then outside and non-friend objects can now have access to this class's member functions and be able to return the data structure via a get method.
Thanks to all for helpful comments and posts. Finally it works as expected.
As Ripi2 suggested, CellFormat objects in the vector were not initialized, so in the constructor I initialized them. Also not presented here, I had somewhere in the code a vector of objects not initialized, so corrected that part as well.
Although looping through all the rows and columns of the grid and creating a default format is NOT the best idea, a future work for me will be Walter's suggestion, i.e. to use sets.
Grid(some arguments){
for (int i = 0; i < nrows*ncols; i++) {
m_CellFormatTable.emplace_back(new CellFormat(this));
}
//Rest is omitted
}
Also corrected below code as well:
CellFormat* Grid::CreateCellFormat(int row, int column)
{
int ncols = GetNumberCols();
CellFormat* format = new CellFormat(this);
std::unique_ptr<CellFormat> ptr(format);
m_CellFormatTable.emplace(m_CellFormatTable.begin() + row*ncols + column,std::move(ptr));
return format;
}
One way to keep track of formatting is:
CellFormat* format = ws->GetCellFormat(i, j);
if (ChangeFillColor) {
ws->SetCellBackgroundColour(i, j, m_LastChosenFillColor);
format->m_BackgroundColor = m_LastChosenFillColor;
}

How to use a 2d vector of pointers

What is the correct way to implement an efficient 2d vector? I need to store a set of Item objects in a 2d collection, that is fast to iterate (most important) and also fast to find elements.
I have a 2d vector of pointers declared as follows:
std::vector<std::vector<Item*>> * items;
In the constructor, I instantiate it as follows:
items = new std::vector<std::vector<Item*>>();
items->resize(10, std::vector<Item*>(10, new Item()));
I how do I (correctly) implement methods for accessing items? Eg:
items[3][4] = new Item();
AddItem(Item *& item, int x, int y)
{
items[x][y] = item;
}
My reasoning for using pointers is for better performance, so that I can pass things around by reference.
If there is a better way to go about this, please explain, however I would still be interested in how to correctly use the vector.
Edit: For clarification, this is part of a class that is for inventory management in a simple game. The set 10x10 vector represents the inventory grid which is a set size. The Item class contains the item type, a pointer to an image in the resource manager, stack size etc.
My pointer usage was in an attempt to improve performance, since this class is iterated and used to render the whole inventory every frame, using the image pointer.
It seems that you know the size of the matrix beforehand, and that this matrix is squared. Though vector<> is fine, you can also use native vectors in that case.
Item **m = new Item*[ n * n ];
If you want to access position r,c, then you only have to multiply r by n, and then add c:
pos = ( r * n ) + c;
So, if you want to access position 1, 2, and n = 5, then:
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ];
Also, instead of using plain pointers, you can use smart pointers, such as auto_ptr (obsolete) and unique_ptr, which are more or less similar: once they are destroyed, they destroy the object they are pointing to.
auto_ptr<Item> m = new auto_ptr<Item>[ n * n ];
The only drawback is that now you need to call get() in order to obtain the pointer.
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ].get();
Here you have a class that summarizes all of this:
class ItemsSquaredMatrix {
public:
ItemsSquaredMatrix(unsigned int i): size( i )
{ m = new std::auto_ptr<Item>[ size * size ]; }
~ItemsSquaredMatrix()
{ delete[] m; }
Item * get(unsigned int row, unsigned int col)
{ return m[ translate( row, col ) ].get(); }
const Item * get(unsigned int row, unsigned int col) const
{ return m[ translate( row, col ) ].get(); }
void set(unsigned int row, unsigned int col, Item * it)
{ m[ translate( row, col ) ].reset( it ); }
unsigned int translate(unsigned int row, unsigned int col) const
{ return ( ( row * size ) + col ); }
private:
unsigned int size;
std::auto_ptr<Item> * m;
};
Now you only have to create the class Item. But if you created a specific class, then you'd have to duplicate ItemsSquaredMatrix for each new piece of data. In C++ there is a specific solution for this, involving the transformation of the class above in a template (hint: vector<> is a template). Since you are a beginner, it will be simpler to have Item as an abstract class:
class Item {
public:
// more things...
virtual std::string toString() const = 0;
};
And derive all the data classes you will create from them. Remember to do a cast, though...
As you can see, there are a lot of open questions, and more questions will raise as you keep unveliling things. Enjoy!
Hope this helps.
For numerical work, you want to store your data as locally as possible in memory. For example, if you were making an n by m matrix, you might be tempted to define it as
vector<vector<double>> mat(n, vector<double>(m));
There are severe disadvantages to this approach. Firstly, it will not work with any proper matrix libraries, such as BLAS and LAPACK, which expect the data to be contiguous in memory. Secondly, even if it did, it would lead to lots of random access and pointer indirection in memory, which would kill the performance of your matrix operations. Instead, you need a contiguous block of memory n*m items in size.
vector<double> mat(n*m);
But you wouldn't really want to use a vector for this, as you would then need to translate from 1d to 2d indices manually. There are some libraries that do this for you in C++. One of them is Blitz++, but that seems to not be much developed now. Other alternatives are Armadillo and Eigen. See this previous answer for more details.
Using Eigen, for example, the matrix declaration would look like this:
MatrixXd mat(n,m);
and you would be able to access elements as mat[i][j], and multiply matrices as mat1*mat2, and so on.
The first question is why the pointers. There's almost never any reason
to have a pointer to an std::vector, and it's not that often that
you'd have a vector of pointers. You're definition should probably be:
std::vector<std::vector<Item> > items;
, or at the very least (supposing that e.g. Item is the base of a
polymorphic hierarchy):
std::vector<std::vector<Item*> > items;
As for your problem, the best solution is to wrap your data in some sort
of a Vector2D class, which contains an std::vector<Item> as member,
and does the index calculations to access the desired element:
class Vector2D
{
int my_rows;
int my_columns;
std::vector<Item> my_data;
public:
Vector2D( int rows, int columns )
: my_rows( rows )
, my_columns( columns )
{
}
Item& get( int row, int column )
{
assert( row >= 0 && row < my_rows
&& column >= 0 && column < my_columns );
return my_data[row * my_columns + column];
}
class RowProxy
{
Vector2D* my_owner;
int my_row;
public;
RowProxy(Vector2D& owner, int row)
: my_owner( &owner )
, my_row( row )
{
}
Item& operator[]( int column ) const
{
return my_owner->get( my_row, column );
}
};
RowProxy operator[]( int row )
{
return RowProxy( this, row );
}
// OR...
Item& operator()( int row, int column )
{
return get( row, column );
}
};
If you forgo bounds checking (but I wouldn't recommend it), the
RowProxy can be a simple Item*.
And of course, you should duplicate the above for const.

How to work around a very large 2d array in C++

I need to create a 2D int array of size 800x800. But doing so creates a stack overflow (ha ha).
I'm new to C++, so should I do something like a vector of vectors? And just encapsulate the 2d array into a class?
Specifically, this array is my zbuffer in a graphics program. I need to store a z value for every pixel on the screen (hence the large size of 800x800).
Thanks!
You need about 2.5 megs, so just using the heap should be fine. You don't need a vector unless you need to resize it. See C++ FAQ Lite for an example of using a "2D" heap array.
int *array = new int[800*800];
(Don't forget to delete[] it when you're done.)
Every post so far leaves the memory management for the programmer. This can and should be avoided. ReaperUnreal is darn close to what I'd do, except I'd use a vector rather than an array and also make the dimensions template parameters and change the access functions -- and oh just IMNSHO clean things up a bit:
template <class T, size_t W, size_t H>
class Array2D
{
public:
const int width = W;
const int height = H;
typedef typename T type;
Array2D()
: buffer(width*height)
{
}
inline type& at(unsigned int x, unsigned int y)
{
return buffer[y*width + x];
}
inline const type& at(unsigned int x, unsigned int y) const
{
return buffer[y*width + x];
}
private:
std::vector<T> buffer;
};
Now you can allocate this 2-D array on the stack just fine:
void foo()
{
Array2D<int, 800, 800> zbuffer;
// Do something with zbuffer...
}
I hope this helps!
EDIT: Removed array specification from Array2D::buffer. Thanks to Andreas for catching that!
Kevin's example is good, however:
std::vector<T> buffer[width * height];
Should be
std::vector<T> buffer;
Expanding it a bit you could of course add operator-overloads instead of the at()-functions:
const T &operator()(int x, int y) const
{
return buffer[y * width + x];
}
and
T &operator()(int x, int y)
{
return buffer[y * width + x];
}
Example:
int main()
{
Array2D<int, 800, 800> a;
a(10, 10) = 50;
std::cout << "A(10, 10)=" << a(10, 10) << std::endl;
return 0;
}
You could do a vector of vectors, but that would have some overhead. For a z-buffer the more typical method would be to create an array of size 800*800=640000.
const int width = 800;
const int height = 800;
unsigned int* z_buffer = new unsigned int[width*height];
Then access the pixels as follows:
unsigned int z = z_buffer[y*width+x];
I might create a single dimension array of 800*800. It is probably more efficient to use a single allocation like this, rather than allocating 800 separate vectors.
int *ary=new int[800*800];
Then, probably encapsulate that in a class that acted like a 2D array.
class _2DArray
{
public:
int *operator[](const size_t &idx)
{
return &ary[idx*800];
}
const int *operator[](const size_t &idx) const
{
return &ary[idx*800];
}
};
The abstraction shown here has a lot of holes, e.g, what happens if you access out past the end of a "row"? The book "Effective C++" has a pretty good discussion of writing good multi dimensional arrays in C++.
One thing you can do is change the stack size (if you really want the array on the stack) with VC the flag to do this is [/F](http://msdn.microsoft.com/en-us/library/tdkhxaks(VS.80).aspx).
But the solution you probably want is to put the memory in the heap rather than on the stack, for that you should use a vector of vectors.
The following line declares a vector of 800 elements, each element is a vector of 800 ints and saves you from managing the memory manually.
std::vector<std::vector<int> > arr(800, std::vector<int>(800));
Note the space between the two closing angle brackets (> >) which is required in order disambiguate it from the shift right operator (which will no longer be needed in C++0x).
Or you could try something like:
boost::shared_array<int> zbuffer(new int[width*height]);
You should still be able to do this too:
++zbuffer[0];
No more worries about managing the memory, no custom classes to take care of, and it's easy to throw around.
There's the C like way of doing:
const int xwidth = 800;
const int ywidth = 800;
int* array = (int*) new int[xwidth * ywidth];
// Check array is not NULL here and handle the allocation error if it is
// Then do stuff with the array, such as zero initialize it
for(int x = 0; x < xwidth; ++x)
{
for(int y = 0; y < ywidth; ++y)
{
array[y * xwidth + x] = 0;
}
}
// Just use array[y * xwidth + x] when you want to access your class.
// When you're done with it, free the memory you allocated with
delete[] array;
You could encapsulate the y * xwidth + x inside a class with an easy get and set method (possibly with overloading the [] operator if you want to start getting into more advanced C++). I'd recommend getting to this slowly though if you're just starting with C++ and not start creating re-usable fully class templates for n-dimension arrays which will just confuse you when you're starting off.
As soon as you get into graphics work you might find that the overhead of having extra class calls might slow down your code. However don't worry about this until your application isn't fast enough and you can profile it to show where the time is lost, rather than making it more difficult to use at the start with possible unnecessary complexity.
I found that the C++ lite FAQ was great for information such as this. In particular your question is answered by:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.16
You can allocate array on static storage (in file's scope, or add static qualifier in function scope), if you need only one instance.
int array[800][800];
void fn()
{
static int array[800][800];
}
This way it will not go to the stack, and you not have to deal with dynamic memory.
Well, building on what Niall Ryan started, if performance is an issue, you can take this one step further by optimizing the math and encapsulating this into a class.
So we'll start with a bit of math. Recall that 800 can be written in powers of 2 as:
800 = 512 + 256 + 32 = 2^5 + 2^8 + 2^9
So we can write our addressing function as:
int index = y << 9 + y << 8 + y << 5 + x;
So if we encapsulate everything into a nice class we get:
class ZBuffer
{
public:
const int width = 800;
const int height = 800;
ZBuffer()
{
for(unsigned int i = 0, *pBuff = zbuff; i < width * height; i++, pBuff++)
*pBuff = 0;
}
inline unsigned int getZAt(unsigned int x, unsigned int y)
{
return *(zbuff + y << 9 + y << 8 + y << 5 + x);
}
inline unsigned int setZAt(unsigned int x, unsigned int y, unsigned int z)
{
*(zbuff + y << 9 + y << 8 + y << 5 + x) = z;
}
private:
unsigned int zbuff[width * height];
};