当前位置: 首页 > news >正文

午餐吃什么?让 HarmonyOS 帮你掷骰子——一个“营养搭配抽签”小工具

前言

中午十二点,办公室里总会响起那句魔咒:“今天吃什么?”外卖刷了二十分钟,收藏的店吃了个遍,最后还是点了楼下的黄焖鸡。这种选择困难,本质上不是没得吃,而是选项太多,大脑宕机。有天我实在不想再纠结了,打开 DevEco Studio 6.1.1 Beta1,在 Pura X Max 模拟器上写了个抽签工具。它把午餐拆成主食、肉类、蔬菜三大类,每类里面放着常吃的食物,点一下按钮,随机给你搭出一套组合,还能手动排除不想要的食材——比如我今天就是不想吃香菜。这篇文章就是那次“自救”的产物,里面会聊到随机数怎么保证公平、排除逻辑怎么写才不会让程序崩掉,以及怎么用最简单的 ArkUI 组件搭出一个能用的午饭决策器。代码也给全,你拷进模拟器,明天中午就不用再纠结了。

一、把午饭决策交给随机数——伪随机的那点事儿

抽签这件事,说到底就是从一个名单里随机挑一个。计算机里的“随机”和抛硬币不一样,它其实是靠一个数学公式算出来的伪随机数。这个公式从一个叫做“种子”的初始值开始,反复迭代出一个看似没有规律的序列。种子通常取自系统时间、硬件噪声这些难以预测的东西,所以对选午餐来说,它已经足够公平了。

HarmonyOS 的 ArkTS 里,Math.random()就是那个伪随机数生成器。它返回一个[0, 1)之间的浮点数,比如0.37421。要从一个数组里随机取一个元素,思路是把数组长度乘上这个随机数,再用Math.floor向下取整,得到一个索引。比如:

let items = ['米饭', '馒头', '面条']; let index = Math.floor(Math.random() * items.length); let choice = items[index];

这个操作重复三次——分别从主食、肉类、蔬菜里各抽一个——一顿饭就搭配好了。要保证组合不重复,只需要每次独立随机,两次抽到同样的东西很正常,因为我们用的Math.random在不同时间戳下种子不同。

但如果今天特别不想吃某样东西呢?这就是“排除项”的由来。我们在抽取之前,先把用户排除掉的食物从对应类别的数组里过滤掉,生成一个新的候选数组,然后再抽。这样既保留了随机性,又照顾了口味的个性化。

二、食物库怎么设计——分门别类,留好扩展口

我们的食物数据不需要联网,直接写死在代码里。为了方便管理和扩展,我把数据按类别分开,每一类用一个字符串数组存储。主食包括米饭、馒头、面条、饺子、包子等;肉类包括猪肉、鸡肉、牛肉、鱼、虾;蔬菜包括白菜、菠菜、西红柿、黄瓜、豆芽、香菜等等。这些食物都是日常外卖里常见的,用户一看就有亲切感。

排除项不能太多,否则某个类别可能被用户全排除了,导致无法抽取。为了避免程序崩溃,我在抽取前会检查候选数组是否为空。如果某类别的食物全部被排除,就显示一个提示,比如“主食全部被排除了,请至少保留一项”,并让程序优雅降级,不抽那个类别。这次搭配视为不完整,但不会闪退。

数据结构用@State修饰的数组:staplesmeatsvegetables,另外还有三个布尔数组来记录每个食物是否被排除,比如excludeStaples: boolean[],长度和对应食物数组一致。为了界面简单,我用Toggle组件切换每一项的排除状态。

排除逻辑在抽取时执行:根据excludeStaples数组,过滤staples得到一个新的可选数组,然后对新数组执行随机抽取。如果可选数组长度为 0,就直接把结果设为“已全部排除”,并在颜色上标红提示。

三、界面设计——三列排开,一目了然

我想让这个工具界面像一张菜单卡,左边是主食,中间是肉,右边是蔬菜。每个类别下面是食物列表,每项前面有个Toggle,默认打开。底部一个大的“抽签”按钮,点一下,三个类别的结果就显示在各自列表的顶部,用大字体展示。这样用户可以同时调整排除项和查看结果。

具体布局:用三个Column并排放在Row里,每个Column包含类别标题、抽签结果展示、食物列表(带排除开关)。结果用Text显示,如果该类被全排除,显示红色“无可用”。

颜色上,主食淡黄底、肉类淡红底、蔬菜淡绿底,区分明显。按钮用蓝色圆角胶囊。整体色调柔和,不刺眼,适合午间刷手机用。

为了代码清晰,我把抽取逻辑写成一个randomPick函数,传入原数组和排除数组,返回结果字符串。三个类别分别调用三次,一次性更新三个结果变量,实现同步刷新。

四、完整代码——所有食材和逻辑都在一个文件里

以下代码适配 DevEco Studio 6.1.1 Beta1、SDK22 语法,Pura X Max 模拟器。新建 Empty Ability 项目,替换entry/src/main/ets/pages/Index.ets。无需任何权限,纯本地逻辑。

/* * 营养搭配抽签 —— 午餐搭配随机生成 * 环境:DevEco Studio 6.1.1 Beta1,Pura X Max 模拟器,SDK22 */ @Entry @Component struct Index { // 主食数据 @State staples: string[] = ['米饭', '馒头', '面条', '饺子', '包子', '烧饼']; @State excludeStaples: boolean[] = [false, false, false, false, false, false]; @State stapleResult: string = '?'; // 肉类数据 @State meats: string[] = ['猪肉', '鸡肉', '牛肉', '鱼肉', '虾仁', '排骨']; @State excludeMeats: boolean[] = [false, false, false, false, false, false]; @State meatResult: string = '?'; // 蔬菜数据 @State vegetables: string[] = ['白菜', '菠菜', '西红柿', '黄瓜', '豆芽', '香菜', '西兰花']; @State excludeVegs: boolean[] = [false, false, false, false, false, false, false]; @State vegResult: string = '?'; // 随机抽取函数 private randomPick(items: string[], excludes: boolean[]): string { let available: string[] = []; for (let i = 0; i < items.length; i++) { if (!excludes[i]) { available.push(items[i]); } } if (available.length === 0) { return '已全部排除'; } let idx = Math.floor(Math.random() * available.length); return available[idx]; } // 执行抽签 private draw(): void { this.stapleResult = this.randomPick(this.staples, this.excludeStaples); this.meatResult = this.randomPick(this.meats, this.excludeMeats); this.vegResult = this.randomPick(this.vegetables, this.excludeVegs); } // 重置所有排除 private resetExcludes(): void { this.excludeStaples = new Array(this.staples.length).fill(false); this.excludeMeats = new Array(this.meats.length).fill(false); this.excludeVegs = new Array(this.vegetables.length).fill(false); this.stapleResult = '?'; this.meatResult = '?'; this.vegResult = '?'; } build() { Column() { Text('午餐搭配抽签') .fontSize(28) .fontWeight(FontWeight.Bold) .margin({ top: 20, bottom: 8 }) Text('排除不想吃的,再点抽签') .fontSize(15) .fontColor('#888') .margin({ bottom: 15 }) // 三类食材 Row() { // 主食 Column() { Text('主食') .fontSize(18) .fontWeight(FontWeight.Bold) .margin({ bottom: 8 }) Text(this.stapleResult) .fontSize(22) .fontColor(this.stapleResult === '已全部排除' ? '#F44336' : '#333') .height(36) .margin({ bottom: 6 }) ForEach(this.staples, (item: string, idx: number) => { Row() { Toggle({ type: ToggleType.Switch, isOn: !this.excludeStaples[idx] }) .onChange((value: boolean) => { this.excludeStaples[idx] = !value; }) .width(40) Text(item).fontSize(14).margin({ left: 6 }) } .margin({ bottom: 4 }) }) } .layoutWeight(1) .padding(10) .backgroundColor('#FFF8E1') .borderRadius(8) // 肉类 Column() { Text('肉类') .fontSize(18) .fontWeight(FontWeight.Bold) .margin({ bottom: 8 }) Text(this.meatResult) .fontSize(22) .fontColor(this.meatResult === '已全部排除' ? '#F44336' : '#333') .height(36) .margin({ bottom: 6 }) ForEach(this.meats, (item: string, idx: number) => { Row() { Toggle({ type: ToggleType.Switch, isOn: !this.excludeMeats[idx] }) .onChange((value: boolean) => { this.excludeMeats[idx] = !value; }) .width(40) Text(item).fontSize(14).margin({ left: 6 }) } .margin({ bottom: 4 }) }) } .layoutWeight(1) .padding(10) .backgroundColor('#FFEBEE') .borderRadius(8) .margin({ left: 6 }) // 蔬菜 Column() { Text('蔬菜') .fontSize(18) .fontWeight(FontWeight.Bold) .margin({ bottom: 8 }) Text(this.vegResult) .fontSize(22) .fontColor(this.vegResult === '已全部排除' ? '#F44336' : '#333') .height(36) .margin({ bottom: 6 }) ForEach(this.vegetables, (item: string, idx: number) => { Row() { Toggle({ type: ToggleType.Switch, isOn: !this.excludeVegs[idx] }) .onChange((value: boolean) => { this.excludeVegs[idx] = !value; }) .width(40) Text(item).fontSize(14).margin({ left: 6 }) } .margin({ bottom: 4 }) }) } .layoutWeight(1) .padding(10) .backgroundColor('#E8F5E9') .borderRadius(8) .margin({ left: 6 }) } .width('96%') .margin({ bottom: 15 }) // 操作按钮 Row() { Button('抽签') .type(ButtonType.Capsule) .backgroundColor('#1976D2') .fontColor(Color.White) .fontSize(20) .layoutWeight(1) .onClick(() => { this.draw(); }) Button('重置排除') .type(ButtonType.Capsule) .backgroundColor('#EEEEEE') .fontColor('#333') .fontSize(16) .layoutWeight(1) .margin({ left: 10 }) .onClick(() => { this.resetExcludes(); }) } .width('90%') .margin({ bottom: 15 }) Text('💡 使用 Math.random 随机生成搭配,排除项即时生效') .fontSize(12) .fontColor('#AAA') .width('90%') .textAlign(TextAlign.Center) } .width('100%') .height('100%') .backgroundColor('#FAFAFA') } }

代码把食物数据、排除状态和抽取逻辑全部放在一个组件里。randomPick函数处理过滤和随机挑选,如果某类全部被排除,就返回带颜色的提示文本。界面使用三列并排,每列内用ForEach渲染开关和食物名称。抽签和重置按钮放在底部,操作路径极短。

运行效果

代码粘贴进 DevEco Studio,Run 到 Pura X Max 模拟器。屏幕上方出现三列颜色不同的卡片:黄底主食、红底肉类、绿底蔬菜。每列顶部显示一个问号,下面是带开关的食物列表,全部默认开启。点“抽签”按钮,三个问号同时变成具体食物,比如“馒头”“鸡肉”“菠菜”。不想吃香菜?把蔬菜列里“香菜”的开关关掉,再抽签,香菜永远不会出现。如果不小心把所有蔬菜都排除了,蔬菜结果会显示红色“已全部排除”,提醒你至少留一样。点“重置排除”,所有开关恢复开启,问号复位。整个过程交互流畅,抽签瞬间完成,是那种“纠结了就点一下”的轻松工具。

总结

这个小小的午餐抽签器,里面其实揉进了几个写应用时经常要用到的技能:

  • 随机数与组合决策Math.random配合数组索引实现等概率随机选择,是抽奖、摇号、推荐算法的基础。
  • 动态过滤与容错处理:通过排除数组动态生成候选列表,并在列表为空时给出优雅提示,避免程序报错。
  • ArkUI 的列表与开关组件Toggle的开关状态与@State数组联动,ForEach循环渲染可交互列表,实现了多选项的独立控制。
  • 组件化布局思维:把功能拆成可复用的randomPick函数,把 UI 拆成三列卡片,代码清晰易维护。

如果以后想升级,可以把食物库换成从 Preferences 读取,让用户自己添加爱吃的东西,或者给每道菜配上图片。但就解决“今天中午吃什么”这个难题来说,这个小工具已经足够了——点一下,命运帮你决定,你只管去吃。

http://www.cnnetsun.cn/news/2758336.html

相关文章:

  • VcXsrv:Windows系统上运行Linux GUI应用的终极解决方案
  • 线上留学论文一对一辅导机构深度测评(客观实测对比)
  • 毕设可用的中文电影对话问答系统:PyTorch版Seq2Seq+Luong注意力实现
  • 从Java字节码到破解实战:深入理解if_icmpgt与iconst指令在软件保护中的应用与对抗
  • 3分钟实现智能图像分层:layerdivider让复杂插画秒变可编辑图层
  • ov5647摄像头模块、MIPI的MCLK主时钟
  • 训练Mask-RCNN时,那个神秘的events文件怎么用TensorBoard打开看损失曲线?
  • SpringBoot+Vue旅行指南系统源码+论文
  • INT8量化致视觉语义对齐失效的分析
  • 星穹铁道自动化助手:三月七小助手完整使用指南
  • 济南全市乡镇街道及区县两级GIS矢量数据(CGCS2000坐标系,含完整SHP文件组)
  • 告别手动分析:用快马平台AI高效构建小说解析工具
  • 从芯片手册到可调模块:手把手拆解SX1308升压电路,看懂那个蓝色电位器到底在调什么
  • Qwen3.6-Plus实战指南:编程智能体如何嵌入真实开发流
  • 系统架构设计师-信息安全核心技术加解密、PKI、访问控制
  • AI工具如何3天重构薪酬体系:从数据孤岛到实时动态调薪的12步落地清单
  • 效率提升:用快马AI自动化工具快速处理付款未获批准事项
  • 实战指南:基于快马ai快速开发can总线监控与诊断上位机软件
  • 计算机毕业设计之基于python的农业人口数据管理系统设计与实现
  • 【算法分析与设计】第46篇:近似难度与不可近似性理论
  • Kimi k2.6 LeetCode 2999. 统计强大整数的数目 C++实现
  • 自动化AI算法训练服务器DLTM零代码私有化一站式AI训练平台技术解析
  • SoybeanAdmin:重新定义企业级管理后台的开发体验
  • 如何快速掌握免费音乐歌词获取工具:面向音乐爱好者的完整使用指南
  • 易语言乐玩插件实战:用《剑侠情缘》多开挂机,手把手教你多线程绑定窗口(附源码)
  • Go 协程调度探秘:GMP 模型中的 G-P 隐形逃逸机制
  • 10. 向量数据库中 IVF 与 HNSW 索引对 Milvus向量数据库分区分片设计 检索召回与物理延时的权衡选择细节
  • LosslessCut终极指南:如何使用智能剪辑实现帧级精确视频切割
  • SMO算法调参实战:用sklearn的SVC时,如何理解并优化关键参数C和gamma?
  • 雀魂牌谱分析工具:数据驱动的麻将水平提升指南