零基础鸿蒙应用开发第九节:流程控制综合练习

零基础鸿蒙应用开发学习计划表

【学习目标】

  1. 吃透嵌套循环的核心逻辑(行/列控制),能独立实现杨辉三角、99乘法表的算法
  2. 掌握猜数字游戏的核心规则:随机数生成、输入校验、次数控制、分支判断、游戏终止逻辑
  3. 理解二维数组的初始化、赋值与遍历,解决杨辉三角这类结构化数据存储问题
  4. 掌握输入校验的三层过滤逻辑(空值、类型、范围),提升程序健壮性
  5. 掌握字符串格式化技巧(对齐、填充),优化控制台输出可读性

【学习重点】

  1. 嵌套循环:外层控“整体结构(行)”,内层控“局部细节(列)”
  2. 输入校验:isNaN()判断数字合法性 + 范围边界判断,拦截非法输入
  3. 二维数组:杨辉三角的核心数据结构,重点掌握“上一行数据复用”生成当前行
  4. 分支判断:猜数字游戏的多状态(猜大/猜小/猜对/次数用尽)逻辑闭环
  5. 状态控制:通过布尔变量(如isGameOver)控制流程启停,避免无效操作

一、工程结构

本节我们将创建名为ArkTSFunPractice的工程,基于 鸿蒙5.0(API12) 开发,使用 DevEco Studio 6.0+ 工具,项目结构目录如下:

ArkTSFunPractice/
├── AppScope                 # 应用全局配置
├── entry/
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/
│   │   │   │   ├── entryability/  # 应用入口
│   │   │   │   │   └── EntryAbility.ets
│   │   │   │   ├── pages/         # 页面代码
│   │   │   │   │   └── Index.ets  # 核心页面(猜数字游戏完整代码)
│   │   │   │   └── utils/         # 纯逻辑工具函数
│   │   │   │       └── TableLogic.ets # 杨辉三角+99乘法表逻辑
│   │   │   ├── resources/         # 资源文件(默认生成,无需修改)
│   │   │   └── module.json5       # 模块配置(默认生成,无需修改)

二、案例解析

案例1:猜数字游戏

以下是猜数字游戏的纯逻辑代码,实现“随机数生成→输入校验→次数控制→分支判断→游戏终止”的完整规则闭环:

// 游戏核心状态
let targetNumber: number = generateRandomNumber(); // 目标数字(1-100)
let userInput: string = ''; // 用户输入的字符串
let guessCount: number = 0; // 已猜次数
let maxAttempts: number = 10; // 最大尝试次数
let message: string = '请输入1-100之间的数字开始游戏'; // 提示信息
let history: string[] = []; // 历史记录
let isGameOver: boolean = false; // 游戏是否结束

// 1. 生成1-100的随机数(核心算法)
function generateRandomNumber(): number {
  return Math.floor(Math.random() * 100) + 1; // 关键:+1 避免生成0,保证范围1-100
}

// 2. 重置游戏(状态重置逻辑)
function resetGame() {
  targetNumber = generateRandomNumber(); // 重新生成答案
  userInput = ''; // 清空输入缓存
  guessCount = 0; // 重置次数
  message = '游戏已重置,请重新输入1-100之间的数字';
  history = []; // 清空历史记录
  isGameOver = false; // 激活游戏流程
}

// 3. 猜数字核心逻辑(核心规则实现)
function handleGuess() {
  // 前置拦截:游戏结束后拒绝处理新猜测
  if (isGameOver) return;

  // 输入校验(三层过滤,核心健壮性保障)
  const guess = Number(userInput);
  if (isNaN(guess) || guess < 1 || guess > 100) {
    message = '请输入有效的1-100之间的数字!';
    console.log('[猜数字游戏]', message); // 替代UI提示,控制台输出
    return;
  }

  // 次数计数:每提交一次猜测,次数+1
  guessCount++;
  const remaining = maxAttempts - guessCount; // 计算剩余次数
  const record = `第${guessCount}次:${guess}`; // 构建历史记录模板

  // 核心分支判断:根据猜测值与目标值的关系更新状态
  if (guess > targetNumber) {
    message = `猜大了!还剩${remaining}次机会`;
    history.unshift(`${record} → 猜大了`);
  } else if (guess < targetNumber) {
    message = `猜小了!还剩${remaining}次机会`;
    history.unshift(`${record} → 猜小了`);
  } else {
    // 猜对:终止游戏流程
    message = `恭喜你猜对了!答案就是${guess},共猜了${guessCount}次`;
    history.unshift(`${record} → 猜对了!🎉`);
    isGameOver = true;
    console.log('[猜数字游戏]', message);
    return; // 猜对后直接退出,避免后续次数用尽判断
  }

  // 次数用尽:终止游戏流程
  if (remaining === 0) {
    message = `游戏结束!正确答案是${targetNumber}`;
    history.unshift(`次数用尽 → 正确答案:${targetNumber}`);
    isGameOver = true;
  }

  // 输出本次操作结果
  console.log('[猜数字游戏]', message);
  // 清空输入缓存,准备下一次输入
  userInput = '';
}

// 测试示例(控制台运行,可选)
// userInput = "50"; handleGuess(); // 模拟输入50并提交
// userInput = "80"; handleGuess(); // 模拟输入80并提交
// resetGame(); // 重置游戏

关键逻辑要点

逻辑模块 核心作用 关键代码/规则
随机数生成 确定游戏唯一答案 Math.floor(Math.random() * 100) + 1(+1是核心,保证1-100范围)
输入校验 拦截非法输入,避免程序异常 isNaN(guess)判断数字合法性 + `guess < 1
次数控制 限制游戏次数,控制流程节奏 guessCount++计数 + remaining = maxAttempts - guessCount计算剩余次数
分支判断 实现游戏核心规则 猜大/猜小:更新提示+历史;猜对/次数用尽:设置isGameOver = true终止游戏
状态重置 支持游戏重新开始 所有变量恢复初始值,且重新生成随机数

⚠️ 易错点

  1. 随机数范围错误:漏写+1,导致生成0-99的数字,不符合1-100的规则;
  2. 未拦截游戏结束状态:isGameOver为true时仍执行猜数字逻辑,导致次数异常增加;
  3. 输入校验遗漏:未判断isNaN(guess),用户输入非数字时会导致后续比较逻辑出错;
  4. 猜对后未提前退出:猜对后仍执行后续的次数用尽判断,可能覆盖正确提示。

案例2:杨辉三角(嵌套循环+二维数组)

纯逻辑实现杨辉三角的生成与控制台格式化输出,核心是“二维数组存储+嵌套循环生成+边界规则+上一行数据复用”:

/**
 * 杨辉三角生成逻辑
 * @param rowCount 生成行数,默认10行
 */
export function testYanghuiTriangle(rowCount: number = 10) {
  // 输入校验:限制行数范围,非法值兜底(健壮性设计)
  if (isNaN(rowCount) || rowCount < 1 || rowCount > 20) {
    rowCount = 10;
    console.log("[testYanghuiTriangle] 输入行数非法,默认显示10行");
  }
  console.log(`\n===== 杨辉三角(${rowCount}行) =====`);
  
  // 二维数组:存储杨辉三角的所有行数据
  let triangle: number[][] = [];

  // 外层循环:控制生成的总行数(行索引从0开始)
  for (let rowIdx: number = 0; rowIdx < rowCount; rowIdx++) { 
    let currentRow: number[] = []; // 临时存储当前行的元素
    // 内层循环:控制当前行的元素个数(列索引≤行索引,保证第n行有n+1个元素)
    for (let colIdx: number = 0; colIdx <= rowIdx; colIdx++) { 
      // 边界规则:每行第一个/最后一个元素固定为1
      if (colIdx === 0 || colIdx === rowIdx) {
        currentRow.push(1); 
      } else {
        // 核心算法:中间元素 = 上一行的当前列-1元素 + 上一行的当前列元素
        const prevRow: number[] = triangle[rowIdx - 1];
        currentRow.push(prevRow[colIdx - 1] + prevRow[colIdx]);
      }
    }
    triangle.push(currentRow); // 将当前行存入二维数组
  }

  // 格式化输出(控制台可视化,非核心逻辑)
  triangle.forEach((row: number[], index: number) => {
    const spaceCount: number = (rowCount - index - 1) * 2;
    const rowStr: string = row.join('  ');
    // 由于空格无法被打印,用*占位
    console.log('*'.repeat(spaceCount) + rowStr);
  });
}

关键逻辑要点

逻辑模块 核心作用 关键代码/规则
输入校验 避免非法行数导致逻辑异常 `isNaN(rowCount)
二维数组初始化 存储结构化的杨辉三角数据 triangle: number[][] = [] 定义二维数组,currentRow: number[] = [] 初始化当前行
外层循环 控制总行数 rowIdx从0到rowCount-1,逐行生成
内层循环 控制每行元素数 colIdx从0到rowIdx,保证第n行有n+1个元素
边界规则 杨辉三角基础规则 `colIdx === 0
中间元素计算 杨辉三角核心算法 prevRow[colIdx - 1] + prevRow[colIdx](复用上一行数据)

⚠️ 易错点

  1. 二维数组行未初始化:直接给triangle[rowIdx][colIdx]赋值,未先创建currentRow,导致数组越界;
  2. 内层循环条件错误:写成colIdx < rowCount,导致每行元素数超出(正确应为colIdx <= rowIdx);
  3. 中间元素计算错误:误用当前行数据(triangle[rowIdx][colIdx - 1])而非上一行(prevRow);
  4. 行索引理解错误:忘记rowIdx从0开始,导致行数少生成1行。

案例3:99乘法表(嵌套循环+格式化)

纯逻辑实现两种样式的99乘法表,核心是“嵌套循环控制行/列组合+字符串格式化保证输出对齐”:

/**
 * 99乘法表生成
 */
export function testMultiplicationTable() {
  console.log("\n===== 99乘法表(直角三角形版) =====");
  for (let i: number = 1; i <= 9; i++) { // 外层:控制乘数(行)
    let line: string = "";
    // 内层:控制被乘数(列),仅到当前行,避免1×2和2×1重复
    for (let j: number = 1; j <= i; j++) { 
      line += `${j}×${i}=${j*i}\t`; // \t制表符保证元素对齐
    }
    console.log(line);
  }
}

⚠️ 易错点

  1. 内层循环条件错误:写成j <= 9,导致生成完整矩形而非三角;
  2. 格式化对齐遗漏:未用\tpadEnd,导致输出内容参差不齐;
  3. 循环变量混淆:将乘数和被乘数搞反(如i×j写成j×i),不影响结果但不符合常规展示习惯;

三、完整代码示例

// UI内容本阶段不学习,重点掌握代码程序逻辑基础。
import { promptAction, router } from '@kit.ArkUI'
import { testYanghuiTriangle, testMultiplicationTable } from '../utils/TableLogic';

@Entry
@Component
struct Index {
  // 游戏核心状态(@State 感知数据变化刷新UI)
  @State targetNumber: number = this.generateRandomNumber() // 目标数字(1-100)
  @State userInput: string = '' // 用户输入的字符串
  @State guessCount: number = 0 // 已猜次数
  @State maxAttempts: number = 10 // 最大尝试次数
  @State message: string = '请输入1-100之间的数字开始游戏' // 提示信息
  @State history: string[] = [] // 历史记录
  @State isGameOver: boolean = false // 游戏是否结束
  
  // 页面加载时执行杨辉三角和乘法表逻辑(控制台输出)
  aboutToAppear() {
    testYanghuiTriangle();
    testMultiplicationTable();
  }

  // 生成1-100的随机数
  generateRandomNumber(): number {
    return Math.floor(Math.random() * 100) + 1;
  }

  // 重置游戏
  resetGame() {
    this.targetNumber = this.generateRandomNumber();
    this.userInput = '';
    this.guessCount = 0;
    this.message = '游戏已重置,请重新输入1-100之间的数字';
    this.history = [];
    this.isGameOver = false;
  }

  // 处理猜数字逻辑
  handleGuess() {
    if (this.isGameOver) return;

    const guess = Number(this.userInput);
    if (isNaN(guess) || guess < 1 || guess > 100) {
      this.message = '请输入有效的1-100之间的数字!';
      promptAction.showToast({ message: this.message });
      return;
    }

    this.guessCount++;
    const remaining = this.maxAttempts - this.guessCount;
    const record = `第${this.guessCount}次:${guess}`;

    if (guess > this.targetNumber) {
      this.message = `猜大了!还剩${remaining}次机会`;
      this.history.unshift(`${record} → 猜大了`);
    } else if (guess < this.targetNumber) {
      this.message = `猜小了!还剩${remaining}次机会`;
      this.history.unshift(`${record} → 猜小了`);
    } else {
      this.message = `恭喜你猜对了!答案就是${guess},共猜了${this.guessCount}次`;
      this.history.unshift(`${record} → 猜对了!🎉`);
      this.isGameOver = true;
      return;
    }

    if (remaining === 0) {
      this.message = `游戏结束!正确答案是${this.targetNumber}`;
      this.history.unshift(`次数用尽 → 正确答案:${this.targetNumber}`);
      this.isGameOver = true;
    }

    this.userInput = '';
  }

  build() {
    Column() {
      // 游戏标题
      Text('猜数字小游戏')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin(20)
        .onClick(()=>{
         router.push({
           url:"pages/nextPage"
         })
        })

      // 游戏规则
      Text(`规则:猜1-100之间的数字,共${this.maxAttempts}次机会`)
        .fontSize(14)
        .fontColor('#666')
        .margin({ bottom: 20 })

      // 输入区域
      Row() {
        TextInput({
          placeholder: '请输入数字',
          text: this.userInput
        })
          .type(InputType.Number) // 限制为数字输入
          .width(200)
          .height(40)
          .border({ width: 1 })
          .padding(5)
          .onChange((value) => this.userInput = value)

        Button('猜一下')
          .width(100)
          .height(40)
          .margin({ left: 10 })
          .onClick(() => this.handleGuess())
      }
      .margin({ bottom: 20 })

      // 提示信息
      Text(this.message)
        .fontSize(16)
        .fontColor(this.isGameOver ? '#e53935' : '#2e7d32')
        .margin({ bottom: 10 })

      // 历史记录
      Text('历史记录:')
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .margin({ bottom: 5, top: 10 })

      Scroll() {
        Column() {
          ForEach(this.history, (item:string) => {
            Text(item)
              .fontSize(14)
              .margin(2)
              .fontColor('#555')
          })
        }
      }
      .height(200)
      .width('100%')
      .border({ width: 1, style: BorderStyle.Dashed })
      .padding(5)

      // 重置按钮
      Button('重新开始')
        .width(150)
        .height(40)
        .margin({ top: 20 })
        .backgroundColor('#42a5f5')
        .onClick(() => this.resetGame())
    }
    .width('100%')
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

运行结果

猜数字综合练习

四、内容总结

1. 逻辑核心回顾

  • 猜数字游戏:核心是随机数生成+输入校验+次数控制+分支判断+状态终止,重点掌握“三层输入过滤”和“游戏状态闭环”;
  • 杨辉三角:核心是二维数组+嵌套循环+边界规则+上一行数据复用,重点掌握“中间元素的计算逻辑”;
  • 99乘法表:核心是嵌套循环的行/列控制,重点是j <= i避免重复。

2. 通用逻辑技巧

  1. 输入校验优先:任何接收外部输入的逻辑,先做合法性校验,再处理核心规则;
  2. 嵌套循环分层:外层控“行/整体”,内层控“列/细节”,避免层级超过2层;
  3. 状态控制闭环:用布尔变量(如isGameOver)控制流程启停,避免无效操作;
  4. 数据结构匹配场景:结构化数据(如杨辉三角)用二维数组,线性数据(如历史记录)用一维数组。

五、代码仓库

六、下节预告

本节我们学习了猜数字小游戏、杨辉三角、九九乘法表的实现逻辑,对之前所学知识做了一次系统巩固,但还留下了关键的知识伏笔。在逻辑与运算章节中,我们发现 0.1 + 0.2 = 0.30000000000000004 而非预期的 0.3,当时仅知晓是浮点数精度问题,未深究底层原因。

下一节我们将进入一个重要的知识分支——计算机底层进制与编码原理,核心学习:

  1. 掌握二进制、八进制、十进制、十六进制的定义,以及在ArkTS中的表示方法与相互转换技巧;
  2. 理解位(bit)、字节(Byte)、半字节(Nibble)的核心概念,以及它们之间的换算关系;
  3. 彻底搞懂ASCII码的本质、表示形式,以及在ArkTS中的实际应用场景;
  4. 掌握二进制科学计数法的规范化表示,为后续学习浮点数存储标准(IEEE 754)打下基础;
  5. 建立“计算机所有数据均以二进制存储”的核心认知,理解整数、浮点数的存储本质,揭开“0.1 + 0.2 ≠ 0.3”的底层奥秘。

通过下一节的学习,你将打通计算机底层存储的基础逻辑,为后续深入理解数据类型、数值运算精度、编码转换等知识点提供关键支撑,让编程思维从“表面应用”深入到“底层原理”。

posted @ 2026-01-17 11:29  鸿蒙-散修  阅读(0)  评论(0)    收藏  举报