Blazor开发小游戏?趁热打铁上!!!

大家好,我是沙漠尽头的狼。

网站使用Blazor重构上线一天了,用Blazor开发是真便捷,空闲时间查查gpt和github,又上线一个 正则表达式在线验证工具[1] 和几个在线小游戏,比如 井字棋游戏[2]扫雷[3] 等。

下面简单介绍一下,看大家有没有兴趣或建议。

1. 新增在线小工具

1.1. 正则表达式在线验证工具

这个示例演示了如何使用Blazor Server开发一个简单的正则表达式在线验证工具。用户可以输入正则表达式和测试字符串并单击“测试”按钮以测试正则表达式是否匹配测试字符串。此外,这个示例还提供了10几个常用的正则表达式测试,用户可以单击链接加载测试数据并自动填充正则表达式和测试字符串。

上图的标注简单说明:

  1. 常用正则表达式:点击自动在下方填充对应的正则表达式(标注2)、测试文本(标注3),点击【测试】(标注4)即可验证
  2. 正则表达式:填写需要使用的正则表达式
  3. 测试文本区域:将需要验证提取的字符串填写在这里
  4. 【测试】按钮:点击应用上面的正则表达式(标注2)并提取测试文本区域(标注3)内容,将匹配结果显示在下方(标注5)
  5. 显示匹配的结果

代码一共123行,里面有常用的正则表达式,简单吧:

代码语言:javascript
复制
@page "/tools/regextester"
@using System.Text.RegularExpressions

<PageTitle>@_title</PageTitle>

<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>

&lt;h3&gt;常用正则表达式测试&lt;/h3&gt;

&lt;p&gt;
    @foreach (var item in _regexPatterns)
    {
        &lt;MButton Color=&#34;lime&#34; Class=&#34;ma-2&#34; OnClick=&#39;() =&gt; LoadTest(item.Pattern)&#39;&gt;@item.Name&lt;/MButton&gt;
    }
&lt;/p&gt;

&lt;div&gt;
    &lt;MTextField Label=&#34;正则表达式&#34; Type=&#34;string&#34; TValue=&#34;string&#34; @bind-Value=&#34;_regexPattern&#34;/&gt;
&lt;/div&gt;

&lt;div&gt;
    &lt;MTextarea BackgroundColor=&#34;grey lighten-2&#34; Solo
               Color=&#34;orange orange-darken-4&#34; TValue=&#34;string&#34; @bind-Value=&#34;_testString&#34;
               Label=&#34;测试字符串&#34; Rows=&#34;8&#34; style=&#34;font-size:12px;&#34; RowHeight=&#34;15&#34; AutoGrow/&gt;
&lt;/div&gt;

&lt;div&gt;
    &lt;MButton Color=&#34;success&#34; class=&#34;ma-2&#34; OnClick=&#34;TestRegex&#34;&gt;测试&lt;/MButton&gt;
&lt;/div&gt;

&lt;div&gt;
    @if (string.IsNullOrEmpty(_regexPattern) || string.IsNullOrEmpty(_testString))
    {
        &lt;p&gt;请输入正则表达式和测试字符串并单击“测试”按钮。&lt;/p&gt;
    }
    else
    {
        &lt;p&gt;匹配结果: &lt;/p&gt;
        &lt;ul&gt;
            @foreach (var match in _matches)
            {
                &lt;li&gt;@match&lt;/li&gt;
            }
        &lt;/ul&gt;
    }
&lt;/div&gt;

</MApp>

@code {
private const string? _title = "工具箱-正则表达式在线验证工具";
private string? _regexPattern;
private string? _testString;

private string? _defaultString = @&#34;下面是一些测试实例:
history: v1.0 正则表达式测试工具上线
v1.1 2023-06-23 刚刚上线
1. 截至目前为止,最长域名后缀 .cancerresearch
demo@qq.com
dotnet9-9@vip.qq.com
dotnet9-9@gmail.com
demo@live.com
127.0.0.1
510112199901013592
123456789012345
18628035382
13493532389
川AAA008
京B45698
14:22:19&#34;;

private readonly List&lt;RegexItem&gt; _regexPatterns = new()
{
    new(&#34;匹配邮箱&#34;, @&#34;\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}&#34;),
    new(&#34;匹配中文&#34;, @&#34;[\u4e00-\u9fa5]+&#34;),
    new(&#34;匹配双字节字符(包含汉字)&#34;, @&#34;[^\x00-\xff]+&#34;),
    new(&#34;匹配时间(时:分:秒)&#34;, @&#34;([01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d&#34;),
    new(&#34;匹配IP(IPV4)&#34;, @&#34;\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}&#34;),
    new(&#34;匹配身份证&#34;, @&#34;\d{17}[0-9Xx]|\d{15}&#34;),
    new(&#34;匹配日期(年-月-日)&#34;, @&#34;(([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)&#34;),
    new(&#34;匹配正整数&#34;, @&#34;[1-9]\d*&#34;),
    new(&#34;匹配负整数&#34;, @&#34;-[1-9]\d*&#34;),
    new(&#34;匹配手机号&#34;, @&#34;(13\d|14[579]|15[^4\D]|17[^49\D]|18\d)\d{8}&#34;),
    new(&#34;匹配车牌号&#34;, @&#34;(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF] &#34;京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z&#34;)|([DF]([A-HJ-NP-Z0-9] &#34;DF&#34;)[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))&#34;)
};

private readonly List&lt;string&gt; _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. 上线在线小游戏

这里先说明,站长上线小游戏,只是为了测试网站服务器压力,如果开发小游戏,建议用客户端模式(wasm),毕竟前者压力在服务器,后者在用户那里。

2.1. 猜数字游戏

游戏开始时,会生成一个1到100之间的随机数字作为目标数字。玩家需要通过输入数字来猜测目标数字,系统会根据玩家的猜测给出相应的提示。如果玩家猜对了,游戏结束,显示恭喜信息,并提供开始新游戏的按钮。

这个游戏简单,代码几十行:

代码语言:javascript
复制
@page "/games/guessing-numbers"

<PageTitle>@_title</PageTitle>

<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>

@if (_isGameOver)
{
    &lt;p&gt;@_message&lt;/p&gt;
    &lt;p&gt;游戏结束!&lt;/p&gt;
    &lt;p&gt;
        &lt;MButton Color=&#34;lime&#34; Class=&#34;ma-2&#34; OnClick=&#39;StartNewGame&#39;&gt;开始新游戏&lt;/MButton&gt;
    &lt;/p&gt;
}
else
{
    &lt;p&gt;猜一个1到100之间的数字:&lt;/p&gt;
    &lt;p&gt;
        &lt;MTextField Label=&#34;数字&#34; Type=&#34;string&#34; TValue=&#34;int&#34; @bind-Value=&#34;_guess&#34;/&gt;
    &lt;/p&gt;
    &lt;p&gt;
        &lt;MButton Color=&#34;success&#34; class=&#34;ma-2&#34; OnClick=&#34;CheckGuess&#34;&gt;猜!&lt;/MButton&gt;
    &lt;/p&gt;
    &lt;p&gt;@_message&lt;/p&gt;
}

</MApp>

@code {
readonly string? _title = "猜数字游戏";
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 = &#34;&#34;;
    _isGameOver = false;
}

private void CheckGuess()
{
    if (_guess == _targetNumber)
    {
        _message = &#34;恭喜你猜对了!&#34;;
        _isGameOver = true;
    }
    else if (_guess &lt; _targetNumber)
    {
        _message = &#34;猜小了!&#34;;
    }
    else
    {
        _message = &#34;猜大了!&#34;;
    }
}

}

2.2. 井字棋游戏

一个简单的井字棋游戏,玩家可以点击棋盘上的方格来下棋。游戏会检查是否有玩家获胜或者平局,并在游戏结束时显示相应的消息。玩家可以点击“开始新游戏”按钮来重新开始游戏。

代码117行:

代码语言:javascript
复制
@page "/games/tictactoe"

<PageTitle>@_title</PageTitle>

<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>

@if (_isGameOver)
{
    &lt;p&gt;@_message&lt;/p&gt;
    &lt;p&gt;游戏结束!&lt;/p&gt;
    &lt;MButton Color=&#34;lime&#34; Class=&#34;ma-2&#34; OnClick=&#39;StartNewGame&#39;&gt;开始新游戏&lt;/MButton&gt;
}
else
{
    &lt;div style=&#34;text-align: center;&#34;&gt;
        @for (var i = 0; i &lt; 3; i++)
        {
            &lt;div&gt;
                @for (var j = 0; j &lt; 3; j++)
                {
                    var i1 = i * 3 + j;
                    &lt;MButton Color=&#34;lime&#34; OnClick=&#39;() =&gt; MakeMove(i1)&#39; Disabled=&#39;IsCellDisabled(i1)&#39;&gt;@_board[i1]&lt;/MButton&gt;
                }
            &lt;/div&gt;
        }
    &lt;/div&gt;
    &lt;p&gt;@_message&lt;/p&gt;
}

</MApp>

@code {
readonly string? _title = "井字棋游戏";
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 = $&#34;玩家 {_currentPlayer} 获胜!&#34;;
        _isGameOver = true;
    }
    else if (_board.All(cell =&gt; cell != null))
    {
        _message = &#34;平局!&#34;;
        _isGameOver = true;
    }
    else
    {
        _currentPlayer = _currentPlayer == &#34;X&#34; ? &#34;O&#34; : &#34;X&#34;;
        if (_currentPlayer == &#34;O&#34;)
        {
            MakeComputerMove();
        }
    }
}

private void MakeComputerMove()
{
// 简单的随机选择一个可用的方格来下棋
    var availableMoves = Enumerable.Range(0, 9).Where(i =&gt; _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 = $&#34;电脑获胜!&#34;;
        _isGameOver = true;
    }
    else if (_board.All(cell =&gt; cell != null))
    {
        _message = &#34;平局!&#34;;
        _isGameOver = true;
    }
    else
    {
        _currentPlayer = _currentPlayer == &#34;X&#34; ? &#34;O&#34; : &#34;X&#34;;
    }
}

private bool CheckWin(string player)
{
// 检查所有可能的获胜组合
    return (_board[0] == player &amp;&amp; _board[1] == player &amp;&amp; _board[2] == player) ||
           (_board[3] == player &amp;&amp; _board[4] == player &amp;&amp; _board[5] == player) ||
           (_board[6] == player &amp;&amp; _board[7] == player &amp;&amp; _board[8] == player) ||
           (_board[0] == player &amp;&amp; _board[3] == player &amp;&amp; _board[6] == player) ||
           (_board[1] == player &amp;&amp; _board[4] == player &amp;&amp; _board[7] == player) ||
           (_board[2] == player &amp;&amp; _board[5] == player &amp;&amp; _board[8] == player) ||
           (_board[0] == player &amp;&amp; _board[4] == player &amp;&amp; _board[8] == player) ||
           (_board[2] == player &amp;&amp; _board[4] == player &amp;&amp; _board[6] == player);
}

private bool IsCellDisabled(int index)
{
    return _isGameOver || _board[index] != null;
}

private void StartNewGame()
{
    _board = new string[9];
    _currentPlayer = &#34;X&#34;;
    _message = null;
    _isGameOver = false;
}

}

2.3. 在线扫雷游戏

在这个示例中,玩家需要点击方格来揭开它们。如果玩家踩到地雷,游戏结束。如果玩家揭开的方格周围有地雷,方格上会显示相应的数字,表示周围的地雷数量。如果玩家成功揭开所有没有地雷的方格,游戏胜利。

此游戏高度还原早期Window版本扫雷,代码较多,抄自开源项目:https://github.com/jarDotNet/BlazorMinesweeper, 如果对代码感兴趣可查看该开源项目,或阅读 Dotnet9网站[4] 关于扫雷部分代码:

3. 最后的话

再说一次哦,网站的小游戏只是为了测试,Server模式不建议开发游戏类功能,这个交给Client模式吧。