ARTICLE DETAIL

资讯详情

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

TypeHero Advent of TypeScript 2023 Day 23:在 TypeScript 类型系统中实现 Connect 4 四子棋

TypeHero Advent of TypeScript 2023 Day 23:在 TypeScript 类型系统中实现 Connect 4 四子棋 教育前端后端【免费下载链接】typeheroConnect, collaborate, and grow with a community of TypeScript developers项目地址https://gitcode.com/gh_mirrors/ty/typehero点击查看免费下载本指南围绕 TypeHero「Advent of TypeScript 2023」第 23 天挑战展开在不写任何运行时代码的前提下仅用 TypeScript 类型系统实现完整的 Connect 4四子棋对局引擎——包括落子、交替回合、胜负判定与平局检测。你将理解该挑战如何用棋盘矩阵类型 状态机类型表达游戏全局并通过 user.ts 的骨架、tests.ts 的 9 组类型测试以及 validate.ts 的验证机制掌握一套可直接复用的「类型级状态机」实现方法论。挑战概述把棋盘游戏搬进类型层这道题的目标非常直接在 TypeScript 类型系统中实现 Connect 4prompt.md。与常规的运行时实现不同这里的棋盘棋子玩家回合全部要以类型的形式表达并通过类型层面的递归计算模拟一次次的落子。Connect 4 的规则原文档要点必须完整掌握玩家各自选择一种颜色本挑战为 与 轮流将棋子投入一个六行七列的垂直悬挂网格棋子沿所在列直线下落占据该列最低的可用空格目标率先在水平、垂直或对角线方向连成四个自己颜色的棋子即获胜。每个格子可以是、或为空。挑战提供EmptyBoard类型作为棋盘的组织骨架而游戏状态由一个对象表示它包含board属性当前棋盘和state属性记录接下来轮到哪位玩家。原文档还特别提示了实现时的一个关键语义state记录的是next up to play下一个轮到谁而非刚才是谁下的——这一点从NewGame的初始状态即可印证后文会结合测试详细展开。状态建模从 Connect4Chips 到 NewGame挑战在 user.ts 中给出了完整的类型骨架我们需要做的是填充Connect4这个unknowntype Connect4Chips | ; type Connect4Cell Connect4Chips | ; type Connect4State | | Won | Won | Draw; type EmptyBoard [ [ , , , , , , ], [ , , , , , , ], [ , , , , , , ], [ , , , , , , ], [ , , , , , , ], [ , , , , , , ], ]; type NewGame { board: EmptyBoard; state: ; }; type Connect4 unknown;几个容易被忽略、但对实现至关重要的细节类型含义说明Connect4Chips两种棋子 \| 胜负双方的颜色Connect4Cell单个格子的取值棋子或空位注意空位是两个空格字符 而非 prompt 里示意性写到的单个空格 实现时必须以 为准Connect4State状态机取值进行中为 \| 表示下一个落子方终局为 Won \| Won \| DrawEmptyBoard初始棋盘六行外层元组 6 个元素× 七列每行 7 个 的二维元组NewGame初始局面空棋盘 state: 即黄方先手棋盘的行列索引语义外层元组下标 0 对应棋盘顶部下标 5 对应底部列下标 06 对应从左到右的七列。棋子总是落入目标列最低的可用空格也就是该列行号最大的那个空位——理解这一点是正确实现落子的前提。测试驱动剖析Connect4 的签名与落子语义挑战要求实现的核心类型是Connect4Game, Column其中Game是当前的棋盘状态对象Column是要落子的列号数字字面量类型。tests.ts 用ExpectEqual来自type-testing工具包对每一步的精确结果做了断言。交替回合与竖直堆叠move1move3前三个测试都向第 0 列落子完整揭示了回合交替的语义type test_move1_actual Connect4NewGame, 0; // board 最底部一行第 0 列变为 // state: type test_move2_actual Connect4test_move1_actual, 0; // 上方第 4 行变为 state 回到 type test_move3_actual Connect4test_move2_actual, 0; // 上方第 3 行变为 state 回到 从 tests.ts 的期望值可以提炼出三条核心规则NewGame.state 因此第一步move1落下的是 落子后state变为——即下一个轮到谁第 0 列连续落子时棋子自底部row 5向上逐格堆叠行号递减每落一子state在与之间翻转一次。多列落子move4move6接下来三个测试转向第 1、2 列验证不同列之间的互不干扰Connect4test_move3_actual, 1 落入第 1 列底部row 5第 0 列保持三层不变Connect4test_move4_actual, 2 落入第 2 列底部Connect4test_move5_actual, 1第 1 列已有 落在其上row 4。至此棋盘呈现为tests.ts第 4 行: 空 空 空 空 空 第 5 行: 空 空 空 空这组测试证明落子只影响目标列且严格遵循最低可用格规则实现时必须对目标列做插入运算而不是直接按行号放置。胜负判定与平局处理当四子连成一线时状态必须切换为对应的Won终局当棋盘填满且无人获胜时切换为Draw。横向胜利red win输入局面中第 4 行已有[, , ]在列 3 落下 后形成[,,,]四连state从变为 Wontests.ts。纵向胜利yellow win输入局面中第 2 列已有[, , ]分别位于 row 2/4/5在列 1 落下 后第 1 列形成 row 3/4/5 的[,,]加上 row 2 已有的 构成纵向四连state变为 Wontests.ts。注意 的四个棋子并非连续四行相邻摆放而是在一列内形成从 row 2 到 row 5 恰好四子的连续堆叠——这提醒我们纵向判定的是同一列内连续四个同色。对角线胜利diagonal yellow win最复杂的情形输入局面在 row 3row 5 之间存在一条/交错的斜向结构当 落子到列 3 后从 row 5 列 1 → row 4 列 2 → row 3 列 3 → row 2 列 3 的斜向路径构成四连state变为 Wontests.ts。平局draw棋盘除第 6 列最底部一格外的 41 格全部填满、且无任何一方四连时Connect4draw 局面, 6将 放入最后一格state变为Drawtests.ts。综合可见Connect4Game, Column的完整行为可以归纳为一条类型级的状态转移函数落子到目标列最低可用格 ├─ 若落子后横/竖/任一斜向出现四连 → state 该方 Won ├─ 若棋盘已满且无人四连 → state Draw └─ 否则 → state 翻转后的下一方 ↔ 类型系统实现技法递归条件类型与元组运算该挑战的 solution 目录solutions在仓库中留空官方未提供参考答案因此以下为基于测试约束可以推断的通用实现思路供读者自行推导验证。思路一落子 对目标列做从底部插入由于棋子总是落入列中最低的空位一种自然的建模是把向列 C 落子转化为从列底部row 5向上扫描、命中第一个空位即替换为当前棋子的递归// 示意把 Chips 插入 Tuple自底向上扫描Inserted 表示是否已插入 type DropTuple extends string[], Chip, Inserted extends boolean false Inserted extends true ? Tuple // 已插入其余原样保留 : Tuple extends [...infer Rest extends string[], infer Last] ? Last extends ? [...Rest, Chip] // 命中空位替换为棋子 : [...DropRest, Chip, true, Last] // 非空则继续向上扫描 : Tuple;把 6×7 的棋盘逐行套用该操作即可得到落子后的新棋盘对棋盘已满的判断等价于检查所有行是否都不含 。思路二胜负检测 对四种连线方向的穷举四连检测需要在四种方向上扫描棋盘横向逐行检查是否存在连续四个相同棋子纵向逐列检查等价于检查列元组内连续四个相同元素斜向主对角线方向从某格向右下方延伸四格斜向副对角线方向从某格向左下方延伸四格。类型级实现通常借助递归条件类型索引访问Board[Row][Col]模板字面量类型组合用数字元组如[0,1,2,3,4,5]驱动递归对每个起点格检查Board[Row][Col]、Board[Row1][Col±1]等四个位置的取值是否全部等于同一棋子。由于tsconfig开启了noUncheckedIndexedAccess索引访问返回的是T | undefined实现时需要用条件类型对越界情况做兜底处理。思路三状态机 条件类型分发Connect4Game, Column的本质是一台小的类型级状态机先用Game[state]取出当前落子方并计算新棋盘再对新棋盘做胜负/平局检测最后输出{ board: NewBoard; state: NextState }作为新的Game。这与前文中列出的转移函数一一对应测试用例正是这台状态机的行为规约。挑战验证机制validate.ts 与严格编译选项TypeHero 的挑战系统通过 validate.ts 对每个挑战做自动化校验。与本题直接相关的机制validate.ts如下读取每个挑战目录下的 tsconfig.json 编译选项本题启用了strict、exactOptionalPropertyTypes与noUncheckedIndexedAccess三项严格模式——前两者要求类型实现完全精确后者则让元组索引访问返回联合了undefined的类型逼迫实现者显式处理越界将 solution 源码与 tests.ts拼接为一个内存中的虚拟源文件solution 在前、tests 在后以避免块级变量先声明后使用的报错通过自定义CompilerHost与createProgram在内存中编译使用getPreEmitDiagnostics收集类型诊断若 tests.ts 中的ExpectEqual...断言失败编译器会报出类型不匹配的诊断并标记该 solution 为 ✗全部通过则标记为 ✓。也就是说本题的 9 组测试不仅是期望值文档更是会被真实 TypeScript 编译器逐一对齐执行的类型级断言——读者在本地把实现填入 user.ts 的Connect4后即可通过challenges/validate.ts的校验获得即时反馈。挑战元数据本题的 metadata.json 记录挑战 id 为2023-23标签 Day Twenty Three属于 Advent of TypeScript 2023 事件序列difficulty 为event作者为 TypeHero且无前置依赖挑战。它排在圣诞老人走出迷宫Day 24prompt.md之前是 2023 年 Advent 活动中一道综合运用元组、条件类型与状态机思想的收官级题目。背景冷知识Connect 4 的别名与求解史原文档附带两条趣味史实值得保留Connect 4 还有多个别名Connect Four、Four Up、Plot Four、Find Four、Captains Mistress、Four in a Row、Drop Four以及在苏联被称为GravitripsConnect 4 在1988 年被 James Allen 与 Victor Allis几乎同时独立求解两人仅相隔约两周。当时受限于算力他们无法给出完整的暴力穷举证明7 年后1995 年荷兰的 John Tromp 借助 Sun Microsystems 与 Silicon Graphics International 工作站上的数据库完成了最终证明累计耗费约40,000 计算小时。小结这道题教会我们的类型编程能力完成 Day 23 后你收获的是一套可复用的类型级游戏引擎能力二维元组即棋盘用嵌套元组表达网格状态用 表达空位用字面量联合表达棋子类型级状态机{ board, state }作为单一状态对象每个Connect4Game, Column调用都是一次确定性的状态转移胜负与平局作为终局态收敛递归条件类型 元组操作自底向上的列插入、四方向连续扫描都建立在递归与[...infer Rest, infer Last]等元组解构技巧之上类型测试即契约Expect/Equal把行为规约直接固化到编译期配合validate.ts的内存编译机制实现与验证形成闭环。以此为起点你可以进一步尝试把同样的思路扩展到更大的棋盘、更多的维度或加入禁止落满列等额外规则——这一切都不需要一行 JavaScript全部发生在类型层。相关文件索引prompt.md、user.ts、tests.ts、metadata.json、validate.ts。赞分享教育前端后端【免费下载链接】typeheroConnect, collaborate, and grow with a community of TypeScript developers项目地址https://gitcode.com/gh_mirrors/ty/typehero点击查看免费下载相关推荐用 TypeScript 类型系统实现倒计时TypeHero「Advent of TypeScript 2023」Day 13 的 DayCounter 实战解析用 TypeScript 类型系统实现倒计时TypeHero「Advent of TypeScript 2023」Day 13 的 DayCounter 实战教育前端后端OpenMed 隐私报告字段 Lint 指南基于类型化 Allowlist Schema 的无值Value-Free报告边界校验OpenMed 隐私报告字段 Lint 指南基于类型化 Allowlist Schema 的无值Value Free报告边界校验 OpenMed 的 op教育前端后端NanoClaw 接入 GitHub 渠道实战基于 Chat SDK Bridge 的 PR/Issue 评论线程 Agent 集成NanoClaw 接入 GitHub 渠道实战基于 Chat SDK Bridge 的 PR/Issue 评论线程 Agent 集成 导读 本指南讲解如何在教育前端后端上一篇WebGAL入门指南如何用可视化编辑器制作你的第一个视觉小说下一篇QiFi - 轻巧而强大的无配置Web应用程序创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表