使用其他信息扩展指针/引用

时间:2015-11-11 08:23:48

标签: architecture

我正在编写一个程序,当玩家遍历它时,程序生成一个迷宫。每个迷宫瓷砖可能具有北,东,南和西邻居。我正在考虑使用指针/引用来存储每个邻居,但是我还必须保存信息是否路径是空闲的(对于未来的迷宫生成或者如果邻居已经生成则只是玩家移动)或者是否被阻止。

我想到了以下方法:

// 1. aggregate data in a new data type
struct Pathway {
    bool isFree;
    MazeTile* neighbor;
}
Pathway north = {true, nullptr}

// 2. store data paralelly
MazeTile* north = nullptr;
bool isNorthFree = true;

// 3. Use inheritance to create a blocked tile
MazeTile* south = new BlockedMazeTile();

我个人会选择第一种方法,但我以前从未见过这种做法。第三个看起来很好并且可以轻松扩展,但解决方案与底层迷宫设计绑定,不能用作这种问题的一般方法。

那么,这些解决方案中哪一个是首选的 - 如果没有,那么它的方法是什么?

2 个答案:

答案 0 :(得分:1)

当然,这取决于我会选择第一个。

它比第三个更好,因为如果需要,您可以在不重新创建类实例的情况下取消阻止您的迷宫图块。谁知道,明天你的魔法世界会发生什么,对吧?灵活变得更好。以防万一;)

此外,如果可能,您可以将迷宫图块存储为数组,如果您的游戏区域或多或少是正方形的话。那么你根本不需要任何对邻居区块的引用。只是blocked标志或任何表示下一个瓷砖进入的标志。

答案 1 :(得分:1)

我也建议#1,但是你并不像想象的那样将图形式的数据结构存储到链接节点的边缘。

如果你想让它变得非常紧密,你可以做的另一件事就是让这些边(路径)只是将索引存储到MazeTile而不是指针。使用索引,您可以将辅助数据存储到高位,例如,指示路径是否被阻止或者您需要什么。

编辑:

根据要求,这里是更详细的基于索引的解决方案。假设你这样做:

class Pathway 
{
public:
    /// Creates a new pathway.
    Pathway();

    /// Sets the index of the neighboring maze tile/node.
    void set_maze_tile(int new_index);

    /// @return The index to the neighboring maze tile/node.
    int maze_tile() const;

    /// Sets whether the pathway is free or not.
    void set_free(bool val);

    /// @return True if the pathway is free.
    bool is_free() const;

private:
    int index;
};

要做到这一点,你需要将这些迷宫图块分配到一些连续的内存块中(例如:使用std::vector或某种其他动态数组 - 它可以增长而不会使索引无效)。

现在你可以这样做:

enum
{
    free_bit = 1 << (sizeof(int)*8 - 1),
    index_mask = ~free_bit
};

Pathway::Pathway(): index(0)
{
}

void PathWay::set_maze_tile(int new_index)
{
     const bool was_free = is_free();
     index = new_index;
     set_free(was_free);
}

int PathWay::maze_tile() const
{
     return index & index_mask;
}

void PathWay::set_free(bool val)
{
    if (val)
        index |= free_bit;
    else
        index &= ~free_bit;
}

bool PathWay::is_free() const
{
     return (index & free_bit) != 0;
}

这是一个有点丑陋,低级别的样式代码,这个界面是一种无聊的getter / setter设计,但它会压缩你的路径,通常占用64位的大约16个字节(考虑到通常的结构填充/ alignment)只需4个字节,这不仅有助于减少内存使用,而且还可以提高速度(更大的空间局部性,更适合缓存线的相邻路径)。

它确实将您的无符号索引范围从2 ^ 31减少到2 ^ 30(允许大约10亿个迷宫图块)。您可以使用unsigned int将该范围加倍到2 ^ 31(尽管除非您真的打算处理接近该范围的某些内容,否则它可能不值得打扰。)