This puzzle is based on a Bloom filter, an efficient and handy data structure for testing membership in a set quickly using a series of hash functions and a vector of bits.
Solvers can play around with the checker on the web page, but it’s not likely that they will make much progress doing so, because there are only a small number of words that are “allowed” and guessing them will be difficult. We do provide one concrete example of an allowed word in the flavortext.
But since the code implementing the Bloom filter is written up quite clearly in bloomfilter.js, solvers can rip this code out and just feed a large wordlist through it to see what it accepts. Comments in the HTML and Javascript invite solvers to investigate the code. (All the words that are “allowed” are real words, most are pretty familiar, and most should be included on even a modest list of English words.) The easiest way to do this is just use node.js and run the code in bloomfilter.js directly, but solvers who program should be able to reimplement this without too much trouble in the language of their choice if they hate Javascript.
Running a wordlist through the checker will discover the following list of allowed words:
(Perhaps the solver’s wordlist will be missing some of these, but it should be possible to fill them in by hand once solvers realize what’s going on.) Here’s where non-coders get to pitch in and help solve! Almost all these words can be organized into groups of four according to some rule, forming a (not necessarily closed) set. There is always a fifth member of this set which was not “allowed” that is the common name of a flower (hey, it’s a bloom filter!). Ordered alphabetically by these missing blooms:
Missing bloom | 1 | 2 | 3 | 4 | Set |
---|---|---|---|---|---|
ASTER | RATES | STARE | TASER | TEARS | Anagrams |
BUTTERCUP | CORCORAN | DEADEYE | HEBE | PORTER | H.M.S. Pinafore characters |
CARNATION | ALTERNATION | DAMNATION | INTONATION | STAGNATION | <word>NATION |
DAISY | AMBASSADOR | BROWNIE | JUNIOR | SENIOR | Girl Scout levels |
EDELWEISS | ALLEGRO | OKLAHOMA | SOLILOQUY | SUNDAY | Rodgers & Hammerstein songs |
FREESIA | ARIES | BRIEFCASE | EASIER | FIREBASE | Transdeletion sequence |
GERANIUM | ARGO | BOON | CHORINE | ODIUM | Elements missing a letter |
HIBISCUS | BOTSWANA | HOLDOVER | LAWRENCE | MALARKEY | Hidden four-letter birds |
IRIS | CORNEA | LENS | PUPIL | RETINA | Parts of the eye |
JASMINE | ALADDIN | GENIE | IAGO | JAFAR | Aladdin characters |
KINGCUP | ACETONE | JACKKNIFE | QUEENSIDE | TENFOLD | <honor card><word> |
LOTUS | BENTLEY | JAGUAR | MINI | MORGAN | British car makes |
MAGNOLIA | COCKTAIL | COLLATERAL | OBLIVION | VALKYRIE | Tom Cruise films |
NARCISSUS | CHAKRA | FUTHARK | RHINO | TAMARIN | Javascript engines |
ORCHID | ARROW | FLAME | HYDRA | SWAN | Dharma Initiative stations |
PRIMROSE | CORIOLANUS | GALE | RUE | THRESH | Hunger Games characters |
There are four words left over that do not belong to a set: BIT BLOOM HASH LOWEST. The enumeration below the grid (4 5, 6 3) tells solvers to interpret these leftovers as the instruction “HASH BLOOM, LOWEST BIT.” There are sixteen blooms and forty-three primes used in the hash functions, which is the dimensions of the grid shown below the checker on the web page. The hash function’s two arguments are named “row” and “column,” further reinforcing the idea that the rows of the grid are associated with the blooms, and the columns with the second argument of the hash function (which prime is used as a modulus).
Even though the sixteen blooms are not “allowed,” we can look at the individual results of hashing them using the 43 different primes, and (as suggested by the leftover words instruction) inspect the lowest (least-significant) bits of the result of evaluating the hash function. The rows are the sixteen blooms in alphabetical order (there is one beginning with each letter of the alphabet from A–P), and the columns are the forty-three prime indices in their given order. If we interpret a least significant bit value of 1 as a black pixel and a 0 as a white pixel, we would create the following 16 × 43 image:
This is clearly the Nike “Swoosh” symbol, so SWOOSH is the answer to this puzzle. (Solvers don’t actually need to create an image file/object; it should be clear just using ASCII art.)
Note that even though Bloom filters are probabilistic, this particular one is such that the chance of a false positive is somewhere south of one in a trillion, so it’s super unlikely that anything except the intended “allowed” words will turn up.
Using node.js, here’s how you can easily rip out the bloomfilter.js code from the web site to check a list of words. Install big-integer using npm, and download a list of words into the file /path/to/wordlist. Then run this code using node:
var bigInt = require('big-integer'); // Insert contents of bloomfilter.js here var filename = '/path/to/wordlist.txt'; var fs = require('fs'); var readline = require('readline'); var rd = readline.createInterface({ input: fs.createReadStream(filename), console: false }); rd.on('line', function(line) { if (checkWord(line)) console.log(line); });
And here is some extra code that you can add to the Javascript to produce the output (as ASCII art) once you have found all the blooms:
const blooms = [ 'ASTER', 'BUTTERCUP', 'CARNATION', 'DAISY', 'EDELWEISS', 'FREESIA', 'GERANIUM', 'HIBISCUS', 'IRIS', 'JASMINE', 'KINGCUP', 'LOTUS', 'MAGNOLIA', 'NARCISSUS', 'ORCHID', 'PRIMROSE' ]; for (var i = 0; i < blooms.length; i++) { var s = ''; for (var j = 0; j < primeTable.length; j++) s += (hash(blooms[i], j) & 1) ? 'XX' : ' '; console.log(s); }
Running this using node outputs:
XX XXXX XX XXXXXX XXXX XXXXXXXXXX XXXXXX XXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXX XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXX