news 2026/9/10 21:04:52

freeCodeCamp 每日编程挑战 185 解析:用 JavaScript 实现花样滑冰评分系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
freeCodeCamp 每日编程挑战 185 解析:用 JavaScript 实现花样滑冰评分系统

freeCodeCamp 每日编程挑战 185 解析:用 JavaScript 实现花样滑冰评分系统

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

本文基于 freeCodeCamp 开源仓库中的每日编程挑战(Daily Coding Challenge)第 185 题,深入讲解如何用 JavaScript 实现一套"去最高分、去最低分、再扣罚分"的花样滑冰评分算法。你将掌握数组排序、切片求和、rest 参数收集罚分等核心技巧,并理解该挑战在仓库中的存储结构、测试断言机制与运行流程,能够独立复现并验证全部示例。

挑战背景:Winter Games Day 6

这道题为 freeCodeCamp 每日编程挑战系列中的Challenge 185: Winter Games Day 6: Figure Skating,属于"冬季运动会"(Winter Games)主题周的第六关,前五关分别是 Opening Day、Snowboarding、Biathlon、Ski Jumping 与 Cross-Country Skiing,后续还有 Speed Skating、Luge 等关卡(可参见 daily-coding-challenges-javascript.json 中的 challengeOrder 列表)。

在 freeCodeCamp 中,这道题以独立的 Markdown 文件形式存储在课程目录下,文件名为697a49e6ff50d756c9b69362.md(对应仓库中的 挑战文件),通过 frontmatter 声明idtitlechallengeType: 28dashedName: challenge-185。其中challengeType: 28对应 challenge-types.ts 中定义的dailyChallengeJs,即"JavaScript 每日挑战"类型;而每日挑战另有一个 Python 变体(dailyChallengePy = 29)。

问题描述与评分规则

花样滑冰的裁判打分逻辑是这道题的核心。题目要求实现一个computeScore函数,其输入与处理规则如下:

  1. 第一个参数是一个包含 10 位裁判打分的数组,每个分数是 0 到 10 之间的数字(允许小数,如8.5);
  2. 基础分计算:去掉最高分和最低分,将剩余 8 个分数求和,得到基础分(base score);
  3. 罚分处理:函数后续接收的所有额外参数都是罚分(penalties),将全部罚分从基础分中减去,得到最终得分。

这一规则模拟了真实滑冰赛事中"去掉极端裁判分、再扣除技术违规罚分"的计分方式,是典型的截断均值(trimmed mean)应用场景。

起步代码与函数签名

仓库为学习者提供的种子代码(seed)如下:

function computeScore(judgeScores, ...penalties) { return judgeScores; }

这里已经给出了关键的函数签名:

  • judgeScores:裁判打分数组,长度为 10,元素取值范围 0~10;
  • ...penalties:rest 参数,将传入的所有额外参数收集为一个数组,computeScore([...], 1, 2, 1)中的1, 2, 1会被收集为[1, 2, 1]

种子代码目前只是原样返回judgeScores,需要学习者补齐排序、截取与罚分逻辑。

参考解法逐行拆解

仓库--solutions--区块给出的官方参考实现如下:

function computeScore(judgeScores, ...penalties) { const sortedScores = [...judgeScores].sort((a, b) => a - b); const baseScore = sortedScores.slice(1, 9).reduce((sum, s) => sum + s, 0); const totalPenalty = penalties.reduce((sum, p) => sum + p, 0); return baseScore - totalPenalty; }

第一步:复制并排序打分数组

const sortedScores = [...judgeScores].sort((a, b) => a - b);
  • 使用展开运算符[...judgeScores]创建原数组的副本,避免sort()原地修改入参(Array.prototype.sort默认会在原数组上排序,复制后调用是更安全的写法);
  • sort((a, b) => a - b)提供比较函数,确保按数值升序排列,而不是默认的字符串字典序。这一点至关重要——如果省略比较函数,[10, 9, 8]会被当作字符串排成[10, 8, 9],导致结果错误;
  • 升序排列后,最小值位于下标 0,最大值位于下标 9。

第二步:剔除首尾并求和

const baseScore = sortedScores.slice(1, 9).reduce((sum, s) => sum + s, 0);
  • slice(1, 9)取出下标 1 到 8 的元素,正好是去掉最低分(下标 0)和最高分(下标 9)后的剩余 8 个分数
  • reduce((sum, s) => sum + s, 0)将这 8 个分数累加,初始值0保证空数组场景下也能安全求和。

第三步:汇总罚分并计算最终得分

const totalPenalty = penalties.reduce((sum, p) => sum + p, 0); return baseScore - totalPenalty;
  • penalties数组同样用reduce求和得到总罚分;
  • 最终得分 = 基础分 − 总罚分。因为罚分只可能减少总分,所以结果可能小于基础分,但仍应保持数值类型一致(整数相减得整数、小数相减得小数)。

测试断言:5 组用例验证

题目通过--hints--区块给出 5 组测试断言,学习者在本地或网页编辑器中提交代码后,会逐一运行这些assert.equal检查。逐组验证如下:

用例输入期望输出计算过程
1[10, 8, 9, 6, 9, 8, 8, 9, 7, 7], 164排序后去首尾,8 个分数求和为 65,减去罚分 1
2[10,10,10,10,10,10,10,10,10,10]80全 10 分,去首尾后 8×10=80,无罚分
3[10, 8, 9, 10, 9, 8, 8, 9, 10, 7], 1, 2, 167基础分 71,罚分合计 4,71−4=67
4[8.0, 8.5, 9.0, 8.5, 9.0, 8.0, 9.0, 8.5, 9.0, 8.5], 0.5, 1.067.5含小数的分数与罚分,基础分 69.0,罚分 1.5
5[6.0, 8.5, 7.0, 9.0, 7.5, 8.0, 6.5, 9.5, 7.0, 8.0], 1.5, 0.5, 0.559基础分 61.5,三项罚分合计 2.5,61.5−2.5=59

以第 1 组为例手动推演:数组排序后为[6, 7, 7, 8, 8, 8, 9, 9, 9, 10]slice(1, 9)得到[7, 7, 8, 8, 8, 9, 9, 9],求和为 65,减去罚分 1,最终64,与断言一致。第 4、5 组用例同时验证了函数对小数分数与多条小数罚分的处理能力,说明sort比较函数与reduce累加对浮点数的兼容性都在考察范围内。

代码仓库中的支撑机制

这道挑战并非孤立存在,仓库中有一套完整的配套体系:

  • 课程结构定义daily-coding-challenges-javascript块在 daily-coding-challenges-javascript.json 中注册,声明了helpCategory: "JavaScript"usesMultifileEditor: truedisableLoopProtectTests: trueblockLayout: "legacy-challenge-list",并将本挑战的id697a49e6ff50d756c9b69362)列入 challengeOrder;
  • 类型系统:challenge-types.ts 中的getIsDailyCodingChallengegetDailyCodingChallengeLanguage函数识别dailyChallengeJs/dailyChallengePy,将第 28、29 两种类型分别映射到javascript/python语言,支撑前后端对该类挑战的差异化处理;同一文件中的viewTypessubmitTypes则将dailyChallengeJs映射为classic视图与tests提交类型,表明这道题采用经典编辑器并依靠测试用例判定通关;
  • 数据校验:daily-coding-challenge-validator.ts 定义了每日挑战的数据结构,其中tests字段正是{ text, testString }数组——对应本题--hints--中"提示文本 + assert 代码"的组织方式;
  • Schema 约束:challenge-schema.js 校验所有挑战文件格式,要求challengeType为 0~33 的整数(Joi.number().min(0).max(33)),并规定solutions为文件数组(Joi.array().items(...).min(1)),与本题"种子代码 + 参考解法"的结构完全吻合;
  • 前端组件:daily-coding-challenge 组件目录 下的widget.tsxcalendar.tsx等实现每日挑战的页面展示与日历,说明该系列挑战已深度集成到 freeCodeCamp 的学习平台中。

易错点与边界情况

  • 排序陷阱:不加比较函数(a, b) => a - b时,sort()按字典序排序,10会排在9之前,导致去分错误;
  • 原地修改:直接对judgeScores.sort(...)会修改传入的数组,虽然不影响本题目断言,但属于不良实践;参考解法用[...judgeScores]复制后排序更安全;
  • 罚分可能为空:第 2 组用例没有罚分参数,此时penalties为空数组,reduce需提供初始值0才能正确返回基础分;
  • 浮点小数:第 4、5 组用例包含8.50.5等小数,算法无需额外取整,保持原值相加减即可。

扩展思考

本算法本质是"截断均值 + 惩罚项"模型,可迁移到其他需要剔除极端值再计分的场景,例如体育赛事裁判打分、问卷异常值处理、数据预处理中的离群值剔除等。若想进一步优化,可考虑:

  • 将"去掉几个最高/最低分"参数化(如改为去掉前 k 个极端值);
  • 增加入参校验(长度不足 10、分数超出 0~10 范围时的处理策略);
  • 使用Math.max/Math.min找出极值后从总和中减去,实现无需排序的等价格式:
function computeScore(judgeScores, ...penalties) { const sum = judgeScores.reduce((s, x) => s + x, 0); const baseScore = sum - Math.max(...judgeScores) - Math.min(...judgeScores); return baseScore - penalties.reduce((s, p) => s + p, 0); }

两种写法都能通过全部 5 组断言,前者逻辑更直观,后者免去排序的开销,适合在数据规模更大时使用。

总结

Challenge 185 是一道兼具趣味性与实用性的数组处理题:用sort+slice+reduce三件套完成"去极值求和",用 rest 参数收集不定数量的罚分并扣除。配合仓库中类型定义、Schema 校验与前端组件,你可以完整理解这类挑战从 Markdown 文件到学习平台运行的整条链路,并在自己的项目中复现这套计分逻辑。

【免费下载链接】freeCodeCampfreeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 21:04:46

金刚石激光烧蚀多物理场仿真与COMSOL优化实践

1. 金刚石激光烧蚀的物理背景与工程挑战 金刚石作为自然界已知最硬的材料,在精密加工领域一直存在加工效率低、工具损耗大的痛点。传统机械加工方法在应对金刚石超硬特性时往往力不从心,而激光烧蚀技术通过将高能量激光聚焦于微小区域,能在极…

作者头像 李华
网站建设 2026/9/10 21:03:51

怀化短视频公司盘点:AI短视频服务商推荐

来源:唐sirAI(www.tangsir.cc) | 电话:18874530691━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━随着AI技术的飞速发展,怀化短视频公司已经成为怀化本地企业数字化营销的重要趋势…

作者头像 李华
网站建设 2026/9/10 21:02:35

JMeter性能测试实战:从入门到企业级应用

1. JMeter实战指南:从零开始掌握性能测试利器第一次接触JMeter是在2015年一个电商项目的压力测试中,当时团队需要模拟双11级别的并发请求。面对这个开源工具,我和大多数初学者一样感到无从下手——界面复杂、概念陌生、文档晦涩。经过8年的实…

作者头像 李华
网站建设 2026/9/10 21:02:01

Java Telegram机器人开发终极指南:OkHttp与Jetty双引擎架构深度解析

Java Telegram机器人开发终极指南:OkHttp与Jetty双引擎架构深度解析 在当今即时通讯应用蓬勃发展的时代,Telegram凭借其强大的API支持和丰富的功能特性,成为了开发者构建智能机器人的首选平台。Java TelegramBots库作为这一领域的技术标杆&a…

作者头像 李华
网站建设 2026/9/10 21:01:20

数据治理实战:从口径统一到报表自动化的完整落地路径

1. 项目背景:一个日期代号背后的数据工程 2026年3月25日,我在整理客户数据资产时发现问题越来越严重——各业务线报送的原始数据质量参差不齐,同名不同义、同义不同名的字段遍地都是,数仓里光“用户ID”就有user_id、uid、member_…

作者头像 李华