3 ms·
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 e
by n2d4 3y ago
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();
- penteract 3y agoThat'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)).
- Taek 3y agoYou 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.
- n2d4 3y agoThe 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.