js: 七圣召唤七日历练: 记录各策略的成功率数据,并据此优化策略选择 (#2005)

This commit is contained in:
Patrick-Ze
2025-09-27 00:27:14 +08:00
committed by GitHub
parent 56fcfccf61
commit d9dc7b0fce
15 changed files with 181 additions and 14 deletions

View File

@@ -2,7 +2,12 @@
如果某个打牌对手有专用策略时,脚本会使用对应分享码自动导入牌组,并使用对应策略进行打牌;
如果没有专用策略,或者分享码中使用了你尚未获得的角色卡时,将使用通用性最高的'雷神柯莱刻晴'进行打牌。
如果没有专用策略,或者分享码中使用了你尚未获得的角色卡时
- 若开启了`自动尝试备用策略`,将按照策略运行记录,按成功率从大到小的顺序逐个尝试备用策略。
- 否则,将使用通用性最高的'雷神柯莱刻晴'进行打牌。
欢迎提交你的策略运行记录(`牌组策略`文件夹下的`各策略胜败记录.json`文件),汇集大家的数据共同提高打牌效率。
## 脚本配置
@@ -11,6 +16,7 @@
| 默认牌组 | 填写你游戏中'雷神柯莱刻晴'队所在的牌组名 |
| 临时牌组 | 填写用来导入分享码的牌组名 |
| 自动尝试备用策略 | 打牌失败时自动逐个尝试备用策略。如果你不想亲自打那些脚本打不过的挑战,也不在乎多次尝试的耗时,可以勾选此项 |
| 仅使用胜率记录大于该值的备用策略 | 根据运行记录,跳过执行那些胜率太小的备用策略 |
| 密码 | 随便填 |
**注意:**
@@ -28,12 +34,10 @@
## 如何添加或删除备用策略
脚本自动将`牌组策略`文件夹下以数字加小数点开头的txt文件识别为备用策略例如`10.莫娜砂糖琴.txt`
脚本自动将`牌组策略`文件夹下以数字加小数点开头的txt文件识别为备用策略例如`1.莫娜砂糖琴.txt`
如果启用了备用策略功能,打牌失败时,按照数字从小到大的顺序自动逐个尝试。
目前脚本内置了8个备用策略都是BetterGI内建的策略
如果想要添加更多的备用策略,参考`_策略模板.txt`完成编辑后,将文件命名为数字加`.`开头就行。
如果觉得尝试次数不用这么多直接删除备用策略对应的txt文件即可。

View File

@@ -3,6 +3,9 @@ let textArray = [];
let skipNum = 0;
let allStrategy = {};
let fallbackStrategyList = [];
const strategyRunRecordFile = "牌组策略/各策略胜败记录.json";
let strategyRunRecord = {};
let minFallbackStrategyScore = 0.25;
// 切换到指定的队伍
async function switchCardTeam(Name, shareCode) {
@@ -200,7 +203,7 @@ async function isTaskRefreshed(filePath, options = {}) {
}
if (shouldRefresh) {
notification.send(`七圣召唤七日历练周期已经刷新,执行脚本`);
// notification.send(`七圣召唤七日历练周期已经刷新,执行脚本`);
return true;
} else {
@@ -472,6 +475,56 @@ function scanCardStrategy() {
return strategyMap;
}
function updateRunRecord(charName, strategyName, win) {
if (!strategyRunRecord[charName]) {
strategyRunRecord[charName] = {};
}
if (!strategyRunRecord[charName][strategyName]) {
strategyRunRecord[charName][strategyName] = { win: 0, fail: 0 };
}
if (win === true) {
strategyRunRecord[charName][strategyName].win++;
} else if (win === false) {
strategyRunRecord[charName][strategyName].fail++;
} // else : do nothing when null
file.writeTextSync(strategyRunRecordFile, JSON.stringify(strategyRunRecord, null, 2), false);
}
function sortAndFilterStrategy(charName) {
const atLeastOne = ["雷神柯莱刻晴"];
if (! settings.useFallbackStrategy) {
return atLeastOne;
}
const toBeCheck = [...atLeastOne, ...fallbackStrategyList];
const charRecord = strategyRunRecord[charName];
if (!charRecord) {
return toBeCheck;
}
const scores = {};
for (const strategyName of toBeCheck) {
const data = charRecord[strategyName];
if (!data) {
scores[strategyName] = 0.5; // 未尝试过的策略
continue;
}
if (data.win === 0 && data.fail === 1) {
scores[strategyName] = 0.3; // 仅失败过一次,再给点机会
} else {
const total = data.win + data.fail;
if (total === 0) {
scores[strategyName] = 0.5;
} else {
scores[strategyName] = data.win / total;
}
}
}
const sortedScores = Object.entries(scores).sort((a, b) => b[1] - a[1]); // 分数从大到小
log.debug(`各策略胜率分数: ${JSON.stringify(sortedScores)}`);
const sortedKeys = Object.entries(sortedScores)
.filter((entry) => entry[1] >= minFallbackStrategyScore);
return sortedKeys;
}
//检查是否有对应的挑战对手
async function searchAndClickTexts() {
middleButtonClick();
@@ -512,14 +565,17 @@ async function searchAndClickTexts() {
log.info("使用角色专用策略与{0}对战", charName);
success = await Playcards(strategy, settings.overwritePartyName, res);
}
if (!success) {
log.info("使用默认策略与{0}对战", charName);
success = await Playcards(allStrategy["雷神柯莱刻晴"], settings.defaultPartyName, res);
}
for (const strategyName of fallbackStrategyList) {
const sortedStrategy = sortAndFilterStrategy(charName);
for (const strategyName of sortedStrategy) {
if (!success) {
log.info("使用备用策略{0}与{1}对战", strategyName, charName);
success = await Playcards(allStrategy[strategyName], settings.overwritePartyName, res);
if (strategyName === "雷神柯莱刻晴") {
log.info("使用默认策略{0}与{1}对战", strategyName, charName);
success = await Playcards(allStrategy[strategyName], settings.defaultPartyName, res);
} else {
log.info("使用备用策略{0}与{1}对战", strategyName, charName);
success = await Playcards(allStrategy[strategyName], settings.overwritePartyName, res);
}
updateRunRecord(charName, strategyName, success);
}
}
@@ -603,7 +659,7 @@ async function Playcards(strategy, teamName, pos) {
if (!success) {
keyPress("ESCAPE");
await sleep(2000);
return success;
return null;
}
click(1610, 900); //点击挑战
await waitOrCheckMaxCoin(8000);
@@ -731,10 +787,16 @@ async function gotoTable6() {
async function main() {
//主流程
const nowTime = new Date();
log.info(`前往猫尾酒馆`);
await gotoTavern();
await captureAndStoreTexts();
allStrategy = scanCardStrategy();
try {
strategyRunRecord = JSON.parse(file.readTextSync(strategyRunRecordFile));
} catch (error) {
log.debug("读取策略运行记录失败");
}
if (settings.useFallbackStrategy) {
fallbackStrategyList = Object.keys(allStrategy).filter((key) => {
return /^(\d+)\./.test(key);
@@ -743,6 +805,16 @@ async function main() {
return parseInt(a) - parseInt(b);
});
log.info("已启用{0}个备用策略: {1}", fallbackStrategyList.length, fallbackStrategyList.join(", "));
try {
const scoreInSetting = parseFloat(settings.minFallbackStrategyScore || -1);
if (scoreInSetting < 0 || scoreInSetting > 1) {
throw new RangeError("无效的输入值范围");
}
minFallbackStrategyScore = scoreInSetting;
} catch (error) {
log.warn("未设置备用策略胜率阈值或阈值无效,使用默认值{0}", minFallbackStrategyScore);
}
} else {
log.info("未启用备用策略");
}

View File

@@ -1,7 +1,7 @@
{
"manifest_version": 1,
"name": "打牌一条龙",
"version": "2.5",
"version": "2.6",
"description": "完成每周的七圣召唤七日历练来客挑战。详见README.md",
"tags": [
"七圣召唤"

View File

@@ -14,6 +14,11 @@
"type": "checkbox",
"label": "打牌失败时自动逐个尝试备用策略"
},
{
"name": "minFallbackStrategyScore",
"type": "input-text",
"label": "仅使用胜率记录大于该值的备用策略 (0到1之间的小数)"
},
{
"name": "passWord",
"type": "input-text",

View File

@@ -0,0 +1,44 @@
// shareCode=AnGhuTQMEoGR83oQCCGR9HsQCDGh9bQQDEEx9rUQDFFB97YQDGFR+LcQDHFh+bgQDIEB
// 作者:HZYgrandma
角色定义:
角色1=皇女
角色2=白术
角色3=林尼
---
策略定义:
皇女 使用 技能2
白术 使用 技能2
林尼 使用 技能3
白术 使用 技能2
皇女 使用 技能2
白术 使用 技能1
白术 使用 技能2
林尼 使用 技能3
皇女 使用 技能2
白术 使用 技能2
林尼 使用 技能3
白术 使用 技能2
皇女 使用 技能2
白术 使用 技能1
白术 使用 技能2
林尼 使用 技能3
皇女 使用 技能2
白术 使用 技能2
林尼 使用 技能3
白术 使用 技能2
皇女 使用 技能2
白术 使用 技能1
白术 使用 技能2
林尼 使用 技能3

View File

@@ -0,0 +1,34 @@
// shareCode=AnGRuSIMBIFR83oQCCGR9HsQCDGh9bQQDEEx9rUQDFFB97YQDGFR+LcQDHFh+bgQDIEB
// 作者: johsang
// 描述: 对面出伤快、元素盾、耐耗王可用,多种召唤物稳定赚费补强生存,应对一些刁钻局有奇效
角色定义:
角色1=迪希雅|火{技能3消耗=1火骰子+2任意,技能2消耗=3火骰子,技能1消耗=4火骰子}
角色2=八重神子|雷{技能3消耗=1雷骰子+2任意,技能2消耗=3雷骰子,技能1消耗=3雷骰子}
角色3=纯水精灵|水{技能4消耗=1水骰子+2任意,技能3消耗=3水骰子,技能2消耗=5水骰子,技能1消耗=3水骰子}
---
策略定义:
迪希雅 使用 技能2
八重神子 使用 技能2
八重神子 使用 技能2
纯水精灵 使用 技能3
纯水精灵 使用 技能3
迪希雅 使用 技能2
迪希雅 使用 技能1
八重神子 使用 技能1
纯水精灵 使用 技能3
纯水精灵 使用 技能1
// 后续的内容不太可能执行到,只是为了一些特殊对局
纯水精灵 使用 技能3
迪希雅 使用 技能2
八重神子 使用 技能2
纯水精灵 使用 技能3

View File

@@ -0,0 +1,8 @@
{
"莱拉": {
"2.刻晴雷神甘雨": {
"win": 1,
"fail": 0
}
}
}