Blazor lets you build interactive web UIs using C# instead of JavaScript. Blazor apps are composed of reusable web UI components implemented using C#, HTML, and CSS.” The application can be run directly in the browser as a WebAssembly. It is sufficient to just host the application. This is very easy to do, for example, with static websites on Azure Storage Accounts.

The Problem or What Is Wordle

In the Wordle game, a 5-letter word is searched every day. To guess it, 6 attempts are available. After each attempt, the color of the letters reveals whether the letter in the word you are looking for occurs in the exact place (green) or whether it occurs in a different place (yellow) or is not contained in the solution word (grey).

How to use

This application should help to find the word you are looking for. For this purpose, a dictionary with approx. 5700 English words is loaded to which various filters can be applied in order to obtain possible matching words.

  1. All letters not yet used should be entered in the Possible Characters (1) field. The first filter step ensures that only words with these letters remain and are used further.
    The word list will be filtered with the regular expression in Line 74, which means that 5 times one of the specified letters must be included in the word.
  2. You should use the green and yellow letters in the Must Characters (2) filed. This reduces the word list to all words that contain at least all of these letters.
    This is also done with a regular expression. The special feature here is that the letters must not appear in a fixed order. Therefore we need to work with lookahead assertion (?=). For example, if the letters A and B can to appear in any order, the regular expression must look like (?=.A)(?=.B).+. The search pattern for this step is build in the line 82-85.
  3. In the last filter step, you can define your own regular expression. This is useful for forcing letters at certain positions or excluding them from certain positions. If you have a green letter, you should write the letter at the correct position (e.g. if you have an E at second position, you can write .E...). If you have a yellow letter, it is at the wrong spot but the word contains it at least once and you should write a “not” at the position in regex (e.g. if an A is not correct at the third position, you can write ..[^A]..).
    This expression will directly run against the current word list (line 94).
  4. After the Search button has been clicked, details of the filter process can be checked in the output under (4). The actual results appear at the bottom of the page.

If you need some background of regular expression (e.g. ^, $, {5}), take a look on this cheat sheet.

How does it work

This is the code for the filter steps with the regular expressions:

var results = String.IsNullOrEmpty(PossibleCharacters)||PossibleCharacters.Equals("*") ? 
				allWords : 
				allWords.FindAll((string s) => Regex.IsMatch(s, "^["+PossibleCharacters+"]{5}$"));
//Console.WriteLine("possChar: " + results.Count);
await SetStatusMsg(String.Format("✔ ({0})", results.Count()), true);
if(!String.IsNullOrEmpty(MustCharacters)){
	await SetStatusMsg("words with must character...", false);
	MustCharacters = MustCharacters.ToUpperInvariant();
	string searchPattern = "";
	//(?=.*A)(?=.*B)(?=.*C).+
	foreach(char c in MustCharacters){
		searchPattern += "(?=.*"+c+")";
	}
	searchPattern += ".+";
	Console.WriteLine("mustChar SearchPattern: " + searchPattern);
	results = results.FindAll((string s) => Regex.IsMatch(s, searchPattern));
	//Console.WriteLine("mustChar: " + results.Count);
	await SetStatusMsg(String.Format("✔ ({0})", results.Count()), true);
}
if(!String.IsNullOrEmpty(RegEx)){
	await SetStatusMsg("words with regex...", false);
	RegEx = RegEx.ToUpperInvariant();
	results = results.FindAll((string s) => Regex.IsMatch(s, RegEx));
	//Console.WriteLine("RegEx: " + results.Count);
	await SetStatusMsg(String.Format("✔ ({0})", results.Count()), true);
}

A few steps are necessary to carry out the asynchronous output during the calculation. First, the call must be done with await to a method marked as async. After the data update has taken place, an update of the surface must be forced with StateHasChanged(). In some cases I needed a delay (await Task.Delay(100)) to make the update visible.

private async Task<bool> SetStatusMsg(string info, bool newline){
	StatusMsg = new MarkupString(StatusMsg.ToString() + info);
	if(newline)
		//StatusMsg += Environment.NewLine;
		StatusMsg = new MarkupString(StatusMsg.ToString() + "<br>");
	this.StateHasChanged();
	await Task.Delay(100);
	return true;
}

How to Build

It is a simple .NET application, therefore:

dotnet build
dotnet watch run

does the trick. The watch option updates the application every time a file change.

How to deploy

The first step is to generate the final output. This ist done with dotnet publish. Now copy the output of the publish folder to the $web container of the Azure blob storage. You can use the script ./copytostorage.sh to perform the copy task with AzCopy. You need to set the credentials and the connection to the Azure Storage account first in the script:

TARGET='https://<YOURSTORAGE ACCOUNT>.blob.core.windows.net/$web'
SAS='?sv=2020-08-04...'

Useful Links

You can see the Wordle Solver in action at: https://wordle.zuehlke.cloud/

You can find the sourcecode in the wordle-solver github repo.