简体   繁体   中英

Simple array use in C++?

I have a grid of squares. Each square is either black or white. The grid ranges from X:-10 to 10 and Y:-10 to 10. I want to represent the grid with a 2D array of bools - black is true and white is false. Array indexes are only positive though- so if I want to create the grid with an array it would be bool array [21][21] . This does the job, but it gets confusing when I am trying to access an element. For example, if I want to access the coordinate "0,3" on the grid, my array index would be [11][14]. This works, but its really messy.

Is there any "cleaner" way I could get the index to correspond with the coordinate?

You can encapsulate the logic into a class that offers the interface you need. To make it a bit generic, you can consider that the type to be stored and the dimensions could vary:

 template <typename T, int DimX, int DimY>
 class offset_array2d
 {
    T data[ DimX*DimY ];
    static const int offset_x = DimX / 2;
    static const int offset_y = DimY / 2;
 public:
    offset_array2d() : data() {}
    T& operator()( int x, int y ) {
       return data[ (x+offset_x) + (y+offset_y)*DimY ];
    }
    T const & operator()( int x, int y ) const {
       return data[ (x+offset_x) + (y+offset_y)*DimY ];
    }
 };

The implementation probably needs some details, but the general idea is there. There should be error reporting and many more things... the dimensions could be made a runtime property (rather than template argument) but that requires dynamic allocation, a proper destructor and copy constructor... I don't really want to go into all that for just the idea.

The other end of the spectrum is user code, that would be quite simple now:

 int main() {
    offset_array2d<bool,21,21> board;
    for ( int i = -10; i < 11; ++i )
      board( i, i ) = true;          // write the diagonal
 }

You could simply access your array through a function, which will calculate the correct offset in the array (add 10 to x and y):

bool grid[21][21];

bool getSquareColour(size_t x, size_t y)
{
   // add bounds checking here
   return grid[x+10][y+10];
}

The same goes for setting the squares. I would wrap all of this into a Grid class.

You might also want to use std::vector<bool> as opposed to bool[] , which will store each bool as individual bits and gives you the extra (possibly unneeded) functionality of the std::vector class.

You should make a helper function

#define OFFSET 10

void place_elem(int x, int y, bool color){

     //put bounds checks here
     a[OFFSET+x][OFFSET+y] = color;

}

So

place_elem(0, -3, true) == (a[10][7] = true)

If you are worried about the overhead of making a function call for every change to the array, then you could use a macro instead:

#define PLACE_ELEM(x, y, c) (a[OFFSET+x][OFFSET+y] = c)

But, DON'T do this unless you fully understand the safety issues with using macros. Also, if you are using C99 or C++ you can use inline methods/functions. This will do the same thing, but without the hazards.

Also, an enum might be better than a bool

Think:

enum Color {BLACK, WHITE};

I'm pretty sure this invokes undefined behavior. I'm also pretty sure this works on every architecture I care about.

#include <cassert>


int main () {
   bool grid_[21][21];
   bool (*grid)[21];

   grid = (bool (*)[21])(&grid_[10][10]);
   assert(&grid_[0][0] == &grid[-10][-10]);
   assert(&grid_[0][20] == &grid[-10][10]);
   assert(&grid_[20][20] == &grid[10][10]);
}

Just to provide an alternate answer that's simple to use (but a little hard to implement and maintain), create a C++ class that hides the complexity with a getter and setter. You can also consider overloading operators. Since the field is binary, I've elected to pack the data using bitwise operations:

class SimpleArray
{
public:
  SimpleArray()
  {
    memset(data, 0, sizeof(data));
  }

  void set(int x, int y, bool value)
  {
    if (x >= -10 && x <= 10 && y >= -10 && y <= 10)
    {
      if (value)
      {
          data[y + 10] |= (1 << (x + 10));
      }
      else
      {
          data[y + 10] &= ~(1 << (x + 10));
      }
    }
  }

  bool get(int x, int y)
  {
    if (x >= -10 && x <= 10 && y >= -10 && y <= 10)
    {
      return (data[y + 10] & (1 << (x + 10))) != 0;
    }
    return false;
  }

  private:
    unsigned int data[21];
};

Instead of incrementing/decrementing your indexes I would create a map of ints (map) where you would assign a specific index to your specific value.

You would then pass the value of the map for your square value (eg you pass the result of the map in your square tables for key value -10 => 0 (index)).

You have an example of maps here: http://www.yolinux.com/TUTORIALS/CppStlMultiMap.html

Sure maps use more memory than a simple function but its better for re-usability.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM