欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图




1.1 应用简介
棋谱记录是一款专为棋类爱好者设计的棋谱管理工具,支持围棋和象棋两种棋类的棋谱记录与复盘。无论是职业比赛还是业余对局,都能完整记录对局信息、棋步序列,方便日后复盘研究。应用采用经典的棋谱卡片式布局,对局信息一目了然。
应用支持棋谱的创建、编辑、删除和详情查看,棋步记录功能让每一步棋都有迹可循。复盘功能支持逐步前进后退,帮助棋手深入分析对局过程。标签分类和搜索筛选功能让棋谱管理更加便捷高效。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 棋谱列表 | 展示所有棋谱记录 | ListView + Card |
| 新建棋谱 | 创建新的棋谱记录 | 表单页面 |
| 编辑棋谱 | 修改已有棋谱信息 | 表单预填充 |
| 删除棋谱 | 删除不需要的记录 | 确认对话框 |
| 详情查看 | 查看棋谱完整信息 | 详情页面 |
| 棋步记录 | 记录每一步棋 | 列表管理 |
| 复盘功能 | 逐步回放棋局 | 播放控制 |
| 类型筛选 | 按围棋/象棋筛选 | PopupMenu |
| 搜索功能 | 关键词搜索棋谱 | TextField过滤 |
| 标签管理 | 棋谱标签分类 | Chip组件 |
1.3 棋谱记录字段
| 字段 | 类型 | 说明 |
|---|---|---|
| 棋谱标题 | String | 棋谱名称,必填 |
| 棋类类型 | ChessType | 围棋/象棋 |
| 对局结果 | GameResult | 黑胜/白胜/红胜/和棋 |
| 黑方棋手 | String | 黑方选手姓名 |
| 白方棋手 | String | 白方选手姓名(围棋) |
| 红方棋手 | String | 红方选手姓名(象棋) |
| 对局日期 | DateTime | 对局发生日期 |
| 对局地点 | String | 对局举办地点 |
| 赛事名称 | String | 所属赛事 |
| 棋步序列 | List | 棋步列表 |
| 棋谱备注 | String | 棋谱详细说明 |
| 标签 | List | 分类标签 |
| 创建时间 | DateTime | 记录创建时间 |
| 更新时间 | DateTime | 最后修改时间 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 目标平台 | 鸿蒙OS | API 21+ |
1.5 项目结构
lib/
└── main_chess_record.dart
├── ChessRecordApp # 应用入口
├── ChessType # 棋类类型枚举
├── GameResult # 对局结果枚举
├── ChessMove # 棋步模型
├── ChessRecord # 棋谱模型
├── ChessRecordPage # 主列表页面
│ ├── _buildSearchBar() # 搜索栏
│ ├── _buildRecordsList() # 记录列表
│ └── _buildRecordCard() # 记录卡片
├── ChessRecordEditPage # 编辑页面
│ ├── _selectDate() # 日期选择
│ ├── _addMove() # 添加棋步
│ ├── _addTag() # 添加标签
│ └── _save() # 保存棋谱
├── ChessRecordDetailPage # 详情页面
│ └── _buildPlayerAvatar() # 选手头像
└── MovesReplayPage # 复盘页面
├── _goToMove() # 跳转棋步
├── _previousMove() # 上一步
└── _nextMove() # 下一步
二、系统架构
2.1 整体架构图
Business Logic
Presentation Layer
Data Layer
ChessRecord
棋谱模型
ChessMove
棋步模型
ChessType
棋类枚举
GameResult
结果枚举
列表页面
搜索栏
棋谱卡片列表
编辑页面
基本信息表单
棋步记录区
标签管理区
详情页面
对局信息展示
复盘页面
棋步列表
播放控制
棋谱管理
增删改查
棋步管理
添加删除
复盘控制
前进后退
筛选搜索
_filteredRecords
2.2 类图设计
contains
manages
contains
has
has
navigates
navigates
navigates
ChessRecordApp
+Widget build()
<<enumeration>>
ChessType
go
xiangqi
<<enumeration>>
GameResult
unknown
blackWin
whiteWin
redWin
blackWinXiangqi
draw
ChessMove
+int moveNumber
+String notation
+String? comment
+int? x
+int? y
ChessRecord
+String id
+String title
+ChessType chessType
+GameResult result
+String blackPlayer
+String whitePlayer
+String redPlayer
+DateTime gameDate
+List<ChessMove> moves
+List<String> tags
+String resultText
+String chessTypeText
+int totalMoves
ChessRecordPage
-List<ChessRecord> _records
-String _searchQuery
-String _selectedType
-List<ChessRecord> _filteredRecords
+Widget build()
-void _addRecord()
-void _editRecord()
-void _deleteRecord()
MovesReplayPage
-ChessRecord record
-int _currentMove
+Widget build()
-void _goToMove()
-void _previousMove()
-void _nextMove()
ChessRecordEditPage
ChessRecordDetailPage
2.3 数据流程图
新建
编辑
删除
查看
复盘
搜索
筛选
用户操作
操作类型
打开编辑页面
打开编辑页面-预填充
确认对话框
打开详情页面
打开复盘页面
过滤记录列表
按类型过滤
填写表单
添加棋步
保存棋谱
更新记录列表
棋步播放控制
逐步前进后退
2.4 复盘流程
播放控制 棋步列表 复盘页面 用户 播放控制 棋步列表 复盘页面 用户 打开复盘 加载棋步 显示第0手 点击下一步 _nextMove() 显示第1手 点击某步 _goToMove(index) 显示指定手 点击上一步 _previousMove() 显示上一手
三、核心模块设计
3.1 数据模型设计
3.1.1 棋类类型枚举 (ChessType)
dart
enum ChessType {
go, // 围棋
xiangqi, // 象棋
}
3.1.2 对局结果枚举 (GameResult)
dart
enum GameResult {
unknown, // 未知
blackWin, // 黑胜(围棋)
whiteWin, // 白胜
redWin, // 红胜(象棋)
blackWinXiangqi, // 黑胜(象棋)
draw, // 和棋
}
3.1.3 棋步模型 (ChessMove)
dart
class ChessMove {
final int moveNumber; // 手数
final String notation; // 棋步记法
final String? comment; // 注释
final int? x; // X坐标
final int? y; // Y坐标
}
3.1.4 棋谱模型 (ChessRecord)
dart
class ChessRecord {
final String id; // 唯一标识
String title; // 棋谱标题
ChessType chessType; // 棋类类型
GameResult result; // 对局结果
String blackPlayer; // 黑方(围棋)
String whitePlayer; // 白方(围棋)
String redPlayer; // 红方(象棋)
String blackPlayerXiangqi; // 黑方(象棋)
DateTime gameDate; // 对局日期
String location; // 对局地点
String event; // 赛事名称
List<ChessMove> moves; // 棋步序列
String comment; // 棋谱备注
List<String> tags; // 标签列表
DateTime createdAt; // 创建时间
DateTime updatedAt; // 更新时间
}
3.2 筛选过滤算法
3.2.1 过滤流程
是
否
是
否
获取全部记录
是否选择类型?
按类型过滤
保留全部
是否有搜索词?
关键词匹配过滤
按日期排序
返回过滤结果
3.2.2 过滤实现
dart
List<ChessRecord> get _filteredRecords {
var records = _records.toList();
// 类型过滤
if (_selectedType != '全部') {
ChessType? type;
switch (_selectedType) {
case '围棋': type = ChessType.go; break;
case '象棋': type = ChessType.xiangqi; break;
}
if (type != null) {
records = records.where((r) => r.chessType == type).toList();
}
}
// 关键词搜索
if (_searchQuery.isNotEmpty) {
records = records.where((r) {
return r.title.toLowerCase().contains(_searchQuery.toLowerCase()) ||
r.event.toLowerCase().contains(_searchQuery.toLowerCase()) ||
r.blackPlayer.toLowerCase().contains(_searchQuery.toLowerCase());
}).toList();
}
records.sort((a, b) => b.gameDate.compareTo(a.gameDate));
return records;
}
3.3 复盘控制算法
3.3.1 播放控制流程
初始状态
下一步
下一步
上一步
上一步
回到开始
跳到结束
第0手
第1手
第2手
第N手
3.3.2 播放控制实现
dart
void _previousMove() {
if (_currentMove > 0) {
setState(() {
_currentMove--;
});
}
}
void _nextMove() {
if (_currentMove < widget.record.moves.length) {
setState(() {
_currentMove++;
});
}
}
void _goToMove(int index) {
setState(() {
_currentMove = index;
});
}
void _goToStart() {
setState(() {
_currentMove = 0;
});
}
void _goToEnd() {
setState(() {
_currentMove = widget.record.moves.length;
});
}
3.4 页面结构设计
3.4.1 列表页面布局
列表页面
搜索栏
棋谱卡片列表
浮动按钮
棋谱卡片1
棋谱卡片2
...
类型/结果标签
棋谱标题
赛事/日期
对局双方
手数/标签
3.4.2 编辑页面布局
┌─────────────────────────────────────────────────────────────┐
│ AppBar: 新建/编辑棋谱 [💾 保存] │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 📝 棋谱标题 * │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 棋类: 围棋/象棋 │ │ 结果: 黑胜/白胜 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ 📅 对局日期 | 🏆 赛事名称 | 📍 对局地点 │
│ │
│ 对局双方: │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ ● 黑方 │ │ ○ 白方 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ 棋步记录 [+ 添加] │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ① 炮二平五 ② 马8进7 ③ ... │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 📋 棋谱备注 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 多行文本输入 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 标签: [名局] [决赛] [×] │
└─────────────────────────────────────────────────────────────┘
3.5 状态管理
3.5.1 核心状态变量
dart
class _ChessRecordPageState extends State<ChessRecordPage> {
final List<ChessRecord> _records = []; // 所有棋谱
String _searchQuery = ''; // 搜索关键词
String _selectedType = '全部'; // 选中的类型筛选
}
class _MovesReplayPageState extends State<MovesReplayPage> {
int _currentMove = 0; // 当前棋步位置
}
3.5.2 状态更新流程
dart
// 添加棋步
void _addMove() {
if (_moveController.text.isNotEmpty) {
setState(() {
_moves.add(ChessMove(
moveNumber: _moves.length + 1,
notation: _moveController.text,
));
_moveController.clear();
});
}
}
// 删除棋步
void _removeMove(int index) {
setState(() {
_moves.removeAt(index);
// 重新编号
for (int i = 0; i < _moves.length; i++) {
_moves[i] = ChessMove(
moveNumber: i + 1,
notation: _moves[i].notation,
);
}
});
}
四、UI设计规范
4.1 配色方案
应用采用棕色主题风格,体现棋类的传统文化:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | Brown | AppBar、按钮、强调 |
| 围棋标签 | Black | 围棋类型标识 |
| 象棋标签 | Red | 象棋类型标识 |
| 黑方 | Black | 黑方选手标识 |
| 白方 | Grey | 白方选手标识 |
| 红方 | Red | 红方选手标识 |
4.2 棋类类型样式
4.2.1 类型标签
| 类型 | 颜色 | 说明 |
|---|---|---|
| 围棋 | 黑色 | 黑白对弈 |
| 象棋 | 红色 | 红黑对弈 |
4.2.2 结果标签
| 结果 | 颜色 |
|---|---|
| 黑胜 | 黑色 |
| 白胜 | 灰色 |
| 红胜 | 红色 |
| 和棋 | 橙色 |
| 未知 | 灰色 |
4.3 组件规范
4.3.1 棋谱卡片
┌─────────────────────────────────────────────────────────────┐
│ [围棋] [黑胜] ⋮ │
│ 名人战决赛第一局 │
│ 🏆 名人战 📅 2024-01-15 │
│ ● 柯洁 vs ○ 申真谞 │
│ 📋 250手 [名局] [决赛] │
└─────────────────────────────────────────────────────────────┘
4.3.2 选手头像
┌─────────────────┐
│ ● 黑方 │
│ 柯洁 │
└─────────────────┘
4.4 交互设计
4.4.1 操作方式
| 操作 | 手势 | 效果 |
|---|---|---|
| 查看详情 | 点击卡片 | 跳转详情页 |
| 新建棋谱 | 点击浮动按钮 | 跳转编辑页 |
| 编辑棋谱 | 点击菜单-编辑 | 跳转编辑页 |
| 删除棋谱 | 点击菜单-删除 | 确认后删除 |
| 复盘棋局 | 点击菜单-复盘 | 跳转复盘页 |
| 搜索 | 输入关键词 | 实时过滤 |
| 筛选 | 点击筛选图标 | 选择类型 |
4.4.2 复盘控制
┌─────────────────────────────────────────────────────────────┐
│ ⏮ ◀ [ 50/250 ] ▶ ⏭ │
└─────────────────────────────────────────────────────────────┘
五、核心功能实现
5.1 列表页面构建
dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('棋谱记录'),
actions: [
PopupMenuButton<String>(
icon: const Icon(Icons.filter_list),
onSelected: (value) {
setState(() {
_selectedType = value;
});
},
itemBuilder: (context) => _typeFilters.map((type) {
return PopupMenuItem(value: type, child: Text(type));
}).toList(),
),
],
),
body: Column(
children: [
_buildSearchBar(),
Expanded(
child: _filteredRecords.isEmpty
? _buildEmptyState()
: _buildRecordsList(),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _addRecord,
child: const Icon(Icons.add),
),
);
}
5.2 棋步管理
dart
// 添加棋步
void _addMove() {
if (_moveController.text.isNotEmpty) {
setState(() {
_moves.add(ChessMove(
moveNumber: _moves.length + 1,
notation: _moveController.text,
));
_moveController.clear();
});
}
}
// 删除棋步
void _removeMove(int index) {
setState(() {
_moves.removeAt(index);
// 重新编号所有棋步
for (int i = 0; i < _moves.length; i++) {
_moves[i] = ChessMove(
moveNumber: i + 1,
notation: _moves[i].notation,
comment: _moves[i].comment,
);
}
});
}
5.3 复盘功能
dart
class _MovesReplayPageState extends State<MovesReplayPage> {
int _currentMove = 0;
void _previousMove() {
if (_currentMove > 0) {
setState(() {
_currentMove--;
});
}
}
void _nextMove() {
if (_currentMove < widget.record.moves.length) {
setState(() {
_currentMove++;
});
}
}
void _goToMove(int index) {
setState(() {
_currentMove = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
// 当前手数显示
Text('第 $_currentMove / ${widget.record.moves.length} 手'),
// 棋步列表
Expanded(child: ListView.builder(...)),
// 播放控制
Row(
children: [
IconButton(onPressed: _goToStart, icon: Icon(Icons.skip_previous)),
IconButton(onPressed: _previousMove, icon: Icon(Icons.chevron_left)),
Text('$_currentMove/${widget.record.moves.length}'),
IconButton(onPressed: _nextMove, icon: Icon(Icons.chevron_right)),
IconButton(onPressed: _goToEnd, icon: Icon(Icons.skip_next)),
],
),
],
),
);
}
}
5.4 表单验证与保存
dart
void _save() {
if (_formKey.currentState!.validate()) {
final now = DateTime.now();
final record = ChessRecord(
id: widget.record?.id ?? DateTime.now().millisecondsSinceEpoch.toString(),
title: _titleController.text,
chessType: _selectedType,
result: _selectedResult,
blackPlayer: _blackPlayerController.text,
whitePlayer: _whitePlayerController.text,
redPlayer: _redPlayerController.text,
blackPlayerXiangqi: _blackPlayerXiangqiController.text,
gameDate: _gameDate,
location: _locationController.text,
event: _eventController.text,
moves: _moves,
comment: _commentController.text,
tags: _tags,
createdAt: widget.record?.createdAt ?? now,
updatedAt: now,
);
Navigator.pop(context, record);
}
}
六、棋谱知识拓展
6.1 围棋棋谱
6.1.1 围棋记谱方式
围棋记谱
坐标记谱
中文记谱
Q16 (星位)
D4 (小目)
右上星
左下小目
6.1.2 围棋术语
| 术语 | 说明 |
|---|---|
| 星 | 棋盘上的9个星位 |
| 小目 | 三四路位置 |
| 目外 | 三五路位置 |
| 高目 | 四五路位置 |
| 天元 | 棋盘中心点 |
6.2 象棋棋谱
6.2.1 象棋记谱方式
象棋记谱
着法记录
局面记录
炮二平五
马8进7
车一进一
初始局面
残局局面
6.2.2 象棋术语
| 术语 | 说明 |
|---|---|
| 平 | 棋子横向移动 |
| 进 | 棋子向前移动 |
| 退 | 棋子向后移动 |
| 将 | 将军 |
| 杀 | 绝杀 |
6.3 棋谱保存格式
6.3.1 常见格式
| 格式 | 说明 | 用途 |
|---|---|---|
| SGF | 围棋标准格式 | 围棋软件通用 |
| PGN | 国际象棋格式 | 国际象棋通用 |
| XQF | 象棋格式 | 象棋软件专用 |
| JSON | 通用数据格式 | 跨平台交换 |
七、扩展功能规划
7.1 后续版本规划
2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 2024-03-24 2024-03-31 核心记录功能 棋步管理功能 复盘播放功能 数据持久化 棋盘可视化 导入导出功能 形势判断功能 AI分析功能 在线对弈功能 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 棋谱记录应用开发计划
7.2 功能扩展建议
7.2.1 棋盘可视化
| 功能 | 说明 |
|---|---|
| 围棋棋盘 | 19x19路棋盘显示 |
| 象棋棋盘 | 9x10路棋盘显示 |
| 落子动画 | 棋子放置动画效果 |
| 标记功能 | 标记关键点 |
7.2.2 导入导出
| 功能 | 说明 |
|---|---|
| SGF导入 | 导入围棋SGF文件 |
| XQF导入 | 导入象棋XQF文件 |
| 图片导出 | 导出棋盘图片 |
| 分享功能 | 分享棋谱链接 |
7.2.3 AI分析
| 功能 | 说明 |
|---|---|
| 形势判断 | 分析当前局面 |
| 最佳选点 | AI推荐最佳着法 |
| 失误分析 | 标记关键失误 |
八、注意事项
8.1 开发注意事项
-
棋步编号:删除棋步后需要重新编号
-
类型切换:切换棋类类型时清空不相关字段
-
日期处理:注意日期的格式化和解析
-
表单验证:必填字段要进行验证
8.2 用户体验优化
💡 用户体验建议 💡
- 棋步记录简洁高效
- 复盘操作流畅自然
- 对局信息一目了然
- 支持快速搜索筛选
8.3 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 棋步编号错误 | 删除后未重编号 | 检查重编号逻辑 |
| 类型切换异常 | 字段未清空 | 切换时清空字段 |
| 复盘位置错误 | 索引越界 | 检查边界条件 |
| 搜索无结果 | 过滤条件错误 | 检查过滤逻辑 |
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
9.2 运行命令
bash
# 查看可用设备
flutter devices
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_chess_record.dart
# 运行到Windows
flutter run -d windows -t lib/main_chess_record.dart
# 代码分析
flutter analyze lib/main_chess_record.dart
十、总结
棋谱记录应用通过完善的功能设计,帮助棋类爱好者记录和管理棋谱。应用支持围棋和象棋两种棋类,对局信息、棋步序列、备注标签等核心数据完整记录。复盘功能支持逐步前进后退,帮助棋手深入分析对局过程。
棋步管理功能支持添加和删除操作,编号自动维护。标签功能帮助对棋谱进行分类,方便筛选和管理。搜索和筛选功能让用户快速定位目标棋谱,提高管理效率。
界面设计采用棕色主题风格,体现棋类的传统文化底蕴。类型标签使用不同颜色区分围棋和象棋,选手头像清晰展示对局双方。应用采用Material Design 3设计规范,遵循Flutter最佳实践,代码结构清晰,易于维护和扩展。
棋谱记录,传承经典,复盘研究,棋艺精进!