IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者
首页 / 云风的BLOG
IT 2026-06-14 05:40:22 / 累计浏览 60

对基本有序的序列排序算法

排序算法在处理基本有序序列时能显著优化性能。传统快速排序效率高但不稳定,插入排序简单却平均复杂度高。归并排序提供稳定性和O(n log n)复杂度,但需要额外内存。现实数据常局部有序,Tim Peters在2002年针对此改进归并排序,提出Timsort算法,广泛用于Python等语言。Timsort先扫描序列识别有序片段(run),再启发式合并这些run以减少比较次数。然而,原始Timsort的合并规则存在栈溢出风险,经形式化证明后通过添加规则修复。Python 3.11进一步引入Powersort,基于虚拟二叉树概念,将栈上限固定为64,合并决策更贴近完全二叉树,简化了栈管理。此外,Timsort还包含多项优化:如利用局部有序性减少合并空间需求、galloping模式加速连续数据处理、逆序快速翻转,以及动态调整最小run size以平衡分片。这些算法通过挖掘数据特性,在工程实践中大幅提升排序效率,是算法与实际应用结合的典范。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 20

Skynet 升级到 Lua 5.5.0

Skynet 随 Lua 5.5.0 正式发布完成了版本升级。Skynet 维护的定制版 Lua 核心特性是允许跨虚拟机共享函数原型,以此节省服务初始化时间和内存。实现此功能的关键难点在于正确处理短字符串内部化(interning)与外部导入原型中字符串的共存问题,该问题通过专门的补丁解决,副产品是支持了跨虚拟机共享只读常量表(可通过 skynet.sharetable 使用)。然而,鉴于 Lua 5.5 引入的 external strings 特性已大幅提升字节码加载速度,建议新项目避免依赖该补丁功能,以降低维护成本。 Lua 5.5 基本兼容 5.4,大多数 Skynet 项目无需大改,但升级后务必充分测试,并使用 `make cleanall` 强制重新编译 Lua。此次升级带来了多项有益改进:新增 `global` 关键字有助于减少拼写错误;分代垃圾回收(GC)改为步进式执行,解决了过去处理大内存服务时的停顿问题;新的不定长参数语法 `...args` 允许以表格形式访问参数,能简化部分代码实现。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 60

用 AI 辅助读书

在闲暇时间重拾小说阅读后,作者发现利用AI能有效解决两大痛点:书籍推荐与语言障碍。推荐方面,通过Gemini模型列举喜爱的书籍或作者,能快速获取个性化书单,并主动探索陌生类型以拓宽阅读边界。针对英文新作中文译本匮乏的问题,作者尝试将传统逐句翻译与AI辅助结合:采用中英对照的机械直译保持信息完整,同时借助Gemini处理复杂句子的文化语境与背景知识,例如解释英文中皇帝自称“We”的特定用法。 这种混合方法显著提升了英文小说的可读性。虽初期阅读速度放缓,但通过适应中英文切换与上下文理解,作者逐渐在机械直译的“准确”与AI解释的“灵活”间找到平衡。以《互惠帝国》三部曲为例,随着对系列故事框架的熟悉,阅读节奏明显加快,印证了理解作品结构能降低后续阅读门槛。最终,AI不仅作为工具弥补了翻译资源的缺口,更通过上下文解析帮助读者跨越语言与文化隔阂,在保持原著韵味的同时,让沉浸式阅读体验得以延续。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

Star Trek : Captain's Chair 初体验

《星际迷航:船长之椅》是一款2025年发布的重度卡牌构筑桌游,规则复杂(BGG权重达4.06)。游戏核心在于动态管理卡组,通过LOG(永久移除)、deploy(部署至桌面)、beam(临时传送至飞船或星球)等多种机制进行灵活的卡组瘦身,显著提升了操作确定性。每张卡牌设计为一卡多用,且玩家在回合结束时可保留手牌、弃牌堆抽牌、新牌入堆位置可选等方式,深度调控牌堆轮转与升级节奏。游戏为每个舰长设计了差异化的初始牌组与固定补充卡堆,市场获取也改为通过特定行动卡实现。单人模式提供无干扰教学、对抗自动化Bot的不对称对战,以及可连续进行5-10局的长期升级“五年计划”。电子模拟版虽便捷,但实体版在触感、操作及反悔便利性上更具优势。作者学习过程中尝试使用AI(如Gemini)辅助理解规则,但AI对细节信息的处理常出现错误和“幻觉”,反映出在专业、小众领域辨别LLM信息价值的重要性。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 20

soluna 外挂 C 模块

soluna 默认静态链接 Lua 虚拟机,导致无法直接外挂动态链接的 C 扩展,因为动态链接会引入多份 Lua 实现,引发运行时错误。根源在于 Lua 中全局空对象的静态引用机制:多份实现会生成多个空对象,运行时比较时出现不一致。虽然 Lua 5.4 后将空对象移入运行期结构以缓解问题,但作者仍强调应避免多份实现。Windows 平台因 DLL 必须编译时绑定所有符号,问题尤为突出。 为解决此问题,soluna 采用新方案:外部 C 扩展库链接代理模块 extlua.c,该模块不依赖 Lua 内部实现,而是利用 lua_getextraspace 宏注入 Lua C APIs。外部库需定义 extlua_init 入口函数,在其中调用 luaapi_init 注入 APIs,再通过 luaL_newlib 注册模块函数。soluna 的加载器通过创建临时虚拟机、传递 APIs 引用并复制入口表来完成动态加载。这种方法同时兼容动态库

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

除法的意义

作者发现三年级女儿可可在掌握除法计算后仍无法理解其意义,表现为面对实际问题时无法将“装盒”场景与除法运算关联。通过实物操作(用token和碗模拟装鸡蛋)和逐步抽象化的引导,作者帮助孩子从具体行为中推导出除法的本质:连续减法的次数记录。例如通过“30个鸡蛋每10个装一盒”的实物操作过渡到用减法计算30-10-10-10=0并数次数,使孩子领悟除法符号的简化作用。进一步通过矩形图示解释乘除法的交换关系(8×10与10×8对应图形旋转),并拆解96÷8为80÷8+16÷8的分步计算,最终让孩子将除法竖式与实际分组过程对应起来。整个过程强调数学符号的具象化意义——符号是帮助思维的工具,但需先理解其代表的实际逻辑。通过一小时的具体演绎,孩子初步建立起除法作为“重复减法”的操作意义与乘除法间的互逆关联认知。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

对数和自然对数的底

对数概念的发明源于天文学中对大数乘除法的简化需求,特别是在通过三角视差法测量天文距离时。由于日地距离已很遥远,测量更远的恒星需要极高的精度,计算误差会显著影响结果。约翰·纳皮尔在没有幂概念的情况下,通过三角公式的启发,从几何意义出发发明了对数。其核心思路是构造一个等比数列,使真数的乘法运算转换为对应等差数列的加减运算。他选择了一个非常接近1的公比(约为0.9999999),这使得等比数列的递推可以通过简单的移位和减法实现,极大方便了手算。在当时以十的七次方为半径的三角函数表背景下,这个选择使得对数表的底数近似为(1+1/10^7)^(10^7),其极限即为自然常数e。因此,以e为底的对数之所以被称为自然对数,并非源于纳皮尔的本意,而是因为e是通过对数运算的自然数学构造过程(令公比的指数趋于无穷)而产生的必然结果。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

一个简单的 A star 寻路算法实现

这篇讲的是一个极简A*寻路算法的实现,作者从实用角度出发,重新设计了一套C语言接口,核心特点是与地图数据结构完全解耦,方便移植到不同场景。 实现上最巧妙的是用单向链表替代了传统A*中复杂的优先队列,同时把所有寻路数据压进一块平坦内存,这样既避免了算法执行中的内存分配,又天然兼容多线程环境。底层数据结构是一个闭散列哈希表,作者用一个自增的version值巧妙实现了O(1)复杂度的表重置,大幅降低重复寻路时的初始化开销。 考虑到实际地图规模,算法内置了安全阀:当哈希表使用率超过一半时自动中止,但会返回已找到的离目标最近的中途点,用户可多次调用拼接完整路径。作者还贴心地提供了可视化函数,能将哈希表内部状态输出为灰度图,方便调试。 虽然代码刚写好还未充分测试,但作者追求的“接口简单、数据结构通用、内存开销固定”的设计目标清晰明确,适合那些需要轻量、易集成寻路功能的项目。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

SetWindowText 引起的死锁

在基于ltask多线程框架的游戏开发中,使用sokol_app封装窗口时遇到了启动阶段偶发黑屏的问题。经排查,死锁源于跨线程调用SetWindowTextW修改窗口标题。由于该API内部通过SendMessageW投递WM_SETTEXT消息,要求窗口线程处理完毕才能返回,而窗口线程当时正阻塞在另一个同步锁上,形成循环等待。 Windows消息机制要求通过SendMessageW发送涉及字符串生命周期管理的系统消息,因此不能简单改用PostWindowTextW避免阻塞。最终解决方案是在ltask框架内创建一个独立服务来执行SetWindowTextW,通过服务间异步消息传递修改标题指令,从而避免阻塞主帧处理流程。这一案例揭示了多线程环境下GUI消息循环与任务调度器交互时的典型死锁陷阱,关键在于理解Windows线程消息队列的同步特性,并设计解耦的线程通信机制。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 60

编写游戏程序的一些启示

在制作《Deep Future》桌游电子版的过程中,作者通过实践深入探讨了游戏程序开发的多个核心问题。他选择基于自研引擎进行开发,旨在理解游戏玩法设计与交互实现的难点,而非追求性能优化。在渲染架构上,他经历了从纯立即模式向混合模式的演进:保留模式用于管理如HUD布局和文本排版等静态层次结构,而立即模式则用于实现动态对象的灵活渲染。针对卡牌游戏特有的复杂图文混排需求,他借鉴了CSS布局思想并集成了Yoga库,同时通过自定义富文本协议解决了本地化与文本拼接的难题。 为分离游戏逻辑与视觉表现,作者引入了基于协程的状态机模型,以自然的时间序列模拟卡牌动画等流程。在交互管理上,他设计了兼顾立即模式风格的焦点轮询机制,通过平坦化的“区域”和“按钮”集合简化了事件处理。这些实践表明,游戏开发中合理的架构分层与状态管理是应对复杂性的关键,而持续的小幅迭代和反思比追求完美方案更能有效推动项目进展。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

在 Lua 中定义类型的简单方法

文章以教程形式探讨了在Lua中定义类型的简洁方法,重点介绍了从基础到进阶的实现策略。首先,作者展示了通过table和元表设置来创建类型的基本方式,这种方法依赖Lua模块机制,适合快速定义独立类型。随后,文章深入讨论了封装class模块的高级方案,通过统一管理类型定义和实例化,提供类型名查找功能,增强了代码组织性。内容核心转向

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 20

立即模式下的鼠标交互处理

这篇讲的是作者在立即模式游戏中遇到的鼠标交互混乱问题。随着界面复杂度增加,原先草率处理的回调代码开始无法应对各种边界情况,比如添加长按操作时发现逻辑已经难以维护。 问题的核心在于消息机制与立即模式的冲突:鼠标移动、点击等事件在帧间以队列形式抵达,而立即模式需要清晰的状态快照。作者发现,像“点击”和“焦点”这类行为本质上是时间跨度的状态,而非瞬间消息。 他的解决方案是重构底层:首先,将鼠标消息在帧间累积,每帧统一发送状态(如位置、按键是否按下)。关键创新在于把“点击”定义为一个独立状态——从按下到抬起的时长,并且这个状态只持续一帧。同时,他引入了焦点管理器,每帧跟踪焦点对象及其持续的帧数。通过比较点击时长和焦点持续时长,就能准确判断一个点击是否真正发生在某个交互对象上。 这套方案让游戏业务能以纯粹的立即模式书写,每帧获得清晰的鼠标状态。作者还提到,可以在此基础上进一步优化,比如仅在焦点改变时更新UI,避免每帧刷新的开销。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

有惊无险的一次网站系统升级

本次系统升级涉及操作系统、PHP、Apache及MySQL等多个组件的跨版本升级。作者将运行超过十年的老旧系统从Ubuntu早期版本逐步升级至2024 LTS,其中MySQL从4.x版本强制升至8.x版本引发的字符集问题尤为棘手。博客数据库原采用GBK编码存储,升级后字段编码信息丢失导致内容显示为乱码。作者通过查阅官方文档、社区求助及本地实验,最终采用二进制模式导出数据库,并编写Lua脚本智能解析导出文件,准确识别并转换其中的GBK内容,同时保留混杂的UTF-8数据片段,成功完成向UTF-8的迁移。整个过程体现了对历史遗留数据的审慎处理,包括备份验证、分段转换、语法校验等关键步骤。升级后系统运行稳定,预计可支持长期使用。

本机暂存
IT 2026-06-03 09:03:24 / 累计浏览 40

深远未来开发总结

本文是一位独立开发者对《深远未来》桌游数字化项目的开发总结。作者从兴趣出发,旨在实践中探索游戏开发难题。整个开发历时约七周,期间穿插搬家等意外,但通过清晰的流程规划和对开发情绪的重视,最终完成了游戏的第一个可玩版本。 技术层面,作者基于自研引擎soluna进行开发,初期为提升效率选择了结构化文本描述界面而非图形编辑器。在将游戏规则转化为数字交互的过程中,面临诸多挑战:例如如何将桌游中自然的、多线程的玩家决策(如advancement效果结算)转化为合理的数字版交互流程,同时又不丢失原版的游戏感和规则深度;如何设计底层的提示与状态机系统以管理复杂的游戏流程;以及如何处理后期的胜利结算、存档、文明卡等复杂功能模块的实现与重构。 作者反复强调保持开发热情的重要性,通过按游戏流程次序逐步实现功能、保持每日进度、及时提供视觉反馈等方式来维持动力。同时,他也认识到过早追求快速实现会导致代码冗余,因此将“尽早且频繁的重构”作为关键经验。开发后期,通过开源吸引了程序员参与合作,共同完善了跨平台支持和本地化,验证了协作对独立项目的增益。 最终,项目代码量控制在约两万行。作者总结,控制代码规模需做好数据与引擎分离,而记录并适时优化代码结构比性能优化更为优先。这次经历让他坚信,明确的任务拆分、对开发情绪的管理以及对代码所有权的重视,是独立游戏开发成功的关键。

本机暂存
IT 2026-06-03 09:03:23 / 累计浏览 40

卡牌构筑类桌游核心规则之二

卡牌构筑类桌游的核心规则设计侧重于平衡玩家行动与决策深度。传统TCG通过打出卡片的费用限制强力牌,但DBG采用购买费用作为限制,确保牌组逐步增强。Dominion限制每回合打出行动卡的数量,通过特定卡牌扩展行动次数,防止早期运气优势。Ascension则不限制打牌数量,但通过VP获取的双重途径(符文购买与杀怪)和公共市场的随机性来制约强力组合的发挥,玩家需在构筑时权衡符文与力量能力。 Nightfall引入六色轮连锁系统,要求按颜色顺序出牌,并允许对手在玩家回合加入连锁,增加互动性。其伤害卡机制将受到攻击的惩罚转化为手牌优势,但限制额外抽牌以防失衡。Unchained作为重置版,改进市场为3x3矩阵,简化费用为两级,并引入天赋点资源;起始手牌改为随机抽取,加快游戏节奏。游戏设计中,通过限制手牌打出、弃牌和构筑行为,为玩家提供有意义的选择空间。Nightfall和Unchained的变化体现了

本机暂存
IT 2026-05-10 18:35:06 / 累计浏览 180

嵌入主线程消息循环的任务调度器

这篇文章聚焦于将基于多线程调度器的项目 `soluna`,移植到 WebAssembly 等非 Windows 平台时遇到的核心难题。作者从项目维护的实际需求出发,解释了为何在可能退化为单线程的环境中,模拟出 `ltask` 调度器的能力成为关键挑战。 文中介绍的核心实现思路颇具巧思:将原本独立的任务调度器巧妙地“嵌入”到主线程自身的消息循环里。这意味着主线程需要同时承担两份工作——既要处理自己的消息队列,又要扮演调度器的角色,为其他逻辑“线程”(通常是协程)分配执行机会。作者没有停留在理论层面,而是深入探讨了如何在单一线程上,通过协作式调度和精心设计的队列,来模拟多线程环境下的任务切换与调度行为。 这种设计确保了项目的多线程调度架构得以保留,其核心价值不因平台变化而丧失。文章清晰地展示了一个现实场景下的工程权衡与技术适配过程,对于需要处理类似跨平台移植问题,或是对单线程高并发模型感兴趣的开发者而言,提供了非常具体的实现参考。

本机暂存
IT 2022-07-24 20:47:15 / 累计浏览 4,400

一个 VLA (可变长度数组)的实现

这篇讲的是作者如何用C语言实现一个更实用、更安全的可变长度数组库。C99引入的VLA特性因安全问题已被MSVC和Linux内核相继放弃,但在日常开发中,变长数组的需求依然存在。现有的通用方案,如C++的std::vector或简单的void*实现,在类型安全、性能(堆内存分配)和与特定运行时(如Lua)的集成方面各有不足。 作者的方案核心是将VLA拆分为抽象的“句柄”和类型化的“访问器”。通过`vla_using`宏,在栈上创建一个指向实际数据的原生指针作为访问器,同时关联句柄,从而在保证类型安全和原生数组访问性能的同时,提供了清晰的API。为兼顾临时使用与持久引用的不同场景,方案统一了栈上缓存与堆分配的切换逻辑。 更巧妙的一点是,作者针对与Lua交互的场景,实现了利用Lua GC管理内存的第三种模式:小块内存直接分配在C栈上,大块内存则转为Lua临时userdata,随函数退出自动回收,省去了手动清理的麻烦。整个实现展示了如何在C语言的限制下,通过宏技巧和分层设计,构建出一个既高效又贴合实际工程需求的通用数据结构。

本机暂存
IT 2022-07-24 20:46:45 / 累计浏览 4,000

用邻接表实现无向图

这篇讲的是作者在游戏管道系统扩展中,如何用邻接表实现一个无向图数据结构。作者从原有的液体管道系统(采用类似树的固定数组存储)出发,面对电线网络等新需求——节点无方向且可多邻接,决定重新设计。核心思路是将节点id与边关系分离,便于模块化复用。具体实现上,每条边用32位紧凑表示(16位端点id对,小id在低位确保唯一性),并设计了一个巧妙的结构:在边数据中加入两个链表指针,分别指向两端点所属的边集合,从而支持高效遍历。 更精巧的是,作者进一步压缩了存储:通过将其中一端点的边集合连续排列,另一端以链表链接,并用“反转端点id”来标志链表结束(通常小id在前),最终每条边只需48位。文章以九宫格网格图为例,完整演示了如何从节点索引开始,逐步追踪并找出顶点5的全部四条邻接边。作者坦言这种无向图实现并非日常工作所需,但经过半天编码,能写出这样紧凑高效的结构让他颇为满意,其压缩方案甚至可能具有一定的原创性。

本机暂存
IT 2021-05-28 08:35:55 / 累计浏览 2,460

fbx 到 gltf 转换问题

这篇文章讲述了游戏引擎团队在迁移到 glTF 格式时,为解决美术工具导出支持不足与 FBX 私有格式带来的转换问题所经历的系列尝试。作者从项目背景出发,详细记录了团队评估和使用四个不同方案的过程:先是发现 Assimp 工具臃肿、编译问题多且存在链接失败 bug,因而放弃;继而尝试自行编写 FBX 解析模块,但意识到数据转换的繁杂性远超预期,非长期维护之选;接着采用 Facebook 发布的 FBX2glTF,却在对方停止维护后陷入 bug 无法修复的困境;最终转向 Blender,利用其优秀的命令行脚本支持、官方 glTF 插件以及详尽的 FBX 文档,形成了稳定可靠的工作流。文章不仅分享了具体的技术选型思路与踩坑经验,也反映了从私有格式走向开放标准过程中的现实挑战与务实解决策略。

本机暂存
IT 2021-05-28 08:32:57 / 累计浏览 2,440

不变量及运算优化

这篇讲的是游戏引擎开发中一个看似简单却消耗10%以上CPU时间的性能坑。作者从实际Profiling结果出发,发现每帧重建渲染队列时,需要对每个可渲染物件的包围盒进行世界空间变换运算,而场景中大量静态物件的这类运算是重复的。 问题的根源在于输入数据量太大(40个float),直接用作缓存键并不现实。巧妙之处在于,作者利用数学库中矩阵已作为不变量拥有唯一ID这一现有设计,将世界空间矩阵的ID作为缓存键,大幅缩减了比较开销。最终,缓存能按“世界矩阵ID”匹配并直接复用上一帧计算好的所有子模型变换结果,避免了重复计算。这个优化思路透明地解决了问题,而无需对场景或资源系统进行大改。

本机暂存