n2d4
a year ago
0
3
Here's a solution with ~3.27 average tries total (including the last guess). It works by spreading the possibilities across each of the 100 "score" buckets as evenly as possible (aka minimizing the variance).

It can identify more than half of all colors in just 2 guesses. If you edit the code to minimize the size of the largest bucket instead, you get an algorithm that has a slightly worse average case, but never needs more than 4 guesses.

Paste it in the site's browser console to try.

    function solve() {
      let possibleTargets = new Array(0x1000).fill(0).map((_, i) => i);
      while (true) {
        // for each possible guess, calculate the score-buckets
        const guessResults = possibleTargets.map((guess) => {  // for better brute-force, iterate through all colors, but this performs better (probably because we don't reward for guessing correctly in the current turn)
          const buckets = new Array(101).fill(0).map(() => []);
          for (const possibleTarget of possibleTargets) {
            buckets[calcScore(possibleTarget, guess)].push(possibleTarget);
          }
          return { guess, buckets };
        });

        // find guess with lowest variance
        const best = guessResults.sort((a, b) => calcVariance(a.buckets) - calcVariance(b.buckets))[0];

        // make the guess & update possible targets
        const sc = makeGuess(best.guess);
        if (sc >= 100) return "Success!";
        possibleTargets = best.buckets[sc];
      }
    }

    function calcVariance(buckets) { const maxBucketSize = Math.max(...buckets.map(b => b.length)); return buckets.reduce((acc, b) => acc + (b.length - maxBucketSize) ** 2, 0); }

    function deconstruct(color) { return [(color & 0xF00) >> 8, (color & 0x0F0) >> 4, (color & 0x00F)]; }

    function calcScore(target, guess) { return score(...deconstruct(target), ...deconstruct(guess)); }

    function makeGuess(guess) { [rr, gg, bb] = deconstruct(guess); submitInput(); return score(r, g, b, rr, gg, bb); };

    solve();
penteracta year ago
That's great. What's the first guess? And does this prove that there is no way of identifying the answer in 2 guesses? I tried running a version of your code across all targets, but my current machine isn't up to it (and there are obviously more efficient ways that you've probably implemented).

I'd like to try out a few alternatives in place of your variance function. Something like b.length*log(b.length) to estimate the expected number of guesses, and perhaps using a version of log closer to ceil(log(x)/log(100)).

Taekpenteracta year ago
You can do 2 guesses if you get lucky. If you want to assume worst possible luck you can't even do it in 3, you need 4.
n2d4penteracta year ago
The first color is #015.

Regarding computing it for all targets, I optimized it by precomputing the value of guessResults in the first iteration, since it's always the same (no matter the target color), which saves most of the computation. I removed the optimization so the code wouldn't be so long here.