使用Blazor和GitHub Copilot开发五子棋游戏

发布时间:2026/11/2 14:36:40
使用Blazor和GitHub Copilot开发五子棋游戏

1. 项目背景与工具准备

五子棋作为经典策略游戏,一直是编程练手的绝佳选择。而Blazor作为微软推出的Web全栈框架,允许开发者使用C#构建交互式Web应用,彻底告别JavaScript的割裂感。这次我尝试用GitHub Copilot这个AI编程助手来加速开发过程,看看AI能否真正理解游戏逻辑和Blazor的组件化思想。

开发环境准备:

  • Visual Studio 2022 17.8+(内置Blazor工具链)
  • .NET 8.0 SDK(Blazor在此版本有重大更新)
  • GitHub Copilot订阅(学生可免费申请)
  • 浏览器选择:推荐Chrome/Edge最新版

提示:Blazor在.NET 8采用全新渲染模式,InteractiveAuto会根据用户设备自动选择WebAssembly或Server渲染,这是性能优化的关键。

2. 工程创建与初始配置

2.1 项目脚手架搭建

在VS中新建Blazor Web App项目时,需要注意几个关键配置项:

  1. 交互渲染模式选择Interactive Auto
  2. 取消勾选"启用WebAssembly详细调试"
  3. 勾选"包含示例页面"(方便参考)
dotnet new blazor -n Gobang --interactivity Auto

2.2 Copilot的提示词工程

在Razor文件中输入以下提示词触发Copilot建议:

@* 生成一个15x15的五子棋棋盘,使用二维数组存储状态,实现轮流落子、胜负判定功能 *@

Copilot生成的初始代码通常包含三个关键部分:

  1. 棋盘渲染逻辑(双层for循环生成table)
  2. 棋子状态数组(int[15,15])
  3. 基础事件处理(@onclick绑定)

3. 核心游戏逻辑实现

3.1 棋盘状态管理

典型的二维数组方案:

private const int BoardSize = 15; private int[,] board = new int[BoardSize, BoardSize]; // 0空 1黑 2白 private int currentPlayer = 1; // 当前玩家 private int winner = 0; // 获胜方

3.2 落子逻辑的闭包陷阱

原始生成的代码会出现经典闭包问题:

@for (int x = 0; x < BoardSize; x++) { <td @onclick="() => PlacePiece(x, y)">...</td> // 所有格子点击都会使用循环最终值 }

解决方案是创建局部变量副本:

@{ int _x = x; int _y = y; <td @onclick="() => PlacePiece(_x, _y)">...</td> }

3.3 胜负判定算法

四方向检测的经典实现:

private bool CheckWin(int x, int y, int player) { // 四个检测方向:横、竖、斜、反斜 int[][] directions = [ [1,0], [0,1], [1,1], [1,-1] ]; foreach (var dir in directions) { int count = 1 + CountDirection(x, y, dir[0], dir[1], player) + CountDirection(x, y, -dir[0], -dir[1], player); if (count >= 5) return true; } return false; }

方向计数辅助方法:

private int CountDirection(int x, int y, int dx, int dy, int player) { int count = 0; for (int step = 1; step < 5; step++) { int nx = x + dx * step; int ny = y + dy * step; if (nx < 0 || nx >= BoardSize || ny < 0 || ny >= BoardSize) break; if (board[nx, ny] == player) count++; else break; } return count; }

4. AI对手的实现与优化

4.1 随机落子AI(初级难度)

private Random _rnd = new(); private (int x, int y) FindRandomMove() { var emptyCells = new List<(int x, int y)>(); for (int i = 0; i < BoardSize; i++) for (int j = 0; j < BoardSize; j++) if (board[i, j] == 0) emptyCells.Add((i, j)); return emptyCells.Count > 0 ? emptyCells[_rnd.Next(emptyCells.Count)] : (-1, -1); }

4.2 评分策略AI(中高级难度)

基于威胁评估的评分系统:

private (int x, int y) FindSmartMove() { var bestMoves = new List<(int x, int y)>(); int maxScore = int.MinValue; for (int x = 0; x < BoardSize; x++) { for (int y = 0; y < BoardSize; y++) { if (board[x, y] != 0) continue; int score = EvaluatePosition(x, y, 2) // 进攻分 + EvaluatePosition(x, y, 1); // 防守分 if (score > maxScore) { maxScore = score; bestMoves.Clear(); bestMoves.Add((x, y)); } else if (score == maxScore) { bestMoves.Add((x, y)); } } } return bestMoves.Count > 0 ? bestMoves[_rnd.Next(bestMoves.Count)] : (-1, -1); }

评分权重配置示例:

// 不同难度级别的评分权重 private readonly int[] _winScores = [ 100, 10000, 10000 ]; private readonly int[] _blockScores = [ 50, 5000, 8000 ]; private int EvaluatePosition(int x, int y, int player) { int score = 0; foreach (var dir in _directions) { int count = 1 + CountDirection(x, y, dir[0], dir[1], player) + CountDirection(x, y, -dir[0], -dir[1], player); if (count >= 5) score += _winScores[_aiLevel]; else if (count == 4) score += _winScores[_aiLevel] / 10; // 更多条件判断... } return score; }

5. 功能扩展与界面优化

5.1 游戏状态管理

private int _blackScore = 0; private int _whiteScore = 0; private bool _isHumanVsAI = true; private int _aiLevel = 1; // 0-简单 1-中等 2-困难 private void RestartGame() { _board = new int[BoardSize, BoardSize]; _currentPlayer = 1; _winner = 0; if (_isHumanVsAI && _currentPlayer == 2) InvokeAsync(AITakeTurn); }

5.2 棋盘视觉增强

使用CSS变量实现棋盘主题化:

:root { --cell-size: 32px; --dark-cell: #eac066; --light-cell: #f9d77e; --black-piece: #000; --white-piece: #eee; } .board-cell { width: var(--cell-size); height: var(--cell-size); border: 1px solid #888; cursor: pointer; transition: all 0.3s ease; } .board-cell:hover { box-shadow: inset 0 0 10px rgba(0,0,0,0.2); }

5.3 落子动画效果

Blazor的动画方案:

@if (board[x, y] == 1) { <span class="piece animate__animated animate__zoomIn" style="color: var(--black-piece)">●</span> }

6. 部署与性能优化

6.1 渲染模式选择

.NET 8的渲染模式对比:

模式优点缺点适用场景
Static最高性能无交互纯展示
Server低延迟占用连接内网应用
WebAssembly离线运行冷启动慢复杂客户端
Auto (推荐)智能切换配置复杂大多数场景

6.2 发布配置

优化发布的命令行参数:

dotnet publish -c Release --self-contained false /p:BlazorWebAssemblyLoadAllGlobalizationData=false

6.3 实测性能数据

在i5-1135G7设备上的测试结果:

  • 首次加载时间:WebAssembly模式约2.8s,Auto模式约1.2s
  • AI思考延迟:中等难度平均300ms
  • 内存占用:常驻内存约45MB

7. 开发心得与Copilot使用技巧

  1. 提示词要具体:明确指定需要Blazor组件、C#逻辑还是CSS样式

    • 坏例子:"写个五子棋"
    • 好例子:"用Blazor生成15x15棋盘,使用二维数组存储状态,包含胜负判定方法"
  2. 代码审查必不可少:Copilot生成的算法需要人工验证边界条件

    • 特别检查:数组越界、胜负判定、先手规则
  3. 分层利用AI建议:

    • 第一层:生成基础框架
    • 第二层:优化具体算法
    • 第三层:添加异常处理
  4. Blazor开发注意事项:

    • 状态变更后必须调用StateHasChanged()
    • 异步操作使用InvokeAsync确保线程安全
    • 避免在循环中执行耗时操作

这个项目最让我惊讶的是Copilot对游戏规则的理解程度——它能准确生成四方向检测算法,但在闭包处理等特定场景仍需人工干预。AI辅助开发的最佳模式应该是:开发者把控架构设计,Copilot加速细节实现,最后人工进行业务逻辑校验。