Go Ahead And Cheat! You Know You Want To!

This is a quick .NET project to solve the Wordle puzzle in minutes, not days! It was created to learn a little more C#, and play around with .NET controls. This Form1 is the epitome of lazy, because cheaters are lazy.

Introduction

We’ve all been there. Slaving over the daily Wordle puzzle, brain a-mush, thinking, “Why won’t they let me out of here, so I can go make more friends and better my life? But no, the karma masters are a harsh lot, insisting you exert youself until your little grey cells can take no more.

Well, Form1 is here to help! With this Wordle solver you can break the chains of your oppression, and get to bed earlier tonight!

Image 1

To use:

Download wordleSolver.zip

The attached project has a debug and release executable in it. Just double-click whichever one you prefer. It will appear with an OpenDialogBox, prompting you for the location of the words.txt dictionary file. Download it from https://github.com/dwyl/english-words, point the dialog box to it, and wait a couple seconds for the words to load. For some reason the form sometimes appears behind other windows, but cheaters are lazy, and I can’t be bothered to fix that, so you may have to go digging.

Once that appears, as you are playing Wordle enter your letters in the Form1 solver, and it will eliminate any words from the dictionary that don’t meet your criteria.

Again, cheaters are lazy, and being one, I didn’t label the five boxes which specify matched letters. But cheaters are also smart, and since you are reading this you must also be a member of the club. So I have faith you will figure it out!

I have added two columns for convenience. One is the sum of the letter frequencies found in each word. Those are from the Dictionary Letter Frequency column at https://en.wikipedia.org/wiki/Letter_frequency. You can use it to try to knock off highly-used letter words first if you so desire. The third column just gives a quick way to see the number of unique letters in each word.

Sorting on these columns is possible, but does take a couple seconds in some cases. Especially if you reverse a previously sorted column. Evidently datagridview uses bubble sort behind the scenes.

Behind the Scenes

This is just a very simple entry eliminator program, but for simplicity it is built as a list builder. Any time a text box changes, corresponding text strings are changed and the program iterates over all the five letter words in the dictionary to see if they match all of the criteria that has been entered in the boxes. So Lists are continually created and destroyed. There are probably more optimal solutions possible. Don’t care – too lazy to optimize further!

If you want, you can hard-code the words.txt file location. That would save more time for the lazier of us. An example is commented out in the code.

Here is a dump of the main part of the code. It is pretty simple. Enjoy!

namespace wordleSolver {
   public partial class Form1 : Form {
      public List<string> allWords = new List<string>();
      public List<string> allFiveLetterWords = new List<string>();

      string nonCharacters = "";
      string hasCharacters = "";
      string p1Char = "";
      string p2Char = "";
      string p3Char = "";
      string p4Char = "";
      string p5Char = "";

      public Form1() 
         InitializeComponent();
         

      private void Form1_Load(object sender, EventArgs e) 
         var path = string.Empty;
         using (OpenFileDialog openFileDialog = new OpenFileDialog()) 
            openFileDialog.InitialDirectory = "";
            openFileDialog.Filter = "txt files (*.txt)
      
         
         System.IO.StreamReader sr = new System.IO.StreamReader(path);

         while (!sr.EndOfStream) 
            string str = sr.ReadLine();
            allWords.Add(str.ToLower());
            
         sr.Close();

         foreach (string str in allWords) 
            if (str.Length == 5) allFiveLetterWords.Add(str);
            

         dataGridView.ColumnCount = 3;
         foreach (string str in allFiveLetterWords) 
            int val = getVal(str);
            int numChars = getChars(str);
            dataGridView.Rows.Add(str, val, numChars);
            
         dataGridView.Sort(this.dataGridView.Columns[1], ListSortDirection.Descending);
         

      private int getChars(string str) 
         int count = 1;
         bool isDifferent = true;
         for (int curPos = 1; curPos < 5; ++curPos) 
            for (int x=0; x<curPos; ++x) 
               if (str[x] == str[curPos]) isDifferent = false;
               
            if (isDifferent) ++count;
            
         return count;
         

      int getVal(string str) 
         
         int total = 0;
         for (int i=0; i<5; ++i) 
            switch (str[i]) 
               case 'a': case 'A': total += 780; break;
               case 'b': case 'B': total += 200; break;
               case 'c': case 'C': total += 400; break;
               case 'd': case 'D': total += 380; break;
               case 'e': case 'E': total += 1100; break;
               case 'f': case 'F': total += 140; break;
               case 'g': case 'G': total += 300; break;
               case 'h': case 'H': total += 230; break;
               case 'i': case 'I': total += 860; break;
               case 'j': case 'J': total += 21; break;
               case 'k': case 'K': total += 97; break;
               case 'l': case 'L': total += 530; break;
               case 'm': case 'M': total += 270; break;
               case 'n': case 'N': total += 720; break;
               case 'o': case 'O': total += 610; break;
               case 'p': case 'P': total += 280; break;
               case 'q': case 'Q': total += 19; break;
               case 'r': case 'R': total += 730; break;
               case 's': case 'S': total += 870; break;
               case 't': case 'T': total += 670; break;
               case 'u': case 'U': total += 330; break;
               case 'v': case 'V': total += 100; break;
               case 'w': case 'W': total += 91; break;
               case 'x': case 'X': total += 27; break;
               case 'y': case 'Y': total += 160; break;
               case 'z': case 'Z': total += 44; break;
               
            
         return total;
         

         private void possibilitiesTextBox_TextChanged(object sender, EventArgs e) 
            hasCharacters = possibilitiesTextBox.Text;
            whittleDownPossibilities();
            

         private void whittleDownPossibilities() {
            dataGridView.Rows.Clear();
            dataGridView.Update();
            dataGridView.Refresh();

            
            List<string> currentPossibilities = new List<string>();

            foreach (string str in allFiveLetterWords) 
               bool isPossibility = true;
               for (int i=0; i<nonCharacters.Length; i++) 
                  for (int j=0; j<5; ++j) 
                     if (nonCharacters[i] == str[j]) 
                        isPossibility = false;
                        goto breakoutNonPossible;
                        
                     
                  
            breakoutNonPossible:
               if (isPossibility) currentPossibilities.Add(str);
               

            
            List<string> reducedPossibilities = new List<string>();

            foreach (string str in currentPossibilities) 
               bool isPossibility = true;
               for (int i=0; i<hasCharacters.Length; i++) 
                  bool hasCurrentCharacter = false;
                  for (int j=0; j<5; j++) 
                     if (hasCharacters[i] == str[j]) 
                        hasCurrentCharacter = true;
                        
                     
                  if (!hasCurrentCharacter) 
                     isPossibility = false;
                     goto breakoutPossibilities;
                     
                  
               breakoutPossibilities:
                  if (isPossibility) reducedPossibilities.Add(str);
               

            currentPossibilities.Clear();
            foreach (string str in reducedPossibilities) 
               bool isPossibility = true;
               if (p1Char != "" && p1Char[0]!=str[0]) isPossibility = false;
               if (p2Char != "" && p2Char[0]!=str[1]) isPossibility = false;
               if (p3Char != "" && p3Char[0]!=str[2]) isPossibility = false;
               if (p4Char != "" && p4Char[0]!=str[3]) isPossibility = false;
               if (p5Char != "" && p5Char[0]!=str[4]) isPossibility = false;
               if (isPossibility) currentPossibilities.Add(str);
               

            foreach (string str in currentPossibilities) 
               int val = getVal(str);
               int numChars = getChars(str);
               dataGridView.Rows.Add(str, val, numChars);
               
            dataGridView.Sort(this.dataGridView.Columns[1], ListSortDirection.Descending);
            }

      private void nonCharTextBox_TextChanged(object sender, EventArgs e) 
         nonCharacters = nonCharTextBox.Text;
         whittleDownPossibilities();
         

      private void p1TextBox_TextChanged(object sender, EventArgs e) 
         p1Char = p1TextBox.Text;
         whittleDownPossibilities();
         

      private void p2TextBox_TextChanged(object sender, EventArgs e) 
         p2Char = p2TextBox.Text;
         whittleDownPossibilities();
         

      private void p3TextBox_TextChanged(object sender, EventArgs e) 
         p3Char = p3TextBox.Text;
         whittleDownPossibilities();
         

      private void p4TextBox_TextChanged(object sender, EventArgs e) 
         p4Char = p4TextBox.Text;
         whittleDownPossibilities();
         

      private void p5TextBox_TextChanged(object sender, EventArgs e) 
         p5Char = p5TextBox.Text;
         whittleDownPossibilities();
         
   }
}

What I Learned

C# uses Lists instead of vectors. Operator = for a List changes the address of the List instead of making the values of one List match another (1). C# does not have a direct equivalent of C++’s multimap unless you import something. The directions on that aren’t clear, so newbies like me can get a little turned off by the effort. I gave up, and used a datagridview to solve the problem. It was more flexible in the end, but I suspect the sorting speed would be vastly improved using C++’s multimap.

What is left not to do

Cheaters are lazy. This is Form1. Good enough. Need an icon? Default is your friend!

History

Being lazy. Well, maybe not so much. Got other things to do! Enjoy the respite from the karma masters! Go out, see the world! Smile at a baby’s laughter!