以伪随机顺序迭代列表而不存储混洗列表

时间:2013-11-25 10:52:48

标签: c++ random

a game中,我们使用名为“colour picking”的技术来选择单位。

这意味着每个可见单元都有一种独特的颜色。

以下是为颜色选择绘制的场景示例:

enter image description here

由于某些用户可能具有16位显示器,因此这些颜色可以在0..64K范围内。

但是,如果我们给单位增加颜色,例如unit0为0,unitN为N,那么人类调试的颜色非常难。单位几乎无法区分。

我们希望为这些单位提供独特而独特的色彩。

我们目前正在使用二叉树(C ++ map)以固定步骤递增,以存储用过的颜色以检查碰撞。这是低端硬件上的性能问题。即使这是一个哈希表并且避免使用string,游戏帧中的临时内存分配也是不受欢迎的。因此,我不想优化现有的代码,而是希望发现是否有办法完全避免维护历史。

有没有办法以大步长或随机迭代数字0..64K,以便使用大多数64K可能值,并避免使用已分配颜色的历史来避免碰撞?

(屏幕上不可能有超过64K的可见单元,我们无需处理这种情况!)

5 个答案:

答案 0 :(得分:8)

我的尝试:

  1. 选择一个prime number接近您想要的范围(64007在这里是一个很好的候选人)。
  2. 找到此号码的primitive roots modulo p
  3. 选择一个“中等范围”原始根( 43062 43067是一个很好的候选者)。

    class Sequence
    {
    public:
         uint32_t get() const {return state;}
         void advance() { state = (state * k)%p;}
         void reset() { state = k; }
    private:
         uint32_t state = 43067;
         const uint32_t k = 43067;
         const uint32_t p = 64007;
    };
    
  4. 以伪随机方式将范围[1,64007]中的所有数字精确地循环一次。

答案 1 :(得分:1)

您可以简单地将step_size作为总可用颜色除以总单位,然后使用(unit_index * step_size)作为每个单位的颜色吗?

答案 2 :(得分:1)

我真的没有看到问题。正如我在评论中所写,你只需要128K来存储[0..64K]的排列,并且你不需要在主循环中进行任何分配。这是C ++ 11中的有状态颜色存储(在旧版C ++中,使用vectornew[]):

class ColorPicker {
    std::array<uint16_t, 65536> colors;
    uint16_t idx;

  public:
    ColorPicker() : idx(0)
    {
        std::iota(colors.begin(), colors.end(), 0);
        std::random_shuffle(colors.begin(), colors.end());
    }

    uint16_t next_color()
    {
        return colors[idx++];
    }
};

您只需要其中一种结构。现在,无论何时创建新单元,请在next_color上调用ColorPicker并将其作为属性存储在单元上。

此解决方案将循环显示颜色。如果不需要,请在每次索引回绕到零时执行random_shuffle

答案 3 :(得分:1)

在我看来,重要的是彼此接近的单位之间的对比度足够高,即我会试图想出一些方法来考虑单位的接近程度。

例如,您可以考虑单位的X / Y坐标,使得彼此接近的坐标获得具有高对比度的颜色,低对比度仅用于距离足够远的单位。

第一个镜头可能是拥有256种颜色的简单数组a,因此a[n]a[n+1]之间存在较大的对比度。然后,您可以使用模数为256的X和/或Y坐标作为数组的索引来选择单位的颜色。这样,您将获得的颜色重用于至少256像素(或您可能使用的任何度量标准)的单位,但不同颜色的单位彼此非常接近。

答案 4 :(得分:0)

首先,使用二进制来存储颜色状态(1使用,0使用)。 2 ^ 16 = 65536(状态)。如果我们使用1位作为一种颜色,则需要65536/8 = 8192字节。
下一个问题是如何管理这些字节。我建议树结构:在这8192个字节上,需要另一个(8192/8 =)1024个字节,这些高位字节中的每个位代表8192个字节中的一个字节,如果其中一个低位字节是 ALL 1,其高位为1。
此规则可以扩展上部和上部:8192 - &gt; 1024 - &gt; 128 ...最后,到1个字节(虽然没有完全使用)。
要使用此结构,您可以从根字节多次生成0..7中的随机数,如果其位为1,请再次尝试;如果它的0,低到低字节,重复这些动作,直到达到最低字节。
此外,您可以在一个数组中构建此树:就像堆中的堆一样。 (有一些空单位)。

APPEND:int16需要一种颜色,一旦下到低位字节,你得到一个三位二进制数,从左到右追加颜色编号:int16。 (根字节只代表2个状态,只生成1位二进制数,其形式为111111 ??。