Create your Wordle like game with Blazor and deploy to GitHub Pages

Ferry To
7 min readFeb 26, 2022

--

Photo by Sincerely Media on Unsplash

Welcome to my Everything in C# series. Wordle is a recently famous word guessing game like Mastermind where each guess return whether each letter is in the right position or just contained in the answer. This time we are going to implement a similar version with Microsoft Blazor technology. I have put my game on GitHub pages. You can take a look and play if interested.

https://muddle.ferrywl.to

What is Blazor?

Blazor is a technology that can run C# code on browser using WebAssembly. In past .NET developers relies on Razor pages for front-end development. Now we can use Blazor to create SPA as if we are using other framework like React/Vue/Angular.

For more information you can check this link: https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blazor

Getting Started

If you do not have .NET SDK installed please follow the steps here: https://dotnet.microsoft.com/en-us/learn/aspnet/blazor-tutorial/install

We are creating a pure client side game with Blazor WASM mode. Once finished you can deploy your game to static web hosting service (e.g. GitHub Pages) and let people play around.

  1. Create your project directory.

2. Open your command prompt / Terminal and change to your project directory. Execute dotnet new blazorwasm . Your project folder should look like this.

structure of new create blazor wasm project

3. Execute dotnet run to check if it works.

When everything works fine. Let’s start to build our game.

Game Logic in C#

1. We need a way to load the answers, thus we have the following class:

2. Then we need to add this into service container. Open Program.cs , look for lines builder.Services.xxxx and insert the following code:

builder.Services.AddSingleton(
sp => {
var httpClient = sp.GetRequiredService<HttpClient>();
const string filePath = "word-list.txt";
return new AnswerProvider(httpClient, filePath);
});

Your Program.cs file should look like this:

The code here tells Blazor to return the same object (Singleton) when requested by Pages/Components and config the AnswerProvider that word-list.txt is the source of answers file.

3. Now it comes to the game logic, they are pretty straight forward. The Guess class responsible to do the matching of each guess and return result of that guess. The Game class control the game state, determine whether the user is win or lose. Note how we provide an event to update code that are interested in knowing the game state has changed.

4. Finally we also need to take care of player input, so we have the GameInput class. This class is responsible for manipulating the buffer of player’s input and flush out the buffer for Game and Guess to consume.

5. Do not forget to config our service container for Game and GameInput . We will need them in our UI. In Program.cs add the following lines:

builder.Services.AddSingleton<Game>();
builder.Services.AddSingleton<GameInput>();

The complete Program.cs should look like this:

That’s all for the game logic. Quite simple isn’t it? 😎

The Game UI with Blazor

  1. Clean up project and removing unused code.

Return to our project structure:

project structure

Since we only care about the game, most of the generated files in default project setup are not needed.

For Pages , keep only Index.razor

For Shared, keep only MainLayout.razor and MainLayout.razor.css

For wwwroot , remove sample-data

Open MainLayout.cs and remove everything and leave only these lines:

<div class="page">
<main>@Body</main>
</div>

because we don’t need a side bar in our project.

2. Build player input UI

Create Input folder under Pages directory. Then In Input folder create new files KeyboardButton.razor and KeyboardButton.razor.css :

In Blazor, you can add CSS style to app.css to make a style globally available. If you create a CSS file named after a component (e.g. component.razor.css ), the styles defined in the file will available to that component only (scoped). We call this CSS isolation.

Remember we did configured the service container to return the same Game object when requested? The first line @inject Game _game tells Blazor that when creating this component, inject an instance of Game so we can access the properties and methods of it.

In Blazor when we annotated a property with [Parameter] attribute, then this parameter can be set when other component contains this component. For example, assuming there is another component and it contains a KeyboardButton then you can set the parameters like this:

<KeyboardButton Text="A" OnClick="@(_ => Console.WriteLine(key))"/>

You can also reference code in markup by prepending @ .

There are 2 points in Keyboard.razor worth we to look at.

  1. You can reference an HTML element in Blazor code via creating a variable of type ElementReference and use @ref attribute to map the HTML element to the said variable.
  2. By setting focus to the container div tag after component finished rendering and set the focus back to the container whenever focus is lost, we can ensure to catch all player keypress event.

Now we have a player input UI as below:

3. Build the game display

There are two types of display needed, one for showing what player inputted; One for showing the guess results. Note how we can change the CSS style at run-time.

The letter box should look like this:

sample letter box

4. Stitch things together.

Now we return to Index.razor and edit it like below:

Things we can learn here:

  1. We use @page "/" here to route this page as default page.
  2. How we listen to Game and GameInput update event.
  3. How we load word-list.txt and set answer of current game on page initialised in OnInitializedAsync() method.
  4. When we want Blazor to re-render the screen, we can call the method StateHasChanged()
  5. To avoid memory leak, it is a best practice to remove the event listener when we unload/close the page. We can do this by implementing IDisposable interface and put the cleanup code inside Dispose() method.

Finally, we edit app.css to add shared styles used in our game. Append these style at the bottom of app.css :

Note: Remember to create your own word-list.txt and copy to wwwroot folder.

Now open your terminal/command prompt and run dotnet run to play your game. :)

sample game result

Publish Your Game

When you are ready, open your terminal/command prompt and run dotnet publish -c Release . You can find your project files at /bin/Release/net6.0/publish/wwwroot

published content of your project

If you have a GitHub account, you can create a new repository and then go to Settings page. Click Pages on the left menu and you can now choose which branch to publish. We use the default setting this time, click Save to finish.

Now clone the repository and then copy all files in publish/wwwroot folder to your repository root directory. Commit the changes and push to GitHub.

Congratulations! You can now play your game at:

https://your-github-username.github.io/your-repository-name

Challenge Yourself

To test about the knowledge you gained in this project, try to add a button in Index.razor . Display only if game is ended. When clicked the reset with a new answer.

Summary

You have just created your own Wordle like game using C# and Blazor. Now you can deployed your game to static web host and invite your friends to get it a try.

If you watch the code carefully, the game logic and UI supports:

  • Variable length answer. You can even contains words of different length in your answer file. It will just work for longer/shorter word.
  • You can also set how many attempts a player allowed to guess to increase/decrease difficulty.
  • Start a new game upon player win/lose by clicking on the restart button. Theres no limit of game allowed per day.
  • Of course you can style the game with your own taste! 🌈

Features of original Wordle that we didn’t implemented (not highly related to Blazor):

  • User progress tracking.
  • Share result to social network. (Those 🟪 🟩 squares. )

The full source code can be found on my GitHub repo, which used Mudblazor UI component library instead of bootstrap. Have fun and stay tuned for the next fun project of my #EverythingInCSharp series! 😉

--

--

Ferry To
Ferry To

Written by Ferry To

A tech Geek in Hong Kong. ex-Founder my own company. Staff Engineer of a startup. Trying to publish at least one article per month.