【问题标题】:Algorithm for generating not repeating, spaced-out RGB color values生成不重复、间隔 RGB 颜色值的算法
【发布时间】:2016-08-14 15:06:45
【问题描述】:

我想要一个静态方法,无论何时调用它都会返回一个尚未出现的颜色值,并且与上次返回的颜色不太接近(即return new Color(last_value += 10) 不会这样做)。它也不应该是随机的,因此每次启动应用程序时,返回颜色的顺序都是相同的。

我想到的第一件事是使用原始数字步长遍历数组,如下所示:

    private static HashMap<Integer, Boolean> used = new HashMap<>();
    private static int[] values = new int[0xfffff]; // 1/16th of possible colors
    private static int current = 0, jump = values.length / 7;

     public static Color getColour(){
        int value = values[current];
        used.put(current, true);
        current += jump;
        current %= values.length;
        //have some check here if all colors were used
        while (used.containsKey(current)){
            current++;
            current%=values.length;
        }
        return new Color(value);
    }

但我不喜欢它,因为在某些回调中颜色会彼此接近。

【问题讨论】:

  • 您如何准确定义 RGB 配色方案的接近度?
  • 为什么不需要随机颜色?我认为在某些时候你必须使用随机。
  • @svs 好吧,只要看一眼颜色就可以彼此区分,同时由宽调色板组成,所以它不仅仅是例如。红色。
  • @Priyamal 使用的颜色是用户界面的一部分,如果用户每次启动应用程序时,一切看起来都不一样,那肯定会给用户带来困扰。
  • @CoderinoJavarino colors are distinct from each other just by glancing at it 你是如何在数学上定义的?

标签: java algorithm colors


【解决方案1】:

使用LFSR 生成非重复的类随机序列的好方法。

/**
 * Linear feedback shift register
 *
 * Taps can be found at: See http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf See http://mathoverflow.net/questions/46961/how-are-taps-proven-to-work-for-lfsrs/46983#46983 See
 * http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm See http://www.yikes.com/~ptolemy/lfsr_web/index.htm See
 * http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
 *
 * @author OldCurmudgeon
 */
public class LFSR implements Iterable<BigInteger> {

    // Bit pattern for taps.
    private final BigInteger taps;
    // Where to start (and end).
    private final BigInteger start;

    // The poly must be primitive to span the full sequence.
    public LFSR(BigInteger primitivePoly, BigInteger start) {
        // Where to start from (and stop).
        this.start = start.equals(BigInteger.ZERO) ? BigInteger.ONE : start;
        // Knock off the 2^0 coefficient of the polynomial for the TAP.
        this.taps = primitivePoly.shiftRight(1);
    }

    public LFSR(BigInteger primitivePoly) {
        this(primitivePoly, BigInteger.ONE);
    }

    // Constructor from an array of taps.
    public LFSR(int[] taps) {
        this(asPoly(taps));
    }

    private static BigInteger asPoly(int[] taps) {
        // Build the BigInteger.
        BigInteger primitive = BigInteger.ZERO;
        for (int bit : taps) {
            primitive = primitive.or(BigInteger.ONE.shiftLeft(bit));
        }
        return primitive;
    }

    @Override
    public Iterator<BigInteger> iterator() {
        return new LFSRIterator(start);
    }

    private class LFSRIterator implements Iterator<BigInteger> {
        // The last one we returned.

        private BigInteger last = null;
        // The next one to return.
        private BigInteger next = null;

        public LFSRIterator(BigInteger start) {
            // Do not return the seed.
            last = start;
        }

        @Override
        public boolean hasNext() {
            if (next == null) {
                /*
                 * Uses the Galois form.
                 *
                 * Shift last right one.
                 *
                 * If the bit shifted out was a 1 - xor with the tap mask.
                 */
                boolean shiftedOutA1 = last.testBit(0);
                // Shift right.
                next = last.shiftRight(1);
                if (shiftedOutA1) {
                    // Tap!
                    next = next.xor(taps);
                }
                // Never give them `start` again.
                if (next.equals(start)) {
                    // Could set a finished flag here too.
                    next = null;
                }
            }
            return next != null;
        }

        @Override
        public BigInteger next() {
            // Remember this one.
            last = hasNext() ? next : null;
            // Don't deliver it again.
            next = null;
            return last;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Not supported.");
        }

        @Override
        public String toString() {
            return LFSR.this.toString()
                    + "[" + (last != null ? last.toString(16) : "")
                    + "-" + (next != null ? next.toString(16) : "") + "]";
        }
    }

    @Override
    public String toString() {
        return "(" + taps.toString(32) + ")-" + start.toString(32);
    }

}

现在您只需要一个8+8+8=24 抽头值。

使用起来很简单。

public void test() {
    // Sample 24-bit tap found on page 5 of
    // http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
    int[] taps = new int[]{24, 23, 22, 17};
    LFSR lfsr = new LFSR(taps);
    int count = 100;
    for (BigInteger i : lfsr) {
        System.out.println("Colour: " + new Color(i.intValue()));
        if (--count <= 0) {
            break;
        }
    }
}

LFSR 的特点:

  • 重复 - 但直到所有可能的位模式都已生成(0 除外)。
  • 生成的数字在统计上是一个很好的随机数。
  • 每次都会生成相同的序列(如果您想要不同的序列,请选择不同的tap)。

为了达到您需要的间距,我建议您添加一个过滤器并丢弃任何(根据您的标准)与前一个过滤器太接近的过滤器。

【讨论】:

    猜你喜欢
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 2021-01-06
    • 2011-04-26
    • 1970-01-01
    相关资源
    最近更新 更多