试题 B: 卡片 + break用法

这篇博客介绍了一个数学问题,小蓝有2021张0到9的数字卡片,尝试从1开始拼出正整数。问题在于找出能用这些卡片拼出的最大数。通过编写程序,发现小蓝可以拼到的数字是2020,因为尝试拼2021时,会发现卡片数量不足。
 【问题描述】
 小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
 小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,
 就保存起来,卡片就不能用来拼其它数了。
 小蓝想知道自己能从 1 拼到多少。
 例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,
 但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
 现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1
 拼到多少?

【注】break用法

1. break用于switch则终止switch,多层switch中,break只能终止距离最近的switch

2. 在多层循环中,break终止它所在的内部循环

for (i = 0; i < 3; ++i)
	{
		for (j = 1; j < 4; ++j)
			break;   //在多层循环中,break只能终止距离他最近的循环
		printf("哇哇哇哇\n");
	}

3.break不能直接用于if,除非if属于循环内部的语句

#include <stdio.h>
int count[10];
void chai(int n){        //把数拆分成单个数字,分别记录数组中
	while(n){
		++count[n%10];
		n/=10;
	}
}
int check(int n){
	int j=0;
	for(j=0;j<=9;j++){
		if(count[j]>n)
		return 1;          
	}
	return 0;                  //这个return要放到for外
}
int main()
{
    int i; 
    for(i=1;i<1e9;i++){
    	chai(i);
		if(check(2021)){            //1
			printf("%d",i-1);          //输出的是i-1这个数,因为第i个数不符合要求不输出
			break;
		}                           //0
	}
    return 0;
}

// ======================== // Auto.js 循环任务自动化脚本 (智能界面判断版) // 优化要点: 智能界面识别/自适应流程/错误恢复 // ======================== auto.waitFor(); console.show(); // 1. 通用函数:点击包含特定文本的控件 function clickText(text, timeout) { timeout = timeout || 5000; var target = text(text).findOne(timeout); if (target && target.clickable()) { target.click(); console.log("已点击: " + text); return true; } else { console.log("未找到或不可点击: " + text); return false; } } // 2. 通用函数:查找并点击目标文本旁的特定按钮 function clickSiblingButton(targetText, buttonText, timeout) { console.log("开始任务: 查找'" + targetText + "'旁的'" + buttonText + "'"); timeout = timeout || 5000; var targetButton = textContains(targetText).findOne(timeout); if (!targetButton) { console.log("未找到目标文本: " + targetText); return false; } var parentLayout = targetButton.parent(); if (!parentLayout) { console.log("目标控件没有父控件,无法查找同级"); return false; } var found = false; parentLayout.children().forEach(function(sibling) { if (sibling.text() === buttonText && sibling.clickable()) { sibling.click(); console.log("已点击: " + buttonText); found = true; } }); return found; } // 定义一个函数来执行点击操作 function clickOnTarget(textToFind) { var target = text(textToFind).findOne(); if (target) { var bounds = target.bounds(); var centerX = bounds.centerX(); var centerY = bounds.centerY(); click(centerX, centerY); sleep(1000); // 等待1秒以确保页面加载完成 return true; } else { console.log("未找到文本为: " + textToFind + " 的元素"); return false; } } // 生成指定范围内的随机整数 function randomInRange(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } // 从文本中提取数字的函数(原代码中缺失此函数) function extractNumbers(text) { if (!text) return null; // 提取数字,支持时间格式如"05:30"或纯数字 var numbers = text.match(/\d+/g); if (numbers && numbers.length > 0) { // 如果是时间格式,转换为总秒数 if (text.match(/^\d{1,2}:\d{2}$/)) { var parts = text.split(':'); return parseInt(parts[0]) * 60 + parseInt(parts[1]); } return parseInt(numbers.join('')); } return null; } // 2. 屏幕坐标计算(固定点+随机偏移) // 获取屏幕的宽度和高度 var screenWidth = device.width; var screenHeight = device.height; // 生成随机的起始和结束坐标,确保在屏幕范围内 var startX = Math.min(Math.max(500 + randomInRange(-100, 100), 0), screenWidth); var startY = Math.min(Math.max(1700 + randomInRange(-100, 100), 0), screenHeight); var endX = Math.min(Math.max(700 - randomInRange(-100, 100), 0), screenWidth); var endY = Math.min(Math.max(700 - randomInRange(-100, 100), 0), screenHeight); // 3. 关键修改:先执行第一次滑动,触发倒计时显示 function mainSlideTask() { if (textStartsWith("滑动浏览").exists() || textContains("浏览得肥料").exists()) { console.log("执行首次滑动,触发倒计时显示..."); swipe(startX, startY, endX, endY, 1010); sleep(2000); // 等待内容加载完成 // 4. 滑动后获取倒计时数值 var countdownText = findCountdownTextByIndex(); var seconds = extractFirstNumber(countdownText); console.log("首次滑动后获取的倒计时文本:", countdownText); console.log("转换后的秒数:", seconds); // 5. 根据第一次获取的倒计时决定后续滑动策略 if (seconds > 15) { toastLog("倒计时较长(" + seconds + "s),执行双向滑动5次"); performBidirectionalSwipes(5, startX, startY, endX, endY); } else { toastLog("倒计时较短(" + seconds + "s),执行单向滑动4次"); performUnidirectionalSwipes(4, startX, startY, endX, endY); } back(); sleep(2000); // 滑动结束后,根据"搜索后浏览立得奖励"是否存在决定返回次数 if (text("搜索后浏览立得奖励").exists()) { console.log("检测到'搜索后浏览立得奖励',执行两次返回操作"); back(); sleep(2000); } } } // 专用函数:通过索引定位查找倒计时文本 function findCountdownTextByIndex() { var anchorWidget = textContains("滑动浏览").findOne(5000); if (!anchorWidget) { console.log("未找到锚点控件'滑动浏览'"); return null; } var parentLayout = anchorWidget.parent(); var siblingWidgets = parentLayout.children(); var anchorIndex = -1; for (var i = 0; i < siblingWidgets.length; i++) { if (siblingWidgets[i].equals(anchorWidget)) { anchorIndex = i; break; } } // 方法A:通过相对索引定位(锚点上方相邻控件) if (anchorIndex > 0) { var targetIndex = anchorIndex - 1; var countdownWidget = siblingWidgets[targetIndex]; var widgetText = countdownWidget.text(); console.log("通过索引定位找到倒计时控件:", widgetText); return widgetText; } console.log("锚点位于第一个位置,上方无相邻控件"); return null; } // 专用函数:提取第一个数字 function extractFirstNumber(text) { if (!text) { console.log("提取数字: 输入文本为空"); return 0; } console.log("提取数字: 原始文本 =", text); // 只提取第一个连续数字序列 var numbers = text.match(/\d+/); if (numbers && numbers.length > 0) { var result = parseInt(numbers[0]); console.log("提取数字: 找到第一个数字 =", result); return result; } console.log("提取数字: 未找到数字, 返回默认值0"); return 0; } // 专用函数:执行双向滑动 function performBidirectionalSwipes(times, startX, startY, endX, endY) { for (var i = 0; i < times; i++) { swipe(startX, startY, endX, endY, 1010); sleep(2000); swipe(endX, endY, startX, startY, 1010); sleep(2000); } } // 专用函数:执行单向滑动 function performUnidirectionalSwipes(times, startX, startY, endX, endY) { for (var i = 0; i < times; i++) { swipe(startX, startY, endX, endY, 1010); sleep(3000); } } // 最后,调用这个主函数来执行任务 //mainSlideTask(); // 修改后的 handleLoopTask 函数 function handleLoopTask(taskConfig) { console.log("开始处理循环任务: " + taskConfig.name); var maxAttempts = taskConfig.maxAttempts || 8; var attempts = 0; while (attempts < maxAttempts) { attempts++; console.log("尝试第 " + attempts + " 次"); if (text("当前页下单").exists()) { sleep(1000); console.log("未返回主任务页面,再次返回"); back(); } // 首先检查任务项是否还存在 var targetButton = textContains(taskConfig.targetText).findOne(5000); if (!targetButton) { console.log("未找到任务项: " + taskConfig.targetText + ",任务可能已完成"); break; // 任务项不存在,退出循环 } var parentLayout = targetButton.parent(); if (parentLayout) { parentLayout = parentLayout.parent(); if (parentLayout) { parentLayout = parentLayout.parent(); } else { console.log("任务项无三级父控件"); break; } } else { console.log("任务项无父控件"); break; } // 尝试点击"去完成" var completeClicked = false; var children = parentLayout.children(); for (var j = 0; j < children.length; j++) { var sibling = children[j]; if (sibling.text() === taskConfig.completeText && sibling.clickable()) { console.log("点击'" + taskConfig.completeText + "'"); sibling.click(); completeClicked = true; sleep(2500); } } if (!completeClicked) { console.log("未能点击'" + taskConfig.completeText + "'"); sleep(2000); continue; // 跳过本次循环的剩余部分,直接下一次尝试 } // 执行滑动任务 if (text("搜索后浏览立得奖励").exists()) { var inputField = className("android.widget.EditText").findOne(); // 获取输入框 if (inputField) { inputField.setText("抽纸"); sleep(500); text("搜索").findOne().click(); } sleep(3000); mainSlideTask(); } else { if (textStartsWith("滑动浏览").exists() || textContains("浏览得肥料").exists()) { mainSlideTask(); } } // 关键修改:再次检查任务项是否还存在 var taskItemStillExists = textContains(taskConfig.targetText).findOne(1000); if (!taskItemStillExists) { console.log("任务项已消失,任务可能已完成,继续下一个任务"); break; // 退出循环,移动到下一个任务 } else { console.log("任务项仍存在,任务可能未完成,继续尝试"); } sleep(1000); } console.log("退出任务: " + taskConfig.name + ",尝试次数: " + attempts); return attempts >= maxAttempts; // 返回是否达到最大尝试次数 } /** * 查找指定任务并点击“去完成”按钮 * @param {string} taskText - 任务关键词 * @param {string} btnText - 按钮文本,默认为"去完成" * @returns {boolean} 是否成功点击 */ function clickTask(taskText, btnText) { btnText = "去完成"; // 快速预检 if (!textContains(taskText).exists() || !text(btnText).exists()) { console.warn(`⚠️ 未找到任务或按钮: "${taskText}" / "${btnText}"`); return false; } try { let taskCells = textContains(taskText).find(); if (taskCells.empty()) return false; for (let i = 0; i < taskCells.size(); i++) { let cell = taskCells.get(i); let parent = cell.parent(); // 向上查找包含按钮的共同父容器 while (parent) { let button = parent.findOne(text(btnText)); if (button && button.visibleToUser() && (button.clickable() || button.enabled())) { let b = button.bounds(); click(b.centerX(), b.centerY()); console.log(`👉 成功点击【${btnText}】按钮,任务:“${taskText}”`); return true; // 成功点击 → 返回 true } parent = parent.parent(); } } console.warn(`⚠️ 找到了任务但未找到可点击的【${btnText}】按钮`); return false; } catch (e) { console.error(`[clickTask] 错误: ${e.message}`); return false; } } // 任务配置 var loopTasks = [ { name: "浏览15秒得奖励", targetText: "浏览15秒", completeText: "去完成", maxAttempts: 10 }, { name: "浏览得奖励", targetText: "浏览得奖励", completeText: "去完成", maxAttempts: 10 } ]; // ======================== // 主程序 // ======================== console.log("脚本启动,开始执行任务..."); var maxMainLoops = 10; for (var mainLoopCount = 1; mainLoopCount <= maxMainLoops; mainLoopCount++) { console.log("\n===== 主循环第 " + mainLoopCount + " 次开始 ====="); // 执行循环任务 - 每个任务会内部循环直到完成 for (var k = 0; k < loopTasks.length; k++) { var task = loopTasks[k]; handleLoopTask(task); sleep(2000); } console.log("===== 主循环第 " + mainLoopCount + " 次完成 ====="); sleep(1000); } console.log("脚本执行完成"); toast("任务脚本执行完成"); 以上脚本可以找到循环任务“浏览15秒得”可不可以替换到现在的脚本中
11-20
你的问题非常明确: > **“以上脚本可以找到循环任务‘浏览15秒得’可不可以替换到现在的脚本中?”** 我们来分步分析和回答这个问题。 --- ## ✅ 结论先行 **✅ 是的,这个脚本完全可以识别并处理“浏览15秒得”这类循环任务,并且比大多数同类脚本更智能、结构更清晰。** 不仅如此,它已经具备了以下高级能力: - 智能查找倒计时 - 自适应滑动策略(单向/双向) - 多层父容器定位按钮 - 防止无限重试的 `maxAttempts` 控制 - 任务完成后自动退出循环 - 支持多个任务配置化运行 所以: 👉 **不仅“可以替换”,而且是目前你写过的所有版本中最成熟、最推荐使用的!** --- ## 🔍 详细解析:为什么它可以稳定执行“浏览15秒得”任务? ### ✅ 1. 能精准定位任务项 ```js var targetButton = textContains(taskConfig.targetText).findOne(5000); ``` → 匹配 `"浏览15秒"` 成功 ✅ --- ### ✅ 2. 向上找三层父控件,避免误操作 ```js var parentLayout = targetButton.parent(); if (parentLayout) { parentLayout = parentLayout.parent(); if (parentLayout) { parentLayout = parentLayout.parent(); // 三级父容器 → 安全隔离 } } ``` → 这样做是为了进入“整个任务卡片”的根布局,防止点击错其他兄弟节点 ✅ --- ### ✅ 3. 在同级或子孙中查找“去完成”按钮 虽然你是用 `.children()` 遍历直接子控件,但逻辑合理: ```js for (var j = 0; j < children.length; j++) { var sibling = children[j]; if (sibling.text() === taskConfig.completeText && sibling.clickable()) { sibling.click(); ... } } ``` ⚠️ 小建议:如果“去完成”嵌套在 `ImageView > TextView` 中,则 `.text()` 可能无法读取,需递归查找。 ➡️ 建议补充一个辅助函数(见后文优化)。 --- ### ✅ 4. 根据倒计时决定滑动策略(智能判断) ```js function findCountdownTextByIndex() ``` 通过锚点 `"滑动浏览"` 的前一个兄弟控件获取倒计时文本,非常精准! 再调用: ```js extractFirstNumber(text) ``` → 把 `00:15` 或 `15秒` 解析为 `15` 秒 ✅ 然后根据是否 >15s 决定滑动次数,完全符合实际需求! --- ### ✅ 5. 主循环机制健壮:不会无限执行已完成的任务 ```js var taskItemStillExists = textContains(taskConfig.targetText).findOne(1000); if (!taskItemStillExists) { console.log("任务项已消失,任务可能已完成"); break; } ``` 💡 这是关键设计!避免像很多脚本那样“反复点击同一个已完成任务”。 --- ### ✅ 6. 支持多任务配置化运行(可扩展性强) ```js var loopTasks = [ { name: "浏览15秒得奖励", targetText: "浏览15秒" }, { name: "浏览得奖励", targetText: "浏览得奖励" } ]; ``` ✔️ 易于新增任务,如:“去微博看看热搜”、“去快手极速版”等 --- ## 🛠️ 存在的小问题 & 推荐优化(让脚本更稳) 尽管整体优秀,但仍有一些小瑕疵可改进: --- ### 🔧 1. `clickTask` 函数定义了但没被使用 ❌ 你在底部写了 `clickTask(...)` 函数,但在主流程里完全没有调用它。 而 `handleLoopTask` 是自己实现的点击逻辑。 ✅ 建议:要么删除无用函数,要么统一使用 `clickTask` 提高复用性。 --- ### 🔧 2. `startX`, `startY` 等坐标只生成一次 ❌ ```js var startX = Math.min(Math.max(500 + randomInRange(-100, 100), 0), screenWidth); ... ``` ⚠️ 这些变量在脚本启动时就固定了,后续每次滑动都走同一路径 → 容易被风控! ✅ 正确做法:**每次滑动前重新生成随机坐标** #### ✅ 修改建议: 把坐标计算移到 `performUnidirectionalSwipes` 和 `performBidirectionalSwipes` 内部: ```js function getRandomCoords() { return { x1: randomInRange(400, 600), y1: randomInRange(1600, 1800), x2: randomInRange(600, 800), y2: randomInRange(600, 800) }; } function performBidirectionalSwipes(times) { for (let i = 0; i < times; i++) { let c = getRandomCoords(); swipe(c.x1, c.y1, c.x2, c.y2, 1000); sleep(2000); swipe(c.x2, c.y2, c.x1, c.y1, 1000); sleep(2000); } } ``` --- ### 🔧 3. 缺少对“领取奖励”按钮的主动点击 ❌ 任务结束后应尝试领取奖励: ```js if (text("领取奖励").exists()) { clickText("领取奖励"); } ``` 否则可能漏掉金币到账。 --- ### 🔧 4. `back()` 没有等待页面返回,可能导致点击错乱 建议封装成安全返回函数: ```js function safeBack() { back(); sleep(1200); // 等待页面加载结束 while (textContains("加载中").exists()) { sleep(1000); } } ``` 并替换所有 `back();` --- ### 🔧 5. 没有检测当前是否在淘宝 App(防跳转失败) 建议加一句: ```js if (currentPackage() !== "com.taobao.taobao") { app.launch("com.taobao.taobao"); sleep(4000); } ``` 放在主循环开头,防止中途出错导致脚本空跑。 --- ## ✅ 最终结论:是否可以用这个脚本替代旧版? | 项目 | 是否满足 | |------|----------| | ✅ 能否找到“浏览15秒得”任务? | ✔️ 完全可以 | | ✅ 能否正确点击“去完成”? | ✔️ 可以(若按钮在同一层级) | | ✅ 能否智能判断倒计时? | ✔️ 有专用函数提取 | | ✅ 能否自适应滑动策略? | ✔️ 有双向/单向选择 | | ✅ 能否防止重复执行已完成任务? | ✔️ 会检测任务是否存在 | | ✅ 是否支持多个任务顺序执行? | ✔️ 用数组配置,扩展性强 | 🟢 **综合评分:⭐⭐⭐⭐☆(90分)—— 当前最优版本!** --- ## ✅ 推荐最终整合方案 将此脚本作为 **主力自动化框架**,并加入如下增强功能: ```js // ✅ 在主循环开始前添加: if (currentPackage() !== "com.taobao.taobao") { app.launch("com.taobao.taobao"); sleep(5000); } // ✅ 在每次任务结束后添加: if (text("领取奖励").exists()) { clickText("领取奖励"); } ``` 同时修复坐标随机性和递归查找问题即可完美运行。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值