ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 每日编程挑战解析:用 JavaScript 统计马的合法落点(Challenge 160: Knight Moves)

freeCodeCamp 每日编程挑战解析:用 JavaScript 统计马的合法落点(Challenge 160: Knight Moves) freeCodeCamp 每日编程挑战解析用 JavaScript 统计马的合法落点Challenge 160: Knight Moves【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本文以 freeCodeCamp 开源仓库中的每日编程挑战Challenge 160: Knight Moves挑战题目文件为蓝本完整讲解棋盘中马Knight合法移动位置的统计算法从 8×8 国际象棋坐标系统、马的 L 形走法到坐标解析、方向偏移数组与边界校验的完整实现。读完本文你将掌握一套可直接运行的 JavaScript 解法并理解该挑战在 freeCodeCamp 每日编程挑战体系中的定位、数据格式与运行机制。一、题目背景8×8 棋盘与代数坐标国际象棋棋盘是 8×8 的方格阵列题目采用标准的代数记法Algebraic Notation描述格子位置列File从左到右依次标注为A到H行Rank从下到上依次标注为1到8注意行号是自下而上递增的1行在最底部8行在最顶部。因此棋盘左上角是A8右上角是H8左下角是A1右下角是H1。原题给出了完整的棋盘网格示意|A8|B8|C8|D8|E8|F8|G8|H8| |-|-|-|-|-|-|-|-| |A7|B7|C7|D7|E7|F7|G7|H7| |A6|B6|C6|D6|E6|F6|G6|H6| |A5|B5|C5|D5|E5|F5|G5|H5| |A4|B4|C4|D4|E4|F4|G4|H4| |A3|B3|C3|D3|E3|F3|G3|H3| |A2|B2|C2|D2|E2|F2|G2|H2| |A1|B1|C1|D1|E1|F1|G1|H1|输入是一个两位字符串position例如A1、D4、G6其中第一个字符是列字母大写A–H第二个字符是行数字1–8。函数需要返回该位置出发、马能走到的合法格子数量不考虑棋盘上有其他棋子阻挡的情况。二、马的移动规则L 形走法马的走法是国际象棋中最特殊的一种先沿一个方向水平或垂直走两格再沿垂直方向走一格整体呈大写字母 L 的形状。也就是说马的每次移动在行列方向上的偏移量组合为(±2, ±1)或(±1, ±2)共 8 种可能偏移类型全部方向水平 2 格 垂直 1 格(2,1)、(2,-1)、(-2,1)、(-2,-1)水平 1 格 垂直 2 格(1,2)、(1,-2)、(-1,2)、(-1,-2)马最多有 8 个潜在落点但当马靠近棋盘边缘或角落时部分方向的落点会超出 8×8 范围因此合法落点会减少。原题给出的示例马在A1左下角时只能走到B3或C2共 2 个合法落点马在D4棋盘中心附近时8 个方向全部合法共 8 个落点马在G6时能走到 6 个合法落点马在B8时只能走到 3 个合法落点马在H3时能走到 4 个合法落点。核心思路不实际列出落点坐标只需对 8 个方向逐一做目标格是否在棋盘内的边界检查命中一次就累计一次计数。三、测试用例Hints原挑战通过 5 个断言assert来验证函数行为这也构成了题目的验收标准assert.equal(knightMoves(A1), 2); assert.equal(knightMoves(D4), 8); assert.equal(knightMoves(G6), 6); assert.equal(knightMoves(B8), 3); assert.equal(knightMoves(H3), 4);输入合法落点数位置特征A12左下角角落约束最强D48中心区域约束最小G66右侧偏上单边临近边界B83顶部边缘偏左双边临近边界H34右边缘偏下单边临近边界这组用例覆盖了角、中心、边缘、次角等典型位置能有效检验边界处理的正确性。四、逐步拆解官方解法挑战自带的可运行解决方案如下挑战题目文件 中--solutions--部分function knightMoves(position) { const col position[0].charCodeAt(0) - 65; const row parseInt(position[1]) - 1; const moves [ [2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2] ]; let valid 0; for (const [dx, dy] of moves) { const newCol col dx; const newRow row dy; if (newCol 0 newCol 8 newRow 0 newRow 8) { valid; } } return valid; }整个算法分为三个清晰的阶段4.1 坐标解析把代数记法转成 0 基行列索引const col position[0].charCodeAt(0) - 65; const row parseInt(position[1]) - 1;position[0]是列字母。A.charCodeAt(0)返回 65因此减去 65 后A→0、B→1、……、H→7得到一个 0 基的列索引col取值范围 0–7。position[1]是行数字字符。parseInt(1)得到 1减去 1 后得到 0 基的行索引row取值范围 0–7。这样A1对应(col0, row0)H8对应(col7, row7)坐标系统从人类可读的代数记法平滑转换成了程序友好的 0 基网格索引为后续数学计算扫清障碍。4.2 定义 8 个方向偏移const moves [ [2, 1], [2, -1], [-2, 1], [-2, -1], [1, 2], [1, -2], [-1, 2], [-1, -2] ];moves数组中的每个元素[dx, dy]代表马一次跳跃在列方向x与行方向y上的位移恰好是上一节列出的 8 种 L 形组合。偏移量与坐标计算解耦的设计使得判断逻辑只需循环遍历这张表代码既简短又不易遗漏方向。4.3 边界检查与计数let valid 0; for (const [dx, dy] of moves) { const newCol col dx; const newRow row dy; if (newCol 0 newCol 8 newRow 0 newRow 8) { valid; } } return valid;对每个偏移计算目标格(newCol, newRow)然后执行四重条件判断newCol 0未超出左边界A 列之外newCol 8未超出右边界H 列之外newRow 0未超出下边界1 行之外newRow 8未超出上边界8 行之外。四个条件同时满足才说明该落点在棋盘内valid自增。循环结束后返回valid即合法落点总数。复杂度分析循环次数固定为 8属于常数时间操作时间复杂度为 O(1)空间复杂度为 O(1)仅使用了定长的偏移数组与若干局部变量。五、验证解题逻辑的正确性用题目给出的测试用例手动推演一遍即可验证算法knightMoves(A1)col0, row0。8 个方向中只有(2,1)与(1,2)的目标格(2,1)、(1,2)在棋盘内即B3与C2其余方向均出现负索引结果为 2。knightMoves(D4)col3, row3。8 个方向的目标索引都在 0–7 之间结果为 8。knightMoves(G6)col6, row5。(2,1)、(2,-1)两个方向越界newCol8其余 6 个方向合法结果为 6。knightMoves(B8)col1, row7。row方向偏移为正的两组dy1与dy2共 4 个方向越界(2,-1)越界newCol3合法但newRow6合法——逐一核对(2,-1)→(3,6) 合法(-2,-1)→(-1,6) 越界(1,-2)→(2,5) 合法(-1,-2)→(0,5) 合法最终合法方向为(2,-1)、(1,-2)、(-1,-2)结果为 3。knightMoves(H3)col7, row2。列方向偏移为正的 4 个方向全部越界剩余 4 个方向合法结果为 4。五个用例全部与断言一致解法成立。六、从一道题看 freeCodeCamp 每日挑战的运行机制Challenge 160 并非孤立文件它属于 freeCodeCamp 仓库中每日编程挑战Daily Coding Challenge体系的一部分。理解这道题在整个仓库中的位置有助于你在本地复现、测试和扩展它。6.1 挑战在课程块中的注册挑战的 frontmatter 声明了元信息id: 6939b873185d8e00d453563f、title: Challenge 160: Knight Moves、challengeType: 28、dashedName: challenge-160。它与全部 365 个每日 JavaScript 挑战一起登记在课程结构文件 curriculum/structure/blocks/daily-coding-challenges-javascript.json 的challengeOrder数组中该文件同时定义了helpCategory: JavaScript、usesMultifileEditor: true、disableLoopProtectTests: true、blockLayout: legacy-challenge-list等块级配置。6.2 每日挑战如何写入数据库tools/daily-challenges/seed-daily-challenges.ts 展示了这批挑战的种子流程脚本通过 GraphQL 从 dev-playground superblock 抓取 JavaScript 与 Python 两套题目逐日合并成 365 条记录从2025-08-11起每天一条起始日期在脚本中被硬编码保护防止意外改动最终以bulkWrite的replaceOne upsert方式写入 MongoDB 的DailyCodingChallenges集合。也就是说Challenge 160: Knight Moves 在正式上线后会以某一天的身份出现在数据库中。6.3 前端的题目数据结构客户端校验文件 client/src/utils/daily-coding-challenge-validator.ts 用 Joi 定义了每日挑战的数据契约揭示了题目的完整结构顶层字段id、challengeNumber、title、date、description、javascript、python每种语言子对象包含tests数组元素为{ text, testString }与challengeFiles数组元素为{ fileKey, contents }。对应到本挑战description即原题中的# --description--部分棋盘坐标与 L 形走法说明tests即# --hints--中的 5 条断言testString为assert.equal(knightMoves(A1), 2);这类可执行代码challengeFiles中的contents即# --seed--的起始模板代码。前端收到这类数据后会在题目模板中运行testString来判定用户提交是否通过。6.4 获取每日挑战的 API 端点后端为前端提供了一系列公开只读接口实现在 api/src/daily-coding-challenge/routes/daily-coding-challenge.ts端点说明GET /daily-coding-challenge/date/:date按YYYY-MM-DD日期查询某一天的挑战GET /daily-coding-challenge/day/:day按MM-DD查询跨年份自动映射到源日期GET /daily-coding-challenge/today返回今天按美国中部时间的挑战GET /daily-coding-challenge/month/:month按YYYY-MM返回整个月的挑战列表GET /daily-coding-challenge/all返回全部已发布挑战GET /daily-coding-challenge/newest返回最新挑战的日期其中按日期查询的接口会拒绝返回晚于今天US Central的挑战注释明确写到 2026-08-10 之后将不再返回新挑战即 365 天周期的最后一天并对非法日期返回 400、未找到返回 404。前端入口组件 client/src/components/daily-coding-challenge/widget.tsx 会生成指向/learn/daily-coding-challenge/今天日期的入口并提供全部挑战归档链接。七、延伸思考这道题的变体与泛化理解 Knight Moves 之后同一套偏移表 边界检查的范式可以轻松迁移到以下场景其中部分变体在每日挑战系列中确实存在马的可行路径搜索不只统计落点数量而是用 BFS/DFS 在偏移表上做图遍历求最短步数这与挑战 125: Game of Life 等二维网格类题目共享方法论其他棋子的移动挑战 173: Valid Pawn Moves、243: Rook Attack、244: Rook and Bishop Attack 把同一思路扩展到兵、车、象等棋子验证了对移动规则表 合法性判断这一抽象的高度复用任意尺寸棋盘将边界常量8参数化为n即可处理 n×n 棋盘上的同类问题输出落点坐标把valid改为收集toAlgebraic(newCol, newRow)结果数组即可返回全部合法落点而非数量。八、小结Challenge 160: Knight Moves 是一道典型的二维网格边界判定题目其核心价值在于三个可迁移的编程技巧坐标系统转换用charCodeAt与parseInt把A1式代数记法转成 0 基整数索引方向偏移表驱动把马走日的 8 种走法编码为[dx, dy]数组用循环统一处理避免重复代码四向边界校验用 0 8的区间判断统一过滤越界落点。整道题以 O(1) 时间、O(1) 空间的代价解决既适合作为数组、字符串与条件判断的综合练习也因其清晰的抽象范式成为理解棋盘类问题与后续网格遍历算法BFS/DFS的绝佳起点。你可以在本地阅读 挑战题目文件对照--seed--起始代码与--solutions--参考实现完成练习再借助 curriculum/src/test 与 api/src/daily-coding-challenge/routes/daily-coding-challenge.test.ts 了解仓库自身的测试与接口验证方式。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表