☰
WarriorJS 计分机制完全指南:得分来源、计算公式与高分策略
2026/9/25 5:24:27 网站建设 项目流程
  • 教育
  • CLI

【免费下载链接】warriorjs

🏰 An exciting game of programming and Artificial Intelligence

项目地址:https://gitcode.com/gh_mirrors/wa/warriorjs
点击查看免费下载

WarriorJS 是一款"编程与人工智能"回合制游戏,勇士(Warrior)的最终目标不只是到达楼梯,而是在抵达楼梯的同时尽可能获得最高分。本文以官方玩家文档 docs/player/scoring.md 为骨架,结合libs/scoring、libs/core等源码与测试,完整拆解 WarriorJS 的计分规则:哪些行为加分、哪些行为扣分、总分如何由三部分构成、等级(Grade)如何评定,并给出可落地的高分实战策略。

一句话总结计分规则

你的目标是不仅到达楼梯,还要获得你能获得的最高分。每个关卡都有多种得分途径,也有可能导致扣分的危险行为;通关后本关得分累加到你的总分(total score)中,随你在整座塔(Tower)中的推进不断累积。

一、得分来源(Earning Points)

根据官方文档,一个关卡内你可以在以下四类行为中获得分数:

行为得分规则
击败敌人(Defeat an enemy)将该敌人的**最大生命值(max health)**加入你的得分
营救俘虏(Rescue a captive)获得该俘虏对应的奖励分(reward)
在奖励时间内通过关卡(Pass the level within the bonus time)获得剩余奖励时间作为分数(每关的奖励时间逐回合递减)
击败所有敌人并营救所有俘虏(Defeat all enemies and rescue all captives)获得20% 整体奖励(20% overall bonus)

1. 击败敌人:得分 = 敌人的最大生命值

"击败敌人得分等于其最大生命值"这一规则在源码中有明确体现:libs/core/src/Unit.ts中定义了所有单位通用的reward属性,其默认值就是最大生命值:

get reward(): number { return this.maxHealth; }

也就是说,普通敌人的"身价"与其最大生命值直接挂钩——血越厚的敌人,击败它获得的分越多。以当前仓库libs/units/src中的单位为例:

  • Sludge:maxHealth = 12,击败得 12 分;
  • Thick Sludge:maxHealth = 24,击败得 24 分;
  • Archer:maxHealth = 7,击败得 7 分;
  • Wizard:maxHealth = 3,击败得 3 分。

具体加分的时机由Unit.damage()决定(见 libs/core/src/Unit.ts):当攻击把目标打死后,若目标是敌人(enemy),攻击者earnPoints(receiver.reward)加分;对应测试见 libs/core/src/Unit.test.ts。

2. 营救俘虏:获得固定奖励分

俘虏(Captive)是特殊的友方单位,营救它可以获得奖励。注意:俘虏的reward被覆写为固定的 20 分,与其极低的maxHealth(1 点)无关,见 libs/units/src/Captive.ts:

class Captive extends Unit { readonly name = 'Captive'; readonly maxHealth = 1; readonly enemy = false; override bound = true; override get reward(): number { return 20; } }

营救动作由Unit.release()实现(libs/core/src/Unit.ts):对非敌人单位,先使其vanish(),然后earnPoints(receiver.reward)。对应测试 libs/core/src/Unit.test.ts 验证了"营救友方单位可获得与 reward 等值的分数"。在战斗中触发营救的是 Rescue 能力,调用warrior.rescue()即可释放前方被束缚的单位。

3. 时间奖励:奖励时间逐回合递减

每个关卡都有一个初始时间奖励(time bonus),它随你行动的每个回合递减。通关时,剩余的时间奖励全部计入得分。

源码实现见 libs/scoring/src/getRemainingTimeBonus.ts:

function getRemainingTimeBonus(turns: ScoringEvent[][], timeBonus: number): number { const turnCount = getTurnCount(turns); const remainingTimeBonus = timeBonus - turnCount; return Math.max(remainingTimeBonus, 0); }

其中getTurnCount就是turns.length(libs/scoring/src/getTurnCount.ts),即你实际玩了多少个回合。因此:

  • 使用回合越少,剩余时间奖励越多;
  • 若使用回合数超过初始 time bonus,该项为 0(不会扣成负数,Math.max(..., 0)保证了下限)。

对应测试见 libs/scoring/src/getRemainingTimeBonus.test.ts:初始 10、用了 3 回合得 7 分;用了 11 回合则归 0。

关卡配置:timeBonus是关卡配置项(见 libs/core/src/types.ts 中的LevelConfig)。以官方塔 towers/the-narrow-path/src/index.ts 为例,第 1 关timeBonus: 15,第 2 关timeBonus: 20,第 3 关timeBonus: 35,第 4 关timeBonus: 45——随着难度递进,时间奖励也更充裕。

4. 全清奖励:20% 整体奖励

若你击败了所有敌人并营救出所有俘虏(即关卡被完全清理,地板上除勇士外没有任何单位),将获得一份相当于"勇士得分 + 时间奖励"之和 20% 的整体奖励。

源码实现见 libs/scoring/src/getClearBonus.ts:

function getClearBonus(turns: ScoringEvent[][], warriorScore: number, timeBonus: number): number { const lastEvent = getLastEvent(turns); if (!isFloorClear(lastEvent.floorMap)) { return 0; } return Math.round((warriorScore + timeBonus) * 0.2); }

关键点:

  • 清理判定:isFloorClear(libs/scoring/src/isFloorClear.ts)统计最终回合地图上除勇士外的单位数量,unitCount <= 1(只允许勇士自己)才算清理完成;
  • 计算基准:(勇士得分 + 时间奖励) × 0.2,结果四舍五入取整(Math.round);
  • 未清理则该项为 0,即使你照样走到了楼梯、通过了关卡,也拿不到这 20%。

测试验证见 libs/scoring/src/getClearBonus.test.ts:例如勇士得分 3、时间奖励 2、关卡已清理,则Math.round((3+2)*0.2) = 1。

二、扣分来源(Losing Points)

文档同时提醒你必须小心:杀死一名俘虏(kill a captive)会招来惩罚。

扣分的机制与加分共用同一套Unit.damage()逻辑(libs/core/src/Unit.ts):当你的攻击杀死一个目标时,源码会检查目标isEnemy()——

  • 目标是敌人:this.earnPoints(receiver.reward),加分;
  • 目标不是敌人(即友方,例如俘虏):this.losePoints(receiver.reward),减去等值分数,也就是惩罚。

对应测试见 libs/core/src/Unit.test.ts:击杀友方单位会losePoints(10)。落实到实战中,俘虏maxHealth只有 1 且处于束缚状态(bound = true),任何一次攻击都可能误杀它,从而损失 20 分并失去后续的营救奖励,因此开战前务必用warrior.feel().getUnit()?.isEnemy()确认目标身份。

三、总分构成:getLevelScore 的三段式结构

通关后,本关得分由 libs/scoring/src/getLevelScore.ts 统一汇总,返回一个包含三个组成部分的对象:

function getLevelScore({ passed, turns }: LevelResult, { timeBonus }: LevelConfig): LevelScore | null { if (!passed) { return null; } const warriorScore = getWarriorScore(turns); const remainingTimeBonus = getRemainingTimeBonus(turns, timeBonus); const clearBonus = getClearBonus(turns, warriorScore, remainingTimeBonus); return { clearBonus, timeBonus: remainingTimeBonus, warrior: warriorScore, }; }
字段含义来源
warrior勇士在本关累计的击杀/营救净得分getWarriorScore.ts 读取最后一回合事件的warriorStatus.score
timeBonus剩余时间奖励(timeBonus - 回合数,最低 0)getRemainingTimeBonus.ts
clearBonus全清 20% 奖励(未全清为 0)getClearBonus.ts

勇士得分的来源

getWarriorScore的实现非常直白:从最后一回合的最后一个事件中读取勇士状态里的score字段(libs/scoring/src/getWarriorScore.ts、libs/scoring/src/getLastEvent.ts)。这个score由Warrior实时维护:Unit.earnPoints()做this.score += points,losePoints()做this.score -= points(libs/core/src/Unit.ts),并通过 Warrior.getStatus() 暴露{ health, score }供事件记录。也就是说,你每一回合的击杀加分、误杀扣分都会实时累计进warriorStatus.score。

总分的合成与等级评定

在 CLI 层,apps/cli/src/utils/buildLevelReport.ts 将三部分相加得到本关总分,并依据关卡配置的aceScore计算等级:

const scoreParts = getLevelScore(levelResult, { timeBonus: levelConfig.timeBonus ?? 0 })!; const totalScore = scoreParts.warrior + scoreParts.timeBonus + scoreParts.clearBonus; const grade = levelConfig.aceScore ? totalScore / levelConfig.aceScore : 0;
  • 总分=warrior+timeBonus+clearBonus;
  • 等级(grade)= 总分 ÷aceScore(每个关卡配置的"满分基准",见 libs/core/src/types.ts)。

等级字母由 libs/scoring/src/getGradeLetter.ts 映射(对应测试见 getGradeLetter.test.ts):

等级数值字母
>= 1.0S
>= 0.9A
>= 0.8B
>= 0.7C
>= 0.6D
< 0.6F

等级会在结算界面展示(apps/cli/src/ui/components/ResultScreen/ResultScreen.tsx),并在史诗模式(Epic Mode)中用于计算平均等级与史诗分数(见 apps/cli/src/Profile.ts 的tallyPoints、calculateAverageGrade、getEpicScoreWithGrade)。

四、实战高分策略

综合文档规则与源码逻辑,最大化总分可以归纳为四条核心策略:

  1. 少回合、快通关,吃满时间奖励:时间奖励随回合递减,这是"看得见"的分数。每回合只做一件有意义的事(WarriorJS 每回合只能执行一个动作),提前规划好行走、攻击、休息的节奏,避免无意义的空走与反复试探。通关回合数 ≥ timeBonus 时该项归 0,且不影响其他两项,所以时间奖励是"锦上添花"项,但往往决定你能否达到 S 级。

  2. 击败每一个敌人,且只击杀敌人:敌人身价 = 最大生命值,血厚的 Thick Sludge(24 分)尤其值得优先击杀;而俘虏只有 1 点血,一个误击就会losePoints(20)——既丢了分,又失去了营救奖励和全清资格,双重损失。

  3. 别漏掉任何俘虏:每个俘虏固定 20 分,且是触发全清奖励的必要条件之一。用isEnemy()/isBound()识别并rescue(),不要用攻击去"清场"。

  4. 追求全清,拿到 20% 整体奖励:全清奖励 =(勇士得分 + 时间奖励) × 20%,它是基于前两项的乘法型加成——你击杀越多、通关越快,这个 20% 的绝对值就越大。这意味着"绕开敌人直奔楼梯"虽然能通过关卡,却会损失掉全清奖励这最后一块拼图。

以 towers/the-narrow-path/src/index.ts 第 1 关为例(timeBonus: 15、aceScore: 10):假设你 3 回合内击杀 1 只 Sludge 并全清通关,则勇士得分 12、时间奖励 12、全清奖励Math.round(24 × 0.2) = 5,总分 29,等级29 / 10 = 2.9,轻松拿下 S 级。反过来,如果拖到 16 回合以上且漏掉全清,总分会显著缩水。

五、小结

WarriorJS 的计分体系清晰而克制:加分项(击杀、营救、时间奖励、全清 20% 加成)与扣分项(误杀俘虏)共同决定了你的单关得分;总分 = 勇士得分 + 时间奖励 + 全清奖励,除以关卡aceScore得到 S/A/B/C/D/F 等级。理解这套规则后,最优解不再是"莽到楼梯",而是"快速、精准、零误伤地清理整个关卡"——这正是 WarriorJS 鼓励玩家打磨 AI 决策逻辑的核心所在。相关实现与测试均可在仓库的 libs/scoring 与 libs/core/src/Unit.ts 中直接查阅验证。

  • 教育
  • CLI

【免费下载链接】warriorjs

🏰 An exciting game of programming and Artificial Intelligence

项目地址:https://gitcode.com/gh_mirrors/wa/warriorjs
点击查看免费下载

相关推荐

上一篇:5分钟掌握Just:让命令行任务自动化不再繁琐
下一篇:lazydocker鼠标支持:终端环境下的图形化交互体验

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询