js:锄地一条龙2.5.0 (#2934)

* Create 搜索成功点击.png

补充模板图片

* 微调路线选择算法

修改后只有一个参数,且对结果影响更加平滑可控
This commit is contained in:
mno
2026-02-26 18:22:50 +08:00
committed by GitHub
parent 310363a4a4
commit 3060c77529
5 changed files with 54 additions and 67 deletions

View File

@@ -24,7 +24,7 @@
### 一、**快速使用指南 ✅**
1. 添加脚本
在 BGI 配置组中点击 +添加 → 选择 “锄地一条龙”脚本。不要直接运行js
在 BGI 配置组中点击 +添加 → 选择 “锄地一条龙”脚本。不要直接在调度器外运行。
2. 配置组设置(⚙️)
- ⚠️ 关键设置,请务必检查!
@@ -160,8 +160,7 @@
- - 环境伤害 :路线处于雪山或挪德卡莱苦壑崖区域,环境伤害会持续扣血
- - 分组逻辑不含路径组1排除标签和任何其他组标签的路径会进入路径组1剩余路径若含有路径组x的标签之一则会进入路径组x
- - 新增支持自定义标签将会尝试将未知的标签通过文件路径description匹配含有对应关键词的路线即视为含有这些标签
- **路线效率计算权重** 影响js评估路线价值计算公式如下,权重越大越看重总收益
- $$ 怪均^k \times 秒均 $$
- **摩拉/耗时权衡因数** 影响js评估路线价值含义为为了多赚1摩拉愿意多花多少秒
- **自动优化:** js将根据运行记录调整每条路线的预期运行时间具体逻辑为至多7条记录去除一个最大值、一个最小值后每条记录占据20%的权重,剩余权重由默认数据填充。如果你不想要这个功能,请禁用。
- **目标数量:** 选取路线目标达到的精英怪数量默认为400同理小怪数量默认为2000
- **优先关键词:** 含有关键词的路线会被视为拥有最高效率例如填写600来让所有600怪物优先考虑填写骗骗花来优先考虑骗骗花

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,4 +1,4 @@
//当前js版本2.2.1
//当前js版本2.5.0
//自定义配置变量预声明
let accountName;
@@ -14,8 +14,7 @@ let timeMoveDown;
let priorityTags;
let excludeTags;
let operationMode;
let k1;
let k2;
let efficiencyIndex;
let targetEliteNum;
let targetMonsterNum;
let partyName;
@@ -88,7 +87,7 @@ let currentFood = "";
//按照用户配置标记路线
await markPathings(pathings, groupTags, priorityTags, excludeTags);
//找出最优组合
await findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonsterNum);
await findBestRouteGroups(pathings, efficiencyIndex, targetEliteNum, targetMonsterNum);
//分配到不同路径组
await assignGroups(pathings, groupTags);
@@ -145,8 +144,7 @@ async function loadConfig() {
tagsForGroup9: settings.tagsForGroup9 || '',
tagsForGroup10: settings.tagsForGroup10 || '',
disableSelfOptimization: settings.disableSelfOptimization ?? false,
eEfficiencyIndex: settings.eEfficiencyIndex ?? 2.5,
mEfficiencyIndex: settings.mEfficiencyIndex ?? 0.5,
efficiencyIndex: settings.efficiencyIndex ?? 2.5,
curiosityFactor: settings.curiosityFactor ?? '0',
ignoreRate: settings.ignoreRate ?? 0,
targetEliteNum: settings.targetEliteNum ?? 400,
@@ -209,11 +207,11 @@ async function loadConfig() {
log.warn("拾取模式不是模板匹配,无法处理沙暴路线,自动排除所有沙暴路线");
}
k1 = +settings.eEfficiencyIndex || 2.5;
k1 = Math.max(0, Math.min(10, Number.isNaN(k1) ? 2.5 : k1));
k2 = +settings.mEfficiencyIndex || 0.5;
k2 = Math.max(0, Math.min(4, Number.isNaN(k2) ? 0.5 : k2));
efficiencyIndex = settings.efficiencyIndex === undefined ? 0.25 :
isNaN(Number(settings.efficiencyIndex)) ||
String(Number(settings.efficiencyIndex)) !== String(settings.efficiencyIndex) ? 0.25 :
Number(settings.efficiencyIndex) < 0 ? 0 :
Number(settings.efficiencyIndex);
targetEliteNum = Math.max(0, +settings.targetEliteNum || 400) + 5; // 预留漏怪
targetMonsterNum = Math.max(0, +(settings.targetMonsterNum ?? 2000)) + 25; // 预留漏怪
@@ -483,7 +481,7 @@ async function markPathings(pathings, groupTags, priorityTags, excludeTags) {
* 返回pathings[] 各元素新增 selectedbool及排序
* 依赖pathings已含 mora_e/mora_m/t/e/available/prioritized
*/
async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonsterNum) {
async function findBestRouteGroups(pathings, efficiencyIndex, targetEliteNum, targetMonsterNum) {
log.info("开始根据配置寻找路线组合");
/* ========== 0. 原初始化不动 ========== */
let nextTargetEliteNum = targetEliteNum;
@@ -495,30 +493,41 @@ async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonst
let totalTimeCombined = 0;
let monsterRouteElite = 0;
let maxE1 = 0, maxE2 = 0;
const ratio = targetEliteNum / Math.max(targetMonsterNum, 1); // 防 0
const f = (Number((1 - Math.exp(-ratio * ratio)).toFixed(3)) + 1) / 2;
let maxE1 = -Infinity, maxE2 = -Infinity;
let minE1 = Infinity, minE2 = Infinity;
pathings.forEach(p => {
p.selected = false;
const G1 = p.mora_e + p.mora_m, G2 = p.mora_m;
p.G1 = G1; p.G2 = G2;
/* 收益 */
const eliteGain = p.e === 0 ? 200 : (G1 - G2) / p.e;
const normalGain = p.m === 0 ? 40.5 : G2 / p.m;
if (p.e !== 0) {
p.E1 = (efficiencyIndex * p.mora_e - p.t) / p.e;
} else {
p.E1 = null;
}
p.E1 = (eliteGain ** k1) * (G1 / p.t);
if (p.e === 0) p.E1 = 0;
if (p.m !== 0) {
p.E2 = (efficiencyIndex * p.mora_m - p.t) / p.m;
} else {
p.E2 = null;
}
p.E2 = (normalGain ** k2) * (G2 / p.t);
maxE1 = Math.max(maxE1, p.E1);
maxE2 = Math.max(maxE2, p.E2);
if (p.e !== 0) maxE1 = Math.max(maxE1, p.E1);
if (p.m !== 0) maxE2 = Math.max(maxE2, p.E2);
if (p.e !== 0) minE1 = Math.min(minE1, p.E1 ?? Infinity);
if (p.m !== 0) minE2 = Math.min(minE2, p.E2 ?? Infinity);
});
pathings.forEach(p => {
if (p.prioritized) { p.E1 += maxE1; p.E2 += maxE2; }
if (p.e === 0) {
p.E1 = minE1 - 1;
}
if (p.m === 0) {
p.E2 = minE2 - 1;
}
if (p.prioritized) {
p.E1 += (maxE1 - minE1 + 2);
p.E2 += (maxE2 - minE2 + 2);
}
});
/* ========== 1. 原两轮选择逻辑照搬,只是去掉“提前 break” ========== */
@@ -529,12 +538,12 @@ async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonst
pathings.sort((a, b) => b.E1 - a.E1);
for (const p of pathings) {
if (p.E1 > 0 && p.available &&
if (p.e > 0 && p.available &&
(totalSelectedElites + p.e <= targetEliteNum + 2)) { // 留一点余量
p.selected = true;
totalSelectedElites += p.e;
totalSelectedMonsters += p.m;
totalGainCombined += p.G1;
totalGainCombined += p.mora_e + p.mora_m;
totalTimeCombined += p.t;
}
}
@@ -544,12 +553,12 @@ async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonst
monsterRouteElite = 0;
pathings.sort((a, b) => b.E2 - a.E2);
for (const p of pathings) {
if (p.E2 > 0 && p.available && !p.selected &&
if (p.m > 0 && p.available && !p.selected &&
(totalSelectedMonsters + p.m < targetMonsterNum + 5)) {
p.selected = true;
totalSelectedElites += p.e; monsterRouteElite += p.e;
totalSelectedMonsters += p.m;
totalGainCombined += p.G2;
totalGainCombined += p.mora_m;
totalTimeCombined += p.t;
}
}
@@ -576,22 +585,14 @@ async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonst
}
/* ========== 3. 最小不可再减集合(贪心逆筛,不碰优先路线) ========== */
// 1. 只留非优先的已选路线,按性价比升序排
// 1. 只留非优先的已选路线,按E1升序、E2升序排差的先删
const selectedList = pathings
.filter(p =>
p.selected &&
!p.prioritized &&
!p.tags.includes('精英高收益')
)
.sort((a, b) => {
const score = p => {
const eliteGain = p.e === 0 ? 200 : (p.G1 - p.G2) / p.e;
const normalGain = p.m === 0 ? 40.5 : p.G2 / p.m;
const perSec = p.t === 0 ? 0 : p.G1 / p.t;
return ((eliteGain / 200) ** k1 + (normalGain / 40.5) ** k2) * perSec;
};
return score(a) - score(b); // 升序:差的先删
});
.sort((a, b) => a.E1 - b.E1 || a.E2 - b.E2);
// 2. 试删
for (const p of selectedList) {
@@ -602,7 +603,7 @@ async function findBestRouteGroups(pathings, k1, k2, targetEliteNum, targetMonst
p.selected = false;
totalSelectedElites = newE;
totalSelectedMonsters = newM;
totalGainCombined -= p.G1;
totalGainCombined -= p.mora_e + p.mora_m;
totalTimeCombined -= p.t;
}
}
@@ -802,7 +803,7 @@ async function validateTeamAndConfig() {
/**
* 调试-分组汇总打印
* 仅统计 group=1..10 且 selected 的路线,累加精英数、小怪数、总收益(G1)与总时长
* 仅统计 group=1..10 且 selected 的路线,累加精英数、小怪数、总收益与总时长
* 输出每组的路线条数、精英/小怪数量、预计收益(摩拉)与预计用时(时:分:秒)
* 用于“调试路线分配”模式快速核对各组工作量
* 将汇总结果写入 调试结果/路线分配结果.txt 文件
@@ -833,7 +834,7 @@ async function printGroupSummary() {
for (const p of groupPath) {
elites += p.e || 0;
monsters += p.m || 0;
gain += p.G1 || 0;
gain += p.mora_e + p.mora_m || 0;
time += p.t || 0;
ignoredElites += (p.original_e || 0) - (p.e || 0);
}
@@ -896,8 +897,7 @@ async function printGroupSummary() {
// 其他配置信息
resultText += "配置参数:\n";
resultText += ` 精英效率指数: ${settings.eEfficiencyIndex || 2.5}\n`;
resultText += ` 小怪效率指数: ${settings.mEfficiencyIndex || 0.5}\n`;
resultText += ` 摩拉/耗时权衡因数: ${settings.efficiencyIndex || 2.5}\n`;
resultText += ` 好奇系数: ${settings.curiosityFactor || 0}\n`;
resultText += ` 忽略比例: ${settings.ignoreRate || 0}\n`;
resultText += ` 目标精英数: ${settings.targetEliteNum || 400}\n`;
@@ -1616,7 +1616,7 @@ async function processPathingsByGroup(pathings, accountName) {
if (pathing.group === targetGroup) {
totalElites += pathing.e || 0; // 精英怪数量
totalMonsters += pathing.m || 0; // 小怪数量
totalGain += pathing.G1 || 0; // 收益
totalGain += pathing.mora_e + pathing.mora_m || 0; // 收益
totalEstimatedTime += pathing.t || 0; // 预计时间
}
}
@@ -1638,13 +1638,7 @@ async function processPathingsByGroup(pathings, accountName) {
const groupStartTime = new Date();
let remainingEstimatedTime = totalEstimatedTime;
let skippedTime = 0;
//移除不必要的属性
{
const keysToDelete = ['monsterInfo', 'mora_m', 'mora_e', 'available', 'prioritized', 'G1', 'G2', 'index', 'folderPathArray', 'E1', 'E2']; // 删除的字段列表
pathings.forEach(p => {
keysToDelete.forEach(k => delete p[k]);
});
}
// 遍历 pathings 数组
for (const pathing of pathings) {
// 检查路径是否属于指定的组

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "锄地一条龙",
"version": "2.4.0",
"version": "2.5.0",
"description": "一站式解决自动化锄地支持只拾取狗粮请仔细阅读README.md后使用",
"authors": [
{

View File

@@ -149,16 +149,10 @@
"label": "勾选后禁用根据运行记录优化路线选择的功能\n完全使用路线原有信息\n【注意】启用该选项将导致无法根据个人运行清空自动优化路线选择"
},
{
"name": "eEfficiencyIndex",
"name": "efficiencyIndex",
"type": "input-text",
"label": "精英计算权重填0以上的数字\n越大越倾向于花费较多时间提高总收益",
"default": "2.5"
},
{
"name": "mEfficiencyIndex",
"type": "input-text",
"label": "小怪计算权重填0以上的数字\n越大越倾向于花费较多时间提高总收益",
"default": "0.5"
"label": "摩拉/耗时权衡因数填0以上的数字\n越大越倾向于花费较多时间提高总收益\n含义为愿意为1摩拉多花多少秒",
"default": "0.25"
},
{
"name": "curiosityFactor",