alexandres / magicwordschallenge

The challenge: find the smallest set of (magic) words which always solve Wordle!
2 stars 0 forks source link

6-word solution? #2

Closed Armavica closed 2 years ago

Armavica commented 2 years ago

I found these 6 "words": COMBO FATTY GRRRL SPUDS VENGE WHILK (all in words_full.txt) which are a solution according to my simulator. However, your check.cpp does not agree. But if print the contents of possible_words at line 246, I get QUITE and QUIET, which should be distinguished given the 6 words above (by FATTY and by VENGE). Is there something that I am doing wrong?

alexandres commented 2 years ago

Your solution looks right to me! That is amazing news. 🙌 🙌 🙌

I believe the issue is in the simulator I used.

The issue is caused by:

COMBO FATTY GRRRL SPUDS VENGE WHILK
Error: multiple possible words for hidden word QUIET
QUIET
QUITE

I ran a quick test:

auto guess = FiveLetterWord("VENGE");
auto hidden = FiveLetterWord("QUIET");
auto conflict = FiveLetterWord("QUITE");
auto hint = evaluate_guess(guess, hidden);
std::cerr << "Hint: " << hint.to_squares() << std::endl;
auto is_possible = IsWordPossible(hint, guess, conflict);
std::cerr << "Is possible: " << is_possible << std::endl;

Outputs

Hint: xYxxx
Is possible: 1

Does your simulator return the same hint? The hint seems to correctly eliminate QUITE since there's an x at the last position, so the bug must be in the IsWordPossible function.

Armavica commented 2 years ago

Yes, I have the same hint when I compare the guess VENGE to the hidden word QUIET: 01000.

alexandres commented 2 years ago

Can you share your IsWordPossible code here to replace https://github.com/alexandres/magicwordschallenge/blob/main/check.cpp#L134 ?

Armavica commented 2 years ago

I don't really have this function in my code, but wouldn't it simpler to compare hint and evaluate_guess(guess, word)? Or am I missing something?

alexandres commented 2 years ago

In your code, how you eliminate candidate hidden words given a guess and its feedback?

Armavica commented 2 years ago

I don't eliminate words, I just check that all the feedbacks are different, for example (simplified code):

guesses = ['COMBO', 'FATTY', 'GRRRL', 'SPUDS', 'VENGE', 'WHILK']
feedbacks = [[compare(guess, hidden) for guess in guesses] for hidden in hidden_words]
# now I can check that all the lines of `feedbacks` are different
nb_collisions = len(feedbacks) - len(set(feedbacks))
# if `nb_collisions == 0`, then `guesses` is a solution
alexandres commented 2 years ago

I think I understand. You have a function that given a set of guesses and a hidden word, returns a unique set of feedbacks. You require that this mapping be one-to-one.

To infer a hidden word, you collect feedbacks using the fixed set of guesses and use the mapping to find the associated hidden word.

I love it!

On Sat, 5 Mar 2022 at 16:29 Virgile Andreani @.***> wrote:

I don't eliminate words, I just check that all the feedbacks are different, for example (simplified code):

guesses = ['COMBO', 'FATTY', 'GRRRL', 'SPUDS', 'VENGE', 'WHILK']feedbacks = [[compare(guess, hidden) for guess in guesses] for hidden in hidden_words]# now I can check that all the lines of feedbacks are differentnb_collisions = len(feedbacks) - len(set(feedbacks))# if nb_collisions == 0, then guesses is a solution

— Reply to this email directly, view it on GitHub https://github.com/alexandres/magicwordschallenge/issues/2#issuecomment-1059819735, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABDK22G3UXS4CJBIGPCUQTU6OY3DANCNFSM5P7LKOKA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

Armavica commented 2 years ago

Yes, checking that N guesses are an offline solution is equivalent to checking that every feedback given by the hidden words is unique (if you combine the N feedbacks), so that it is possible to distinguish every hidden word.

alexandres commented 2 years ago

Awesome. I will correct the check program usinf your idea and update the README to show that 6 word solution exists. Congratulations! 💪🏻💪🏻

What seemed impossible might just be possible.

On Sat, 5 Mar 2022 at 17:09 Virgile Andreani @.***> wrote:

Yes, checking that N guesses are an offline solution is equivalent to checking that all of the feedbacks given by the hidden words are unique (if you combine the N feedbacks), so that it is possible to distinguish every hidden word.

— Reply to this email directly, view it on GitHub https://github.com/alexandres/magicwordschallenge/issues/2#issuecomment-1059824684, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABDK25ZDO4BZJF7C5MXORDU6O5OVANCNFSM5P7LKOKA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

Armavica commented 2 years ago

Great :) Looking for 5 now :)

alexandres commented 2 years ago

Updated code and README with your algorithm and solution! :)

xanthe-cat commented 2 years ago

Hello Alexandre and Virgile,

I’m the creator of a (notorious?) Wordle knock-off that uses a slightly larger hidden wordlist than the 2,315 pre-NYT Wordle: it uses 2,686 words in total, including about 190 words that Josh Wardle initially had included in the game as of last October, and subsequently chose to remove.

This should make it more difficult to find sets of magic words: for example, none of the 8, 7, or 6 word solutions in the README.md satisfy the check program when run against the 2,686 wordlist (they have 1, 2, and 10 conflicts respectively). However, in doing somewhere between a dozen and two dozen runs of the 8-word version of magicwords, I found 7 different 8 word solutions for the larger set, so I continued running it until I obtained an 8th. Here they are:

8: ADDER BURAN CAHOW FELLA KNOSP MATTE RITZY VLOGS 8: AHULL ATTAR CHINK FAZES MERGE NODDY PROVE UPBOW 8: APPEL CRWTH DAZED DEFOG MURKY SNIBS TABLE VEGAS 8: ARGON CWTCH DAZED FLYPE JUNKS MELBA RORAL VIOLD 8: CAROB FELLY MIDDY PLOTS SAVER THUNK WIMPS ZIGAN 8: CROON DRUID FUSEL MAWKY PLEBE RIDGY SHAVE TARPS 8: CAMAN DEWED FOOTS PIRNS SNABS THILK VOUGE XYLYL 8: CURLI DOWDS GLOBE MUTCH PAVAN REFEL SPIKS TANGY

Each of these satisfies both the 2,686 wordlist and the 2,315 Wordle wordlist – which is as you would expect to always be the case, when one list is a strict subset of the other, as here. Since it is hardly impossible that the NYT might change the wordlist at any time, it’s not out of the question that the current best magic words discovered might be invalidated by a subsequent version of the game, while magic words discovered training on a larger set of hidden words might be more resilient to such a change.

Anyway, I’ve gotten fairly close to a 7-word solution for the 2,686 word set a couple of times after running magicwords for several days. I’ve noticed it’s fairly uncommon for a search to improve dramatically the more iterations that have been gone through – usually the current solution will converge quickly towards a low number of conflicts within the first 10,000 to 20,000 iterations, but it won’t improve greatly beyond that point. One search only got down to 3 conflicts after 700,000 iterations, while a different search reduced to just 2 conflict after 1,100 iterations, and then stubbornly sat there for 250,000 more iterations. Et cetera.

The most promising 7-word set I’ve discovered converged down to a single conflict fairly rapidly: 7: CADDY FLOOR MUNGE PLANK SWEEP TILTH VERBS (1 conflict)

There are numerous alternative sets I can find shuffling letters around from one word to another without reducing the number of conflicts by that last number, e.g.: 7: CADDY FREER MUNGE PLANK SWOOP TILTH VERBS (also 1 conflict) 7: CHEER FLANK MUNGE PADDY SWOOP TILTH VERBS (1) 7: CHEER FLANK MUNGE SPOOL TILTH VERBS WADDY (1) 7: CLANK FLEER MUNGE SPOOL TILTH VERBS WADDY (1) 7: CREEL FADDY MUNGE PLANK SWOOP TILTH VERBS (1)

I’m wondering, since magicwords obviously begins somewhat randomly and then looks to refine the current set of words, whether it instead could be directed to investigate one or more candidate words?

I also found it useful to slightly modify the check.cpp code to make the output a little more verbose and to print out the number of conflicts, which only needed an additional line and changes to the lines above and below.

        auto is_solution = conflicts(solution);
        auto text = is_solution == 0 ? "These magic words solve Wordle, conflicts = " : "These words do not solve Wordle, conflicts = ";
        std::cerr << text << is_solution << std::endl;
alexandres commented 2 years ago

Hi @xanthe-cat ! Sorry for the late reply. magicwords.cpp implements a very basic genetic algorithm. Your proposed "could be directed to investigate one or more candidate words" solution sounds like simmulated annealing or hill climbing. Trying both on this problem could be a fun exercise. You can also try reaching out to @Armavica to see if he'll share his code with you.

Good luck!