用 Ruby 词法记号长度背诵圆周率:解析 TRICK 2015 金奖作品 kinaba/entry.rb 的 Piphilology 技巧

发布时间:2026/9/13 5:42:20

用 Ruby 词法记号长度背诵圆周率:解析 TRICK 2015 金奖作品 kinaba/entry.rb 的 Piphilology 技巧 用 Ruby 词法记号长度背诵圆周率解析 TRICK 2015 金奖作品 kinaba/entry.rb 的 Piphilology 技巧【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby导读本文深入剖析 Ruby 官方仓库 sample/trick2015/kinaba/ 下获得 TRICK 2015第 2 届 Transcendental Ruby Imbroglio Contest即 RubyKaigi 上的 Ruby 黑魔法大赛金奖的参赛作品entry.rb。该作品以 Best piphilology最佳圆周率记忆法为名实现了一个用 Ruby 词法记号lexical token长度编码圆周率数字的极致脑洞程序本身既是 Pi 的记忆口诀运行时又能输出 10000 位圆周率。读完本文你将理解 Ripper 词法分析驱动的 Pi 编码原理、srand返回值作为隐式赋值槽的黑魔法、以及 TRICK 4096 字符限制下的程序嵌入策略。TRICK 2015 与获奖作品背景sample/trick2015/README.md明确说明该目录收录了第 2 届 TRICKTranscendental Ruby Imbroglio Contest for rubyKaigi的获奖作品并特别强调这些是反面教材BAD EXAMPLES绝不能把它们当作示例代码来学习 Ruby。其中 kinaba/entry.rb 获得Gold award金奖获奖称号为 Best piphilology。整个目录结构如下kinaba/entry.rbBest piphilology —— 金奖ksk_1/entry.rbMost unreadable ALU —— 银奖monae/entry.rbDoubling amphisbaena award —— 铜奖eregon/entry.rbLeast general solver —— 第 4 名ksk_2/entry.rbMost general solver —— 第 5 名所有作品以 MIT 许可证发布。TRICK 的玩法核心在于参赛者必须在代码中同时满足程序能正常运行完成特定任务与代码满足某种极端的自指约束双重条件而本文主角的约束就是每个词法记号的长度必须对应 π 的数字序列。Piphilology用词长记忆圆周率英文世界的历史传统remarks.markdown首先指出这个程序是一种面向 Rubyist 的Piphilology圆周率记忆法。在英语世界背诵圆周率的诗歌遵循一个规则第 n 个单词的字母数就是 π 的第 n 位数字。经典的开头是How I wish I could calculate pi → 3, 1, 4, 1, 5, 9 ...即每个单词的长度依次对应 3-1-4-1-5-9。当某位数字为0时使用一个 10 字母的单词来表示因为 10 % 10 0。Ruby 的翻译词法记号长度即数字作者把这一传统移植到 Ruby源代码中每个词法记号token的字符长度对 10 取模就得到 π 的一个数字。注意这里的关键是词法记号而非单词——因为 Ruby 的空白符空格、换行、缩进不影响分词所以整段源码可以任意换行排版而 Pi 的编码完全由 token 本身决定。文档中给出了验证方法用标准库 Ripper 对源文件做词法分析$ ruby -r ripper -e \ puts Ripper.tokenize(STDIN).grep(/\S/).map{|t|t.size%10}.join entry.rb 31415926535897932384626433832795028841971693993751058209749445923078164062862...这里Ripper.tokenize返回源码的全部词法记号来自仓库中的 ext/ripper/lib/ripper/lexer.rb 与 ext/ripper/lib/ripper/core.rb 等实现grep(/\S/)过滤掉纯空白 token再对每个 token 求长度并取模 10拼起来恰好是 π 的前缀。也就是说整个程序的排版本质上就是一篇用 Ruby 关键字、类名、常量、运算符填字写成的 Pi 长诗。同时直接运行程序也能得到同样的输出——它在计算并打印前 10000 位 π$ ruby entry.rb 31415926535897932384626433832795028841971693993751058209749445923078164062862...程序运行要求运行方式非常简单无需任何参数$ ruby entry.rb作者确认的实现/平台ruby 2.2.3p173 (2015-08-18 revision 51636) [x64-mingw32]也就是说这是在 2015 年的 CRuby 2.2.3Windows 64 位构建上验证通过的。由于程序依赖的srand返回值语义、Ripper 分词规则以及Integer等 Kernel 方法都属于语言核心行为现代 CRuby 上基本同样可以运行但若要严格复现当年的验证环境应以该版本为准。内部原理Token 长度的硬约束词法记号不是简单的空格分词remarks.markdown特别强调了一个微妙点token 并不是按空格切分得到的最小单元。例如表达式a*b cdef并不表示数字序列 [3, 1, 4]即 a*b 3 字符、 1 字符、cdef 4 字符实际上 Ripper 会将其切分为 5 个 tokena、*、b、、cdef对应 [1, 1, 1, 1, 4]。这意味着什么一旦你决定写一个多字符的标识符后续连续的非空白字符都会被独立计数。这种token 长度税对代码写作施加了极其严苛的约束你不能自由选择变量名长度因为每个字符都在 π 的编码序列里消费掉一个位置不能随意写注释注释里的词也会被计入字符串字面量的内容长度也会影响编码。这是整个作品最核心的工程难点——所有代码逻辑都必须在每个 token 长度已由 π 的某一位数字事先规定好的前提下进行。理论上可行实践中困难文档随即指出一个深刻的观察π 被广泛认为是一个正规数normal number即任何有限数字序列都会在其小数展开中出现参见 Wikipedia 的 Normal number 条目。如果这一猜想成立那么从理论上讲任何程序都可以被藏进 π 的某段数字中——你只需要把程序分词后的 token 长度序列当作一段数字串去 π 里找到它的出现位置即可。但在实践中这远非易事尤其是在 TRICK 的4096 字符代码长度限制下。文档给出了量化的论证假设你想嵌入某个程序片段其 token 长度序列比如g hij对应的 [1, 2, 3]在 π 中随机均匀出现那么期望每隔 1000 位才出现一次而为了到达那个位置前面的 500 万个填充字符平均约 5000 字符/位 × 1000 位早已远超 4096 字节的限额。如果老老实实按找到位置再填充的思路来写代码体积会爆炸到原来的 333 倍以上文档估算 blowup 为 1000/3。因此必须使用一些 TRICK 级别的技巧来压缩开销。四个关键黑魔法remarks.markdown的 Internals 一节公开了作者的四个核心技巧1. 全局变量别名alias $a $balias $curTerm $initTermRuby 的alias关键字可以给全局变量起别名。作者用这个特性实现同一个值在不同 token 长度位置上的复用同一个数学变量如累加项$curTerm可以同时拥有短名字和长名字从而在不同数字位要求下比如某个位置需要 1 字符 token、另一个位置需要 8 字符 token都能放得下。这相当于把 token 长度约束下的取名自由最大化。2. srand 作为隐式赋值槽srand $counter 0x00000001这是整个作品最精巧的一招。根据 random.c 中srand的文档call-seq:srand(number Random.new_seed) - old_seedsrand以给定数值为种子重置伪随机数生成器并返回上一个种子值。因此srand这个调用本身其长度是固定的 5 个字符对应数字 5恰好是%10后的 5通过传入不同的表达式它可以消费某个数值最重要的是srand不用等 1 字符的赋值号就能把值存储下来——因为返回值上一个种子本身就可以被后续的srand或Integer等上下文使用。作者说 the token-length5essentially becomes a value-store that can be written without waiting for the 1-letter token。也就是说在 π 的数字序列里5 出现得足够频繁可以把srand当作一个自带存储语义的槽位随时用它来暂存/传递数值从而绕开必须恰好在一个位置放下赋值号的严苛约束。这在源码中体现为大量srand的链式使用例如$initTerm || Integer srand * 0x00000002。3. 精心挑选的 77-token 核心计算程序组合上述技巧后作者设计出一个只有77 个 token的 π 计算核心它被嵌入到 π 的前242 个 token中。核心程序如下big, temp Array 100000000**0x04e2 srand big alias $curTerm $initTerm big big init || big $counter || 02 while 0x00012345 $counter numbase 0x0000 $initTerm || Integer srand * 0x00000002 srand $counter 0x00000001 $sigmaTerm || init $curTerm / srand pi, Integer $sigmaTerm $counter 1 srand big $counter 0b1 num numbase | srand $sigmaTerm $curTerm pi 3_3_1_3_8 $curTerm * num end print pi剩余 165 个 token 则是无操作no-op的填充物——在entry.rb中可以看到大量成串的类名Numeric、Interrupt、Enumerable、String……、关键字begin/rescue/ensure、next/redo、defined?、字面量3.1415e0、31i、55555、false以及instance_variable声明它们存在的唯一目的就是凑出 π 对应位置的 token 长度同时不改变程序语义。对比333 倍体积爆炸的朴素方案242/77 ≈ 3.14 的膨胀率显得极为优雅。4. π 的 10000 位输出是真实计算的作者特别强调The 10000 digits output of Pi is seriously computed with no cheets——没有任何作弊这 10000 位是程序真正算出来的并非硬编码常量。所用公式为Pi/2 1 1/3 1/3*2/5 1/3*2/5*3/7 1/3*2/5*3/7*4/9 ...这是 Wallis 型无穷乘积的变体。在 token 约束下$sigmaTerm扮演累加和、$curTerm扮演当前项$curTerm $curTerm * n / (2n1)形式的迭代在代码中被编码为$curTerm / srand # 除以 (2n1) $curTerm * num # 乘以 n $sigmaTerm $curTerm # 累加用大整数Integer定点运算把精度推到 10000 位最后print pi输出。整个循环被压缩进一个while 0x00012345 $counter的巨型循环里74565 次迭代配合$counter 1等计数技巧全部逻辑都塞进了 token 长度的枷锁之中。最终彩蛋膨胀率也是 π文档在结尾抛出一个饶有趣味的自指问题最终代码的膨胀率blowup ratio是多少答案是242 / 77 3.14159... ≈ 3.14连填充代码相对于核心代码的膨胀率本身前三位都是 3.14。这个作品在程序内容、程序行为、程序元信息三个层面都与 π 形成了自洽的呼应——可以说这不是一段打印 π 的代码而是用 π 写出来的一段代码它恰好也算出了 π。总结kinaba/entry.rb之所以能拿下 TRICK 2015 金奖在于它同时做到了三点表层源代码的 token 长度序列精确复现 π 的数字用 Ripper 一验便知公开、可验证里层程序真实运行并计算出 10000 位 π使用大整数定点迭代而非常量作弊元层代码体积膨胀率、嵌入策略、srand复用等所有工程细节都被统筹进与 π 相关的主题下连最终的 242/77 ≈ 3.14 都是精心设计的结果。对于想深入研究的读者可以在仓库中继续探索完整的参赛源码 sample/trick2015/kinaba/entry.rb含全部填充 token、作者备注 sample/trick2015/kinaba/remarks.markdown、TRICK 2015 全部获奖作品 sample/trick2015/README.md以及支撑srand返回值语义的 random.csrand的 call-seq 明确记载 The previous seed value is returned和提供词法分析能力的 ext/ripper/lib/ripper/lexer.rb。需要说明的是这是一件反教材性质的艺术品其代码风格绝不代表 Ruby 的最佳实践——它存在的意义是展示一门语言在极端约束下能爆发出的创造力上限。【免费下载链接】rubyThe Ruby Programming Language项目地址: https://gitcode.com/GitHub_Trending/ru/ruby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/13 5:42:20

MP-GWO算法在多无人机协同路径规划中的应用与优化

1. 项目概述 多智能体无人机协同作业已经成为现代智能系统的重要研究方向,其中航迹路径规划是核心挑战之一。传统算法在处理复杂环境下的多无人机协同规划时,往往面临收敛速度慢、易陷入局部最优等问题。MP-GWO(多种群灰狼优化)算…

2026/9/13 5:42:20

C++行为树开发实战:BehaviorTree.CPP入门指南

1. 行为树基础概念解析 行为树(Behavior Tree)是一种在游戏AI和机器人控制领域广泛使用的决策架构。与传统的有限状态机相比,行为树采用树状结构组织行为逻辑,具有更好的可读性和可维护性。BehaviorTree.CPP是一个用现代C&#xf…

2026/9/13 6:47:22

CSP-J备考指南:规避算法热搜陷阱,掌握六大基础算法稳拿奖

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 6:47:22

Shell脚本路径可靠性保障:realpath原理与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 6:47:22

大语言模型架构与训练关键技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 6:47:22

DeepSeek Harness工程实践:构建可控AI代码插件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/13 6:42:22

C++课程设计实战:打地鼠游戏的状态机与实现

简介:这是面向高校C课程设计和期末大作业的实用项目资源,提供基于Qt框架的打地鼠游戏完整工程。代码涵盖随机生成地鼠、鼠标点击判定、计时计分、胜利与结束界面等核心模块,既可直接编译运行作为验收成果,也适合作为学习游戏循环、…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/12 6:37:43

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码