2012-02-22 7 views
1

私は四角形のグリッドを持っています。各正方形は黒または白です。グリッドの範囲はX:-10~10、Y:-10~10です。私はboolの2D配列でグリッドを表現したい - 黒は真、白は偽です。配列のインデックスは肯定的ですが、配列を使ってグリッドを作成したい場合はbool array [21][21]となります。これは仕事ですが、要素にアクセスしようとすると混乱します。たとえば、グリッドの座標「0,3」にアクセスする場合、配列インデックスは[11] [14]になります。これはうまくいきますが、本当に面倒です。C++での単純な配列の使用ですか?

座標に対応するインデックスを取得できる「クリーナー」の方法はありますか?

+1

グリッドの範囲が各軸で-10~10の場合、21×​​21のグリッドではありませんか? –

+0

@AndréCaronあなたの権利。それを私が直した。 – fdh

答えて

6

あなたが必要なインターフェイスを提供していますクラスにロジックをカプセル化することができます。それは少しジェネリックにするには、タイプを保存すると、寸法が変化することができることを考えることができます。

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 ]; 
    } 
}; 

実装は、おそらくいくつかの詳細が必要ですが、一般的な考え方があります。エラー報告やその他多くのことがあるはずです...ディメンションは(テンプレート引数ではなく)実行時プロパティにすることができますが、動的割り当て、適切なデストラクタ、コピーコンストラクタが必要です...実際には行きたくありませんすべてのことをちょうどアイデアのために。私は、これは未定義の動作を呼び出しますかなり確信している

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

+1私はあなたの答えが私のものより好きです:) –

+0

コンストラクタに関して: 'offset_array2d():data(){}'は仕事をするべきです... '' '' ' '-offset_x'で指定します。 –

+0

@MatthieuM .:エラーを指摘していただきありがとうございます。 –

2

あなたは、アレイへのすべての変更のための関数呼び出しを行うことによるオーバーヘッドを心配している場合は、その後、

#define OFFSET 10 

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

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

} 

ので

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

ヘルパー関数を作成する必要があります代わりにマクロを使用できます。

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

しかし、マクロを使用する際の安全性の問題を十分に理解していない限り、これを行わないでください。また、C99またはC++を使用している場合は、インラインメソッド/関数を使用できます。これは同じことをしますが、危険はありません。

enum Color {BLACK, WHITE}; 
+0

この場合は重要ではありませんが、enumは通常intのサイズを占有しませんか?したがって、sizeof(int)によってサイズ要件を増やしますか?より大きなグリッドで重要になる可能性があります。 – dcousens

+0

あなたは正しいですが、透明性がトレードオフの価値がある場合があります – Avi

3

あなたは単に配列の正しいオフセットを計算する関数、を通して、あなたの配列にアクセスすることができました(10を追加します。

考える

また、列挙型は、ブール値よりも良いかもしれませんxおよびy):

bool grid[21][21]; 

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

正方形を設定する場合も同じです。私はこれをすべてGridクラスにラップします。

またbool[]とは対照的に、個々のビットとして各boolを保存し、あなたにstd::vectorクラスの余分な(おそらく不要)機能を与えるであろう、std::vector<bool>を使用する場合があります。

+0

ドメイン-10〜10をカバーするには、配列を[21] [21]に設定する必要があります。 –

+0

@BicycleDude:OPの(現在はedittedされている) 'array'宣言をコピー&ペーストして、チェックすることさえ考えませんでした。 – AusCBloke

+0

@AusCBloke 'bool grid [21] [21]'はstd :: vectorの実装よりもまだ小さいです。データについては言及しません。なぜ複雑さを追加するのですか? – dcousens

0

インデックスを増分/減分する代わりに、特定のインデックスに特定のインデックスを割り当てるints(マップ)のマップを作成します。

次に、平方の値にマップの値を渡します(たとえば、キー値-10 => 0(インデックス)の平方テーブルにマップの結果を渡します)。 http://www.yolinux.com/TUTORIALS/CppStlMultiMap.html

確かにマップが簡単な関数よりも多くのメモリを使用しますが、その再利用性のためのよりよい:

現在地のマップの例を持っています。

1

単純な使い方(実装と保守は少し難しい)を提供するには、ゲッターとセッターで複雑さを隠すC++クラスを作成してください。演算子のオーバーロードを考慮することもできます。フィールドがバイナリであるので、私はビット演算を使用して、データをパックすることを選択しました:

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]; 
}; 
2

スペクトルのもう一方の端は、今非常に簡単になり、ユーザーコード、です。私はまた、私が気にしているすべてのアーキテクチャーでこれがうまく動作することを確信しています

#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]); 
} 
関連する問題