3

我想设置所有俄罗斯方块的定义:

#include <iostream>
#include <vector>

struct Tetris{
    std::vector<int> data;
    int getAt(int x, int y){return data.at(y*4+x);};
} tetris[6];

int main(){
    //stick
    tetris[0].data.resize(32);
    int array0[32]={0,0,0,0,
                    0,0,0,0,
                    1,1,1,1,
                    0,0,0,0,
                    0,1,0,0,
                    0,1,0,0,
                    0,1,0,0,
                    0,1,0,0};
    tetris[0].data.assign(array0,array0+32);

    //brick
    tetris[1].data.resize(16);
    int array1[16]={0,0,0,0,
                    0,1,1,0,
                    0,1,1,0,
                    0,0,0,0};
    tetris[1].data.assign(array1,array1+16);

    ...

}

这样我就需要定义6个数组来存储初始化数据(array0... array1),初始化后就没用了。这似乎非常低效并且浪费内存。我想知道是否有办法在每次使用后删除这些数据?

更新:

如果我想重用array0,说

    tetris[0].data.resize(32);
    int array0[32]={...};
    tetris[0].data.assign(array0,array0+32);

    //brick
    tetris[1].data.resize(16);
    delete array0;
    int array0[16]={...};
    tetris[1].data.assign(array0,array0+16);

    ...

编译器会报错“array0 redefinition”。delete在这种情况下不工作?

4

3 回答 3

5

如果您想控制静态分配类型的生命周期,您可以添加任意范围解析运算符来执行此操作。

int main()
{
    {
        //stick
        tetris[0].data.resize(16);
        int array0[16]={0,0,0,0,
                    0,0,0,0,
                    1,1,1,1,
                    0,0,0,0};
        tetris[0].data.assign(array0,array0+16);

        //brick
        tetris[1].data.resize(16);
        int array1[16]={0,0,0,0,
                    0,1,1,0,
                    0,1,1,0,
                    0,0,0,0};
        tetris[1].data.assign(array1,array1+16);
    }//THISONE
    //Do the rest of the work of main, without the pesky arrays sticking around.

}

在这个 main 示例中,您的俄罗斯方块变量仍然存在,因为它是全局的。但是您声明的那些数组不会停留在“THISONE”之后。

请注意,我不一定推荐这种方法。创建一个类,或者使用其他一些更标准的方法是更可取的。但有时这是一个不错的小技巧,可以避免使用不必要的动态分配。

编辑:这种方法可能更好,但请确保您了解正在发生的一切,否则您最好坚持您所知道的。特别是如果您不了解我在这里所做的所有坏事,以便快速为您提供示例。

#include <iostream>
using namespace std;

class stick;//Forward declaration so shape can make stick a "friend"

class shape {//This classe declaration should go in a .h file.
    static const int WIDTH = 4;
    static const int HEIGHT = 4;
    int array[WIDTH][HEIGHT];

public:


    shape(){
        for(int i = 0; i < HEIGHT; i++) {
            for(int j = 0; j < WIDTH; j++) {
                array[i][j] = 0;
            }
            array[i][i] = 1;
        }
    }

    void printShape() {
        for(int i = 0; i < HEIGHT; i++) {
            for(int j = 0; j < WIDTH; j++) {
                cout << array[i][j] << " ";
            }
            cout << endl;
        }
    }

    friend class stick;
};

class stick: public shape {//This declaration should also go in a header file
public:
    stick() {
        for(int i = 0; i < HEIGHT; i++) {
            for(int j = 0; j < WIDTH; j++) {
                if(i == 0) array[i][j] = 1;
                else array[i][j] = 0;
            }
        }
    }
};



int main(){

    shape planeShape;
    stick stickShape;
    cout << "PLAIN SHAPE: " << endl;
    planeShape.printShape();

    cout << endl << "STICK SHAPE: " << endl;
    stickShape.printShape();



    cout << endl << "PLANE SHAPE POINTER:" << endl;
    shape* shapePointer = &planeShape;
    shapePointer->printShape();

    cout << endl << "STICK SHAPE POINTER:" << endl;
    shapePointer = &stickShape;
    shapePointer->printShape();

}
于 2013-06-06T19:04:11.710 回答
2

构成程序的指令存在于内存中。因此,您array0显式设置值的事实array0[n]={0,0,1,...}意味着这些值已经通过分配它们的代码存储在内存中并且无法删除。

即使您切换到使用指针和动态分配的数组,您仍然会在内存中始终存在数组的内容,因为它们在填充数组的代码中是硬编码的。

我只会使用您的原始设置,除非不要重复使用array0. 对于您要使用的每种情况,都有一个不同的数组array0

于 2013-06-06T19:26:35.153 回答
1

您可以尝试以编程方式生成图块,但由于对称性,需要注意重复,并且某些生成的图案可能是伪造的,例如:

int array0[16]={0,0,0,0,
                0,0,0,0,
                0,0,0,0,
                1,1,1,1};

int array0[16]={0,0,0,1,
                0,1,0,0,
                1,1,0,1,
                0,0,1,0};

可以通过尝试每种组合的生成算法生成。为避免重复,您需要建立瓷砖配置中存在的对称规则。在更一般的多联骨牌设置中,这将是一个非常有趣的问题。

对于俄罗斯方块图块,鉴于只有少数有效配置,该解决方案可能有点牵强。但是,您可以节省一点内存空间,方法是将所有图块存储在同一个数组中,使用数组元素的每个位来携带每个图块的信息,然后使用位掩码选择正确的模式。

这是 C++11 中的一个小程序为您进行组合:

#include <array>
#include <vector>
#include <iostream>
#include <utility>

#define WIDTH 4

typedef std::pair<int,int> coord_t;

coord_t coord(int x, int y) {
  return std::make_pair(x,y);
}

int index(const coord_t &c) {
  //std::cout << "getting (" << c.first << "," << c.second << ")" << std::endl;
  return c.first * WIDTH + c.second;
}

coord_t cw (const coord_t &c){ 
  int x = c.first;
  int y = c.second;
  return coord(WIDTH - 1 - y, x);
}

coord_t r0(const coord_t &c){
  return c;
}

coord_t r90(const coord_t &c){
  return r0(cw(c));
}

coord_t r180(const coord_t &c){
  return r90(cw(c));
}

coord_t r270(const coord_t &c){
  return r180(cw(c));
}

typedef coord_t (*rotate)(const coord_t &);


class tetro;

std::ostream &operator <<(std::ostream &out, const tetro &t);

class tetro {

public:

  tetro(){ v.reserve(WIDTH * WIDTH); }

  tetro(const std::initializer_list<int> &data): v(data){
    std::cout << *this << std::endl;
  }

  tetro(const tetro &src) {
    for (int i = 0; i < WIDTH * WIDTH; i++)
      v[i] = src.v[i];
  }

  void set(coord_t c, int val){
    v[index(c)] = val;
  }

  int get(coord_t c) const {
    return v[index(c)];
  }

  void combine (int r, const tetro &b, rotate rot){
    int i,j;
    for (i = 0; i < WIDTH; i++) {
      for (j = 0; j < WIDTH; j++) {
        coord_t c = coord(i,j);
        set(c, get(c) | ( b.get(rot(c)) << r));
      }
    }
  }

private:

  std::vector<int> v;

};

std::ostream &operator <<(std::ostream &out, const tetro &t){
  int i,j;
  for (i = 0; i < WIDTH; i++) {
    for (j = 0; j < WIDTH; j++) {
      coord_t c = coord(i,j);
      out << t.get(c) << ",";
    }
    out << std::endl;
  }
  return out;
}

std::array<tetro, 6> vl {{

  {
    0,0,1,0,
    0,0,1,0,
    0,1,1,0,
    0,0,0,0
  },

  {
    0,0,0,0,
    0,1,1,0,
    0,1,1,0,
    0,0,0,0
  },

  {
    0,0,0,0,
    1,1,1,1,
    0,0,0,0,
    0,0,0,0
  },


  {
    0,1,0,0,
    0,1,0,0,
    0,1,1,0,
    0,0,0,0
  },

  {
    0,1,0,0,
    0,1,1,0,
    0,0,1,0,
    0,0,0,0
  },

  {
    0,0,0,0,
    1,1,1,0,
    0,1,0,0,
    0,0,0,0
  }

  }};

void combine(int rank, tetro &t, rotate rot){
  for (auto it = vl.begin(); it != vl.end(); ++it) {
    t.combine(rank, *it, rot);
    rank++;
  }
}

int main(){

  tetro t;
  int d = 6;
  combine(0, t, r0);
  combine(d, t, r90);
  combine(d+d, t, r180);
  combine(d+d+d, t, r270);

  std::cout << "result " << std::endl << t << std::endl;

}

它从规范和镜像的四元开始, 并构建一个包含所有变化的单个数组int,包括每个四元骨的所有旋转。您可以简单地将代码限制为第一个组合 - 即。如果您的代码已经处理了旋转,则无需旋转,char而是使用数组,总共仅消耗 16 个字节的空间(不计算操作数据所需的任何其他代码使用的空间,保留为练习...)。

否则,保留整个数据,并使用享元模式来实现您的对象,每个对象仅包含四联体的等级,以及它的旋转(090180270,因此 4 种不同的状态)。您必须包含上述程序生成的整个数组(384 字节),并编写函数来根据等级和状态计算位掩码(这可以从提供的程序的代码中推断出来)。

于 2013-06-06T19:57:07.663 回答