Hello everyone, I am the Wolf at the End of the Desert.
The website has been rebuilt with Blazor and went online a day ago. Developing with Blazor is truly convenient. In my spare time, I consulted GPT and GitHub, and launched a Regular Expression Online Tester and several online mini-games, such as Tic-Tac-Toe and Minesweeper.
Below is a brief introduction. Let me know if you're interested or have any suggestions.
1. New Online Mini Tools
1.1. Regular Expression Online Tester
Online access: https://dotnet9.com/tools/regextester
This example demonstrates how to develop a simple regular expression online verification tool using Blazor Server. Users can input a regular expression and a test string, then click the "Test" button to verify if the regex matches the test string. Additionally, this example provides over a dozen commonly used regex patterns. Users can click a link to load test data, which automatically fills in the regex and test string.

Brief explanation of the annotations in the image:
- Common regular expressions: Click to automatically fill in the corresponding regex (annotation 2) and test text (annotation 3). Click [Test] (annotation 4) to verify.
- Regular expression: Enter the regex to be used.
- Test text area: Fill in the string to be validated/extracted here.
- [Test] button: Click to apply the regex above (annotation 2) and extract the content from the test text area (annotation 3). The match results are displayed below (annotation 5).
- Display matching results.
The code is only 123 lines and includes commonly used regular expressions, simple enough:
@page "/tools/regextester"
@using System.Text.RegularExpressions
<PageTitle>@_title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>
<h3>Common Regular Expression Tests</h3>
<p>
@foreach (var item in _regexPatterns)
{
<MButton Color="lime" Class="ma-2" OnClick='() => LoadTest(item.Pattern)'>@item.Name</MButton>
}
</p>
<div>
<MTextField Label="Regular Expression" Type="string" TValue="string" @bind-Value="_regexPattern"/>
</div>
<div>
<MTextarea BackgroundColor="grey lighten-2" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_testString"
Label="Test String" Rows="8" style="font-size:12px;" RowHeight="15" AutoGrow/>
</div>
<div>
<MButton Color="success" class="ma-2" OnClick="TestRegex">Test</MButton>
</div>
<div>
@if (string.IsNullOrEmpty(_regexPattern) || string.IsNullOrEmpty(_testString))
{
<p>Please enter a regex and test string, then click the "Test" button.</p>
}
else
{
<p>Match results: </p>
<ul>
@foreach (var match in _matches)
{
<li>@match</li>
}
</ul>
}
</div>
</MApp>
@code {
private const string? _title = "Toolbox - Regular Expression Online Tester";
private string? _regexPattern;
private string? _testString;
private string? _defaultString = @"Below are some test examples:
history: v1.0 Regex Tester went online
v1.1 2023-06-23 Just went online
1. As of now, the longest domain suffix is .cancerresearch
demo@qq.com
dotnet9-9@vip.qq.com
dotnet9-9@gmail.com
demo@live.com
127.0.0.1
http://dotnet9.com/
510112199901013592
https://dotnet9.com/
123456789012345
18628035382
13493532389
川AAA008
京B45698
14:22:19";
private readonly List<RegexItem> _regexPatterns = new()
{
new("Match Email", @"\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}"),
new("Match Chinese", @"[\u4e00-\u9fa5]+"),
new("Match Double-byte Characters (including Chinese)", @"[^\x00-\xff]+"),
new("Match Time (HH:mm:ss)", @"([01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d"),
new("Match IP (IPv4)", @"\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}"),
new("Match ID Card", @"\d{17}[0-9Xx]|\d{15}"),
new("Match Date (yyyy-MM-dd)", @"(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)"),
new("Match Positive Integer", @"[1-9]\d*"),
new("Match Negative Integer", @"-[1-9]\d*"),
new("Match Phone Number", @"(13\d|14[579]|15[^4\D]|17[^49\D]|18\d)\d{8}"),
new("Match License Plate", @"(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))")
};
private readonly List<string> _matches = new();
private void TestRegex()
{
if (string.IsNullOrWhiteSpace(_regexPattern) || string.IsNullOrWhiteSpace(_testString))
{
return;
}
try
{
var regex = new Regex(_regexPattern);
var match = regex.Match(_testString);
_matches.Clear();
while (match.Success)
{
_matches.Add(match.Value);
match = match.NextMatch();
}
}
catch
{
_matches.Clear();
}
}
private void LoadTest(string pattern)
{
_regexPattern = pattern;
_testString = _defaultString;
}
record RegexItem(string Name, string Pattern);
}
2. Online Mini Games Launched
Let me clarify first: The site owner launched these mini games solely to test the server load. If you develop games, it's recommended to use the client-side mode (WASM), because the former puts pressure on the server, while the latter puts pressure on the user's side.
2.1. Guess the Number Game
Online access: https://dotnet9.com/games/guessing-numbers

At the start of the game, a random target number between 1 and 100 is generated. Players need to guess the target number by inputting numbers. The system gives hints based on the player's guess. If the player guesses correctly, the game ends, a congratulatory message is displayed, and a button to start a new game appears.
This game is simple, with just a few dozen lines of code:
@page "/games/guessing-numbers"
<PageTitle>@_title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>
@if (_isGameOver)
{
<p>@_message</p>
<p>Game Over!</p>
<p>
<MButton Color="lime" Class="ma-2" OnClick='StartNewGame'>Start New Game</MButton>
</p>
}
else
{
<p>Guess a number between 1 and 100:</p>
<p>
<MTextField Label="Number" Type="string" TValue="int" @bind-Value="_guess"/>
</p>
<p>
<MButton Color="success" class="ma-2" OnClick="CheckGuess">Guess!</MButton>
</p>
<p>@_message</p>
}
</MApp>
@code {
readonly string? _title = "Guess the Number Game";
private int _targetNumber;
private int _guess;
private string? _message;
private bool _isGameOver;
protected override void OnInitialized()
{
StartNewGame();
}
private void StartNewGame()
{
var random = new Random();
_targetNumber = random.Next(1, 101);
_guess = 0;
_message = "";
_isGameOver = false;
}
private void CheckGuess()
{
if (_guess == _targetNumber)
{
_message = "Congratulations, you guessed it!";
_isGameOver = true;
}
else if (_guess < _targetNumber)
{
_message = "Too low!";
}
else
{
_message = "Too high!";
}
}
}
2.2. Tic-Tac-Toe Game
Online access: https://dotnet9.com/games/tictactoe

A simple Tic-Tac-Toe game. Players can click on squares on the board to make a move. The game checks if a player has won or if it's a draw, and displays the appropriate message when the game ends. Players can click the "Start New Game" button to restart.
Code: 117 lines.
@page "/games/tictactoe"
<PageTitle>@_title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>
@if (_isGameOver)
{
<p>@_message</p>
<p>Game Over!</p>
<MButton Color="lime" Class="ma-2" OnClick='StartNewGame'>Start New Game</MButton>
}
else
{
<div style="text-align: center;">
@for (var i = 0; i < 3; i++)
{
<div>
@for (var j = 0; j < 3; j++)
{
var i1 = i * 3 + j;
<MButton Color="lime" OnClick='() => MakeMove(i1)' Disabled='IsCellDisabled(i1)'>@_board[i1]</MButton>
}
</div>
}
</div>
<p>@_message</p>
}
</MApp>
@code {
readonly string? _title = "Tic-Tac-Toe Game";
private string?[] _board = new string[9];
private string _currentPlayer = "X";
private string? _message;
private bool _isGameOver;
private void MakeMove(int index)
{
if (_board[index] != null || _isGameOver)
{
return;
}
_board[index] = _currentPlayer;
if (CheckWin(_currentPlayer))
{
_message = $"Player {_currentPlayer} wins!";
_isGameOver = true;
}
else if (_board.All(cell => cell != null))
{
_message = "Draw!";
_isGameOver = true;
}
else
{
_currentPlayer = _currentPlayer == "X" ? "O" : "X";
if (_currentPlayer == "O")
{
MakeComputerMove();
}
}
}
private void MakeComputerMove()
{
// Simple random selection of an available square to make a move
var availableMoves = Enumerable.Range(0, 9).Where(i => _board[i] == null).ToList();
var random = new Random();
var randomIndex = random.Next(availableMoves.Count);
var computerMove = availableMoves[randomIndex];
_board[computerMove] = _currentPlayer;
if (CheckWin(_currentPlayer))
{
_message = $"Computer wins!";
_isGameOver = true;
}
else if (_board.All(cell => cell != null))
{
_message = "Draw!";
_isGameOver = true;
}
else
{
_currentPlayer = _currentPlayer == "X" ? "O" : "X";
}
}
private bool CheckWin(string player)
{
// Check all possible winning combinations
return (_board[0] == player && _board[1] == player && _board[2] == player) ||
(_board[3] == player && _board[4] == player && _board[5] == player) ||
(_board[6] == player && _board[7] == player && _board[8] == player) ||
(_board[0] == player && _board[3] == player && _board[6] == player) ||
(_board[1] == player && _board[4] == player && _board[7] == player) ||
(_board[2] == player && _board[5] == player && _board[8] == player) ||
(_board[0] == player && _board[4] == player && _board[8] == player) ||
(_board[2] == player && _board[4] == player && _board[6] == player);
}
private bool IsCellDisabled(int index)
{
return _isGameOver || _board[index] != null;
}
private void StartNewGame()
{
_board = new string[9];
_currentPlayer = "X";
_message = null;
_isGameOver = false;
}
}
2.3. Online Minesweeper Game
Online access: https://dotnet9.com/games/minesweeper

In this example, players click squares to reveal them. If a player steps on a mine, the game ends. If the revealed square has mines adjacent to it, the square displays a number indicating the count of surrounding mines. If the player successfully reveals all squares without mines, the game is won.
This game highly resembles the classic Windows version of Minesweeper. The code is more extensive and is adapted from the open-source project: https://github.com/jarDotNet/BlazorMinesweeper. If you're interested in the code, check out that project or read the Minesweeper-related code on the Dotnet9 website:

3. Final Words
Let me reiterate: The mini games on the site are only for testing. The Server mode is not recommended for developing game-like features; that should be left to the Client mode.
If you have any tool requirements, feel free to leave a comment. The site owner will consider adding them when time permits.
That's all for today. Wishing everyone a peaceful Dragon Boat Festival.
- Website: https://dotnet9.com/
- Source Code: https://github.com/dotnet9/Dotnet9
- .NET Version: .NET 8.0.0-preview.5.23280.8
- WeChat Technical Group: Add the site owner's WeChat (codewf), be sure to note "Join Group"
- QQ Technical Group: 771992300