HarmonyOS 鸿蒙6.0实战开发项目–AI 五子棋对战 App

本项目是一个基于 HarmonyOS ArkTS + ArkUI 开发的鸿蒙五子棋 App,项目名为 WzqGame。项目包含登录、注册、本地人机对战、棋盘尺寸切换、黑白执棋选择、AI 自动落子、胜负判定、悔棋、音效开关、棋盘最大化和事件日志等功能,适合用来练习 HarmonyOS 原生应用中的状态管理、自定义棋盘绘制、游戏规则封装和简单 AI 策略实现。

功能如下:

  • 用户登录或注册
  • 15x15 与 30x30 棋盘切换
  • 选择执黑先手或执白后手
  • 本地 AI 自动对弈
  • 五子连线胜负判定
  • 平局判断
  • 悔棋与重新开始
  • 棋盘最大化、缩放和平移
  • 黑白落子音效
  • 对局事件日志

一、系统架构总览

项目采用 HarmonyOS Stage 模型开发,整体可以拆成五层:

层级 主要文件 职责
页面层 Index.ets 登录注册、对局设置、棋盘页面、结果弹窗、用户交互
棋盘渲染层 BoardCell.etsIndex.ets 中的 BoardCell Builder 棋盘网格、星位、棋子、最后落子标记
规则模型层 GameTypes.etsGameLogic.etsGameState.ets 棋子类型、游戏状态、落子记录、胜负和平局判断
AI 决策层 LocalGomokuAI.ets 候选点筛选、攻防评分、AI 落子选择
公共能力层 GameConstants.etsAudioManager.ets 棋盘参数、星位配置、缩放参数、落子音效

核心数据流如下:

用户点击棋盘
  -> Index.ets 校验当前状态和落子位置
  -> 更新 boardData 与 moveHistory
  -> GameLogic.determineGameStatus() 判断胜负
  -> 未结束时切换 currentTurn
  -> 如果轮到 AI,LocalGomokuAI.chooseMove() 计算落点
  -> @State 驱动棋盘、状态栏、日志实时刷新

登录注册目前使用页面本地状态保存账户信息:

状态 用途
isLoggedIn 控制登录页和首页切换
authAccount 当前输入的手机号/邮箱
authPassword 当前输入的密码
registeredAccount 本地注册账号
registeredPassword 本地注册密码

二、系统演示截图

1. 登录页

登录页只保留手机号/邮箱、密码、登录、注册和忘记密码入口,页面风格沿用原项目的浅色背景、白色面板和蓝色主按钮。

登录页

2. 注册页

注册页包含手机号/邮箱、密码和确认密码,提交时完成基础校验。

注册页

3. 对局设置页

对局设置页可以选择棋盘尺寸和执棋颜色,进入游戏后由黑方先手。

对局设置页

4. AI 对战棋盘

棋盘页面展示当前回合、步数、玩家与 AI 棋色、悔棋、重新开始、最大化和音效开关。

AI 对战棋盘

5. 对局状态与日志

事件日志记录开局、AI 落点、悔棋和胜负结果,方便观察整局对弈过程。

对局状态与日志


三、系统详细介绍

1. 登录与注册

登录注册逻辑位于 Index.ets,没有单独拆路由页面,而是在现有入口页中通过 isLoggedIn 控制展示登录注册页或游戏首页。

核心状态:

@State isLoggedIn: boolean = false;
@State authMode: AuthMode = AuthMode.LOGIN;
@State authAccount: string = '';
@State authPassword: string = '';
@State authConfirmPassword: string = '';
@State registeredAccount: string = '';
@State registeredPassword: string = '';

注册时主要处理三类校验:

  • 手机号/邮箱不能为空
  • 密码不能为空
  • 确认密码不能为空,且两次密码一致

登录时校验账号和密码不能为空。本地已注册账号后,会继续校验账号和密码是否匹配。登录成功后设置:

this.currentAccount = account;
this.isLoggedIn = true;

这里先使用本地页面状态模拟登录流程,后续接后端时可以把 handleLogin()handleRegister() 替换为真实接口请求。


2. 对局设置

对局设置集中在 SetupPanel() 中,页面保留三个核心信息:

  • 棋盘尺寸
  • 执棋颜色
  • 开始对战

棋盘尺寸支持 15x15 和 30x30:

private switchBoardSize(size: number): void {
  this.selectedBoardSize = size === 30 ? 30 : 15;
  if (this.phase === GamePhase.SETUP) {
    this.resetBoard(this.selectedBoardSize);
  }
}

执棋颜色支持黑方先手和白方后手。如果玩家选择白方,进入游戏后会先触发 AI 黑棋落子。


3. 棋盘渲染

棋盘渲染主要在 Index.etsStaticBoard()ScalableBoard()BoardCell() 中完成。每个交叉点通过 ForEach(getIndices(this.boardSize)) 生成,按行列渲染网格、星位和棋子。

棋盘单元格主要包含:

  • 横向网格线
  • 纵向网格线
  • 星位标记
  • 黑白棋子
  • 最后落子红点标记

棋盘样式配置来自 GameConstants.ets

export const BOARD_LAYOUT = {
  padding: 15,
  board15: {
    cellSize: 22,
    pieceSize: 20
  },
  board30: {
    baseCellSize: 12,
    basePieceSize: 10
  }
};

30x30 棋盘和最大化模式下支持缩放和平移,方便在手机屏幕上查看大棋盘。


4. 游戏状态与落子流程

游戏状态由 GamePhaseGameStatus 共同控制:

enum GamePhase {
  SETUP = 'setup',
  PLAYING = 'playing',
  OVER = 'over'
}

一次玩家落子的核心流程:

private handleCellClick(row: number, col: number): void {
  if (!this.canPlace(row, col)) {
    return;
  }

  const placed = this.placePiece(row, col, this.playerPiece, true);
  if (placed && this.gameStatus === GameStatus.PLAYING) {
    this.queueAiMove();
  }
}

placePiece() 会复制棋盘、写入棋子、记录历史、播放音效、判断胜负,并在对局未结束时切换回合。


5. 胜负判定

胜负判定封装在 GameLogic.ets 中,核心思路是以最后落子点为中心,向四个方向双向统计连续同色棋子数量。

四个方向:

export const DIRECTIONS: Position[] = [
  { row: 0, col: 1 },
  { row: 1, col: 0 },
  { row: 1, col: 1 },
  { row: 1, col: -1 }
];

判断逻辑:

const total = positiveCount + negativeCount + 1;
if (total >= this.config.winCondition) {
  return true;
}

这种写法只围绕最后一步落子检查,不需要每次遍历整张棋盘,适合五子棋这类实时交互场景。


6. 本地 AI 决策

AI 逻辑封装在 LocalGomokuAI.ets。AI 不依赖网络服务,直接根据当前棋盘状态计算落点。

AI 决策大致分为五步:

  1. 扫描棋盘生成候选落点
  2. 优先寻找 AI 能直接获胜的位置
  3. 检查玩家是否存在必须阻挡的连线
  4. 对候选点进行攻防评分
  5. 选择综合分最高的位置落子

核心入口:

const move: AIMove | null = this.ai.chooseMove(
  this.boardData,
  this.aiPiece,
  this.playerPiece
);

评分时会同时考虑进攻和防守,避免 AI 只顾自己连子而忽略玩家威胁。


7. 悔棋、日志和音效

悔棋逻辑位于 undoLastRound()。由于是人机对战,悔棋时默认撤销最近两步,也就是玩家一步和 AI 一步,让棋局回到玩家可继续选择的位置。

事件日志通过 eventLogs 维护,最多保留 8 条:

this.eventLogs.push(`${timeText} ${content}`);
if (this.eventLogs.length > 8) {
  this.eventLogs.shift();
}

音效由 AudioManager.ets 管理,黑白棋分别使用 black_piece.mp3white_piece.mp3。页面上通过 Toggle 控制音效开关。


四、核心模型说明

模型 类型 说明
PieceType enum 空位、黑子、白子
GameStatus enum 进行中、黑方胜、白方胜、平局
MoveRecord interface 单步落子记录
GameConfig interface 棋盘尺寸、胜利条件、悔棋限制
Position interface 棋盘坐标
AIMove interface AI 落点和落子原因

这些模型把棋盘数据、游戏规则和页面展示拆开,后续如果扩展联机对战、难度选择或战绩统计,可以继续基于这些结构增加字段。


五、数据流向示例

以“玩家执黑开始一局”为例:

用户登录
  -> 进入对局设置页
  -> 选择 15x15 棋盘和执黑先手
  -> 点击开始对战
  -> resetBoard() 初始化棋盘
  -> 玩家点击棋盘落黑子
  -> GameLogic 判断是否获胜
  -> currentTurn 切换到白方
  -> LocalGomokuAI 计算白方落点
  -> AI 落白子
  -> 页面状态、棋盘、日志同步刷新

这个流程覆盖了 HarmonyOS 应用中常见的页面状态切换、列表渲染、自定义组件、交互反馈和业务逻辑封装。


六、开发中的关键处理

1. 棋盘数据不可直接原地改

落子时先复制 boardData,再替换整份棋盘数据:

const nextBoard = this.cloneBoard(this.boardData);
nextBoard[row][col] = piece;
this.boardData = nextBoard;

这样能让 ArkUI 更稳定地感知状态变化并刷新棋盘。

2. 胜负判断只检查最后一步

每次落子后只围绕最后落点检查四个方向,不做全棋盘扫描。这样 30x30 棋盘也能保持较轻的计算量。

3. AI 落子需要延迟反馈

AI 使用 setTimeout() 延迟落子,让用户能感受到“玩家落子 -> AI 思考 -> AI 落子”的过程,不会显得页面瞬间跳变。

4. 30x30 棋盘要支持缩放

手机屏幕直接展示 30x30 棋盘会比较密集,所以项目给大棋盘和最大化模式加入 PinchGesturePanGesture,支持双指缩放和三指拖动。

5. 页面文案保持克制

登录注册页只保留账号、密码、确认密码、登录、注册和忘记密码,没有加入第三方登录、验证码倒计时或宣传式文案,页面更接近真实 App 的功能页。


七、适合继续扩展的方向

这个项目可以继续扩展:

  • 登录状态持久化
  • 接入后端登录注册接口
  • AI 难度选择
  • 人人双人对战模式
  • 对局计时
  • 战绩统计
  • 棋谱回放
  • 禁手规则
  • 联机对战
  • 棋盘主题切换

如果想继续提高完整度,可以优先做 AI 难度选择、战绩统计和棋谱回放,这些功能和五子棋 App 的使用场景最接近。


八、项目总结

AI 五子棋对战项目覆盖了 HarmonyOS 实战开发中比较典型的能力:

  • ArkUI 页面搭建
  • ArkTS 状态管理
  • 本地登录注册
  • 自定义棋盘渲染
  • 手势缩放和平移
  • 音频播放控制
  • 游戏规则封装
  • 本地 AI 决策
  • 对局日志和结果弹窗

它的页面数量不多,但能把 UI、状态、模型、算法和交互反馈串起来。对于正在学习 HarmonyOS 的同学来说,这类小型游戏项目很适合用来理解 ArkTS 状态驱动 UI 的开发方式。

九、源码获取


想获取代码请点击此链接或下方链接

https://ycc123666.oss-cn-beijing.aliyuncs.com/img/87ce0de2f2d8d0baab5b6aa8c3aebdab.jpg
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐