
示例工程教程【免费下载链接】Cangjie-Examples本仓将收集和展示高质量的仓颉示例代码欢迎大家投稿让全世界看到您的妙趣设计也让更多人通过您的编码理解和喜爱仓颉语言。项目地址https://gitcode.com/Cangjie/Cangjie-Examples点击查看免费下载导读本篇文章以 Cube 案例说明文档 为核心骨架围绕仓颉语言团队刘俊杰所写的神奇的魔方示例逐层拆解其用代数风格实现三阶魔方 Model / View / Controller 的全过程。你将看到enum递归数据类型、操作符成员函数、extend扩展、if表达式、lambda、元组解构与模式匹配如何在几十行代码内组合出一个可运行、可验证数学规律的魔方模拟器同时文章会结合仓库内的 cube.cj、rotation.cj、matrix.cj、permutation.cj 与 main.cj 源码讲清每一层设计的动机与底层实现。读完本文你将掌握用仓颉语言进行递归类型建模、操作符重载与面向数学问题的函数式编程思路。案例概览一个集语言特性之大成的数字魔方按照 readme.md 的定位本案例综合应用仓颉语言的基础特性实现三阶魔方的 Model、View 和 Controller可以在控制台中模拟魔方操作并验证一些魔方相关的数学规律。文档列出了六个核心知识点也是本文的六个主线使用enum构造递归数据类型Rotation结合操作符成员函数和模式匹配实现魔方变换操作的代数表示使用extend为二维数组扩展并重载索引操作符函数实现取魔方面行/列数据的操作为Int64类型扩展两个属性简化表达行列索引Index实例基于if表达式求值、lambda表达式、函数一等公民和元组解构等特性快速实现魔方面顺/逆时针旋转使用模式匹配和递归调用实现Rotation实例的解构和动作执行用代数风格的编码验证置换群阶数、相似变换、组合子变换等数学规律。从代码结构看案例的文件划分本身就是一次典型的 MVC 分层Rotation与Permutation承担操作模型Model的代数定义Matrix扩展承担状态数据模型Cube类同时承载状态、动作执行Controller与展平打印Viewmain.cj则是驱动整个模拟与数学验证的入口。下面按由数据到行为、由抽象到验证的顺序逐层展开。效果预览案例在控制台中按面展平输出魔方状态黄色背景的六个面依次显示 U顶、L/F/R中环三面、D底、B背每格以面代号编号标记顶行提示当前已执行的操作序列该图来自仓库 preview.png演示了案例真实的运行输出形态后续各小节将解释这些状态是如何被计算出来的。项目结构与运行方式Cube 项目位于仓库的 Cube 目录核心文件如下文件职责rotation.cjRotation递归枚举、Face类型别名、*/**/等操作符重载matrix.cjIndex枚举、Matrix/Vector类型、extend Matrix与extend Int64扩展permutation.cj置换序列类型及其逆变换计算cube.cjCube主类六面状态、旋转/置换动作、历史记录与打印main.cj程序入口基本操作演示与数学规律验证从 cjpm.toml 可以确认这是一个标准的仓颉可执行程序工程name cube、output-type executable无第三方依赖。克隆仓库后在Cube目录下使用仓颉包管理器cjpm即可构建与运行构建cjpm build运行cjpm run。由于案例完全基于标准库不依赖图形界面任何具备仓颉编译环境的平台均可直接复现。第一层用 enum 递归类型为魔方操作建模魔方六面的标准操作记法在速拧领域约定俗成FFront 前、BBack 后、LLeft 左、RRight 右、UUp 上、DDown 下每种字母表示正对此面顺时针旋转 90 度。递归枚举 Rotationrotation.cj 用一个递归枚举把操作本身建模为一等公民public enum Rotation : ToString Hashable EquatableRotation { F | B | L | R | U | D | X(Rotation, Rotation) | I(Rotation) }F | B | L | R | U | D是六个原子操作对应六个面的 90 度顺转X(Rotation, Rotation)是复合节点用于把两个操作组织成一个序列I(Rotation)表示逆变换即正对r面逆时针旋转 90 度。这正是文档所说使用enum构造递归数据类型的体现X和I的成员类型又引用自身使得一个操作序列可以表达为树状结构为后面的模式匹配解构埋下伏笔。同时enum声明实现了ToString、Hashable、Equatable三个接口保证它可以被打印、比较并能作为HashMap的 KeyCube类中正是用Face作为键存储六面状态。操作符*组合出置换群在群论视角下六面旋转操作可以生成一个置换群——群元素就是操作序列群乘法就是先做 A 再做 B。源码重载了*操作符rotation.cjpublic operator func *(that: Rotation): Rotation { match (this) { case X(x1, x2) X(x1, X(x2, that)) // 按此顺序分解重组递归解构时按从左到右的顺序执行变换 case _ X(this, that) } }它把A * B规范化为X(A, B)并且对已有复合结构采取向右嵌套、保持原序的规整策略从而保证无论用户怎么写最终都能按从左到右的线性顺序被递归解构执行。操作符**幂运算表示高阶置换rotation.cj 进一步重载幂操作符用于表示重复执行public operator func **(exp: UInt32): Rotation { var result this for (_ in 0..(exp - 1)) { result result * this } return result }例如(F * F * L * L * B * R) ** 90表示把FFLLBR这一操作串重复 90 次。这是后续验证置换群阶数的基础工具一个置换的阶数就是它需要重复多少次才能还原幂运算恰好让这类验证可以直接用代数式表达。ToString递归打印操作序列Rotation自己实现了打印逻辑rotation.cj原子操作输出字母I(r)输出r并切换逆标记打印⁻¹上标X(x1, x2)按顺序拼接特别地逆变换时需要反序——(A * B)⁻¹ B⁻¹ * A⁻¹这是群论中逆元反序律的代码化体现。hashCode与也直接复用toString()结果保证相同操作序列语义一致。Face语义化的类型别名rotation.cj 中public type Face Rotation把面与操作统一到同一枚举一个面既可以作为状态空间的维度也可以作为针对它的操作这一巧妙的别名让后续HashMapFace, Matrix的键与rotate(face)的参数天然一致。第二层让行列索引可读——Index 与 extend魔方旋转必然涉及取某一面的某一行/列或把某一行/列赋给另一个面。为了把2.r第 2 行、-0.r第 0 行倒置这类读起来像数学记号的东西直接写进代码案例用Index枚举与两次extend完成了类型层面的领域语言。Index带倒置语义的索引matrix.cj 定义了enum Index { Row(Int64) | Col(Int64) | Inv(Index) public operator func -(): Index { match (this) { case Inv(v) v case _ Inv(this) } } public func value(): Index { match (this) { case Inv(v) v case _ this } } }Index只有三个形态行号、列号以及倒置包装Inv。一元负号操作符负责给索引打上/去掉倒置标记value()则剥离标记取回原始索引。这样-0.r就能在类型层面表达第 0 行且换位时反向——这正对应魔方邻面置换中某些行/列需要倒置的真实物理行为。extend Int64用属性把数字变成索引文档特别点出为Int64类型扩展两个属性。源码在 matrix.cj 中做了这件事extend Int64 { public prop r: Index { get() { Row(this) } } public prop c: Index { get() { Col(this) } } }从此2.r、0.c可以直接作为Index使用替代啰嗦的Row(2)、Col(0)配合一元负号即可写出-2.r这种自解释的索引表达式。extend Matrix二维数组的行/列视角matrix.cj 先定义两个类型别名type Vector Array(Face, Int64) type Matrix ArrayVector即每个魔方格的单位是(面, 编号)二元组一行是一组格子整个面是一个二维数组。随后extend Matrixmatrix.cj提供四类能力create(face)静态工厂生成 3×3 的初始矩阵格子编号按3 * i j 1递增形成标准复原态operator func [](index: Index)按行取this[r].clone()按列取Vector(this.size, { i this[i][c] })用lambda一行构造出列向量set(index, value)按行直接赋值按列逐元素写入特别地遇到Inv时先reverse()再赋值——倒置语义在取值时被忽略、在赋值时被落实与置换算法需要的方向约定完全吻合print(row)/print()把一行或整个面展平输出到控制台是后续 View 层的基础。这四段代码集中展示了extend、操作符重载、lambda表达式、函数一等公民与元组解构在数据访问层面的组合威力也正是文档所列知识点第二条、第三条、第四条的落地位置。第三层旋转与置换——魔方转动的两大动作有了数据访问层接下来就是魔方转动的核心算法。从物理上拆解任意一面的 90 度旋转都可以分成两步该面本身 3×3 矩阵旋转以及相邻四个面相应行/列的轮换。面内旋转 rotatecube.cj 实现面内旋转private func rotate(face: Face, inverse: Bool) { const N 3 let matrix Matrix.create(face) let map if (inverse) { { i: Int64, j: Int64 (N - 1 - j, i) } } else { { i: Int64, j: Int64 (j, N - 1 - i) } } for (i in 0..N) { for (j in 0..N) { let (u, v) map(i, j) matrix[u][v] data[face][i][j] } } data[face] matrix }注意这里的两个细节用if表达式直接产出 lambda。if (inverse) { 逆时针映射 } else { 顺时针映射 }的整段求值结果就是一个映射函数这正是文档所说基于if表达式求值、lambda表达式、函数一等公民的典型用法——映射函数被当作值来选择和传递用元组解构消费映射结果。let (u, v) map(i, j)把返回的二元组一步解构为两个下标配合双重循环完成原地坐标变换。顺时针映射(j, N-1-i)与逆时针映射(N-1-j, i)互为反向保证了rotate(face, true)恰好能撤销rotate(face, false)。邻面置换 permute面内旋转只会打乱该面本身要完成一次真实转动还必须把相邻四面的边界行/列同步轮换。cube.cj 的permute接收一个置换序列并执行轮换private func permute(perm: Permutation, inverse: Bool) { let p if (inverse) { perm.inverse() } else { perm.clone() } p.reverse() var (lastFace, lastIndex) p[0] let vector data[lastFace][lastIndex] for (i in 1..p.size) { let (face, index) p[i] data[lastFace].set(lastIndex, data[face][index]) (lastFace, lastIndex) (face, index) } data[lastFace].set(lastIndex, vector) }算法本质是一个环形搬家先备份第一项然后依次把后一项搬到前一项的位置最后把备份放到末尾项的位置。逆操作时先取perm.inverse()再整体reverse()与数学上逆置换 反序反向一致。六面的置换表不同面对应的邻面置换各不相同cube.cj 在static init()中静态构造了六张表例如permutation[F] [(L, 2.c), (U, -2.r), (R, 0.c), (D, -0.r)]这行代码的语义是F 面顺转 90 度时L 面第 2 列 → U 面第 2 行倒置、U 面第 2 行倒置→ R 面第 0 列、R 面第 0 列 → D 面第 0 行倒置、D 面第 0 行倒置→ L 面第 2 列首尾相接成轮换。每个元素都是(面, 索引)元组索引部分全部用2.c、-0.r这种extend Int64提供的可读写法并借负号表达倒置——前面两层铺垫在这里被完整兑现。第四层模式匹配递归执行——transform 与 apply有了旋转与置换两大原子动作剩下的问题是如何把任意复杂的Rotation尤其是X、I递归结构翻译成具体的rotatepermute调用序列。答案在 cube.cj 的transform中private func transform(rotation: Rotation, inverse: Bool): Unit { match (rotation) { case I(r) transform(r, !inverse) case X(r1, r2) // 对复合操作进行递归分解 if (inverse) { // 逆变换需要反序 transform(r2, inverse) transform(r1, inverse) } else { transform(r1, inverse) transform(r2, inverse) } case _ rotate(rotation, inverse) permute(permutation[rotation], inverse) } }这是一个教科书级的模式匹配 递归调用结构case I(r)把取逆降级为翻转inverse标志后递归执行于是任何嵌套逆操作都被逐步化简case X(r1, r2)把复合操作拆成两段且逆变换时交换执行顺序(r1·r2)⁻¹ r2⁻¹·r1⁻¹正变换则保持原序兜底的case _匹配六个原子操作直接执行面内旋转 邻面置换。由于*操作符已经保证复合结构按从左到右线性嵌套这里的递归解构恰好能按书写顺序还原每一步动作形成一个简洁的两层解释器。对外接口applycube.cj接收Rotation以record: Bool false控制是否保留历史public func apply(rotation: Rotation, record!: Bool false) { transform(rotation, false) history.add(rotation) print() if (!record) { reset() } }record: true时操作被加入history并在打印后保留状态适合连续演示record缺省为false时打印完立即reset()回到复原态适合一次性验证某个操作串的净效果——后续的数学验证正是利用这一语义逐条检查的。第五层Controller 与 View——状态管理与会话输出Cube类本身承担了 Controller 与 View 的角色。状态数据public let data HashMapFace, Matrix()以六面为键存放矩阵私有history记录已执行操作序列供打印与回放。reset()cube.cj遍历[F, B, L, R, U, D]重建初始矩阵。打印逻辑print()cube.cj把魔方展平为雷达图式布局先输出提示符与history中全部操作的toString()拼接让用户看到当前状态是如何到达的输出顶面U的完整矩阵对每一行依次输出L、F、R三个面的同一行构成中环三面的横向拼接最后输出底面D与背面B。配合Matrix的print系列扩展整个控制台输出既完整覆盖六个面又以缩进对齐保持了空间上的可读性——这正是 preview.png 中看到的运行形态。数学验证置换群阶数、相似变换与组合子变换案例的压轴部分是 main.cj 中用代数式完成的四组数学验证它们把前面实现的操作代数直接当作数学工具使用。基本操作与复合操作let cube Cube() cube.print() for (r in [F, B, L, R, U, D]) { cube.apply(r, record: true) } cube.reset() cube.apply(F * R * I(F * R)) // 复合操作前六次分别转动六个面并保留状态展示基本操作F * R * I(F * R)则验证了复合操作的书写、逆元与执行顺序。置换群的阶数群论中置换的阶 重复多少次回到单位元。源码依次验证了三组阶数cube.apply((F * F * R * R) ** 6) cube.apply((F * U * L * L * R) ** 36) cube.apply((F * F * L * L * B * R) ** 90)FFRR由 2 阶与 3 阶置换组合而成最小公倍数为 6故重复 6 次必然还原FULLR由 3、4、6、9、18 阶置换组合阶数为 36FFLLBR的阶数为 90。由于**操作符把重复执行编码为幂式代数这三行代码本身就是计算置换阶数的实验程序——若阶数估计错误apply打印出的状态将不再是复原态。相似变换 UGU⁻¹已知G R⁻¹DRFDF⁻¹可以翻转 FUR 角块。若要翻转 BUR 角块不必重新推导公式而是利用相似变换先执行U把 BUR 换到 FUR 位置执行G翻转再执行U⁻¹归位let G I(R) * D * R * F * D * I(F) cube.apply(G) let H U * G * I(U) cube.apply(H)H UGU⁻¹直接写成代数表达式代码与数学记号一一对应展示了操作即值的建模红利。组合子变换 MU⁻¹M⁻¹U组合子commutatorABA⁻¹B⁻¹是魔方公式构造的经典工具。已知MRL⁻¹FFLR⁻¹D⁻¹RL⁻¹FLR⁻¹能保持顶面其他方块不变、仅翻转 UF 棱块但会打乱下面两层。源码先构造并应用M再利用组合子思想构造更精细的公式let M R * I(L) * F * F * L * I(R) * I(D) * R * I(L) * F * L * I(R) cube.apply(M) let N M * I(U) * I(M) * U // 同时翻转 UF 和 UL其余还原 cube.apply(N) let P N * U * I(N) * I(U) // 进一步同时翻转 UL 和 UR cube.apply(P)N M · U⁻¹ · M⁻¹ · U的推导逻辑是先M翻转 UF用U⁻¹把 UL 移到 UF 位置再M⁻¹翻转 UL 并还原下面两层最后U归位——整个魔方最终仅 UF 与 UL 被翻转。P NUN⁻¹U⁻¹再套一层组合子把目标推广为同时翻转 UL 与 UR。整个程序以纯粹的代数表达式书写复杂的魔方公式验证结果全部反映在控制台打印的状态上直观且可复现。小结从魔方中读到的仓颉语言特性回看整个案例它没有使用任何图形库或第三方依赖纯粹用仓颉语言自身的能力搭建了一个可交互、可验证的魔方模型值得关注的语言特性可以总结为递归枚举 模式匹配Rotation用F|B|L|R|U|D | X(Rotation, Rotation) | I(Rotation)表达操作代数transform用match完成递归解构是一等的数据结构设计范式操作符成员函数*、**、、!、一元-、[]的批量重载使数学/物理语义直接映射为代码符号extend扩展机制为Matrix扩展索引与打印、为Int64扩展r/c属性让领域语言长在既有类型之上无需继承if表达式、lambda与函数一等公民旋转映射作为值被if表达式选出、被lambda构造配合元组解构完成紧凑的坐标变换代数式编程置换群阶数、相似变换、组合子变换均以可执行代码的形式呈现程序既是模拟器也是数学规律的验证器。对希望深入仓颉语言特性的读者建议按 rotation.cj → matrix.cj → permutation.cj → cube.cj → main.cj 的顺序通读源码并亲自修改main.cj中的操作串例如调整(F * U * L * L * R) ** 36的幂次观察输出变化你会更快理解操作即数据、公式即代码这一设计思想。赞分享示例工程教程【免费下载链接】Cangjie-Examples本仓将收集和展示高质量的仓颉示例代码欢迎大家投稿让全世界看到您的妙趣设计也让更多人通过您的编码理解和喜爱仓颉语言。项目地址https://gitcode.com/Cangjie/Cangjie-Examples点击查看免费下载相关推荐【从入门到精通】Cangjie-Examples全案例详解用仓颉语言构建AI与高性能应用【从入门到精通】Cangjie Examples全案例详解用仓颉语言构建AI与高性能应用 为什么选择Cangjie Examples 你是否还在为寻找高质量示例工程教程2025最新版仓颉语言实战Cangjie-Examples全场景安装与核心功能解析2025最新版仓颉语言实战Cangjie Examples全场景安装与核心功能解析 导语为什么选择Cangjie Examples 你是否还在为仓颉C示例工程教程仓颉语言三方库开发实战vcard4cj电子名片解析库源码中8个Cangjie核心特性解析仓颉语言三方库开发实战vcard4cj电子名片解析库源码中8个Cangjie核心特性解析 vcard4cj 是一个用仓颉语言Cangjie编写的开源三方库上一篇PredictionIO 引擎算法切换实战从 NaiveBayes 平滑迁移到 MLlib Random Forests下一篇Jekyll 未来日期文章发布机制解析Minimal Mistakes 主题中的 --future 实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考