随机地下城房间生成器

把 9 类地下城素材按种子拼成结构完整的房间:形状、大小、墙面、地面、家具、光线、气味、声音、危险各取一条,用「 · 」连成一行。默认种子 3-7、5 间房,含危险 2 个、黑暗 1 个。LCG 确定性算法,同一个种子加批次号永远复现同一批房间,刷新页面结果不变,支持 1~12 间批量生成与 CSV 导出。

种子 3-7、第 1 批固定推出这 5 间房,刷新不变;换一批只把批次号加 1。
序号形状大小危险项明暗
1半圆形壁龛室双层挑高墙缝里伸出的触手只够到你脚踝有光
2穹顶圆形大厅篮球场大小无明显危险,只有灰尘有光
3圆形竖井底仅容一人转身安全的死角,适合歇脚黑暗
4八角形小间壁橱大小墙缝里伸出的触手只够到你脚踝有光
5双柱间方厅双层挑高无明显危险,只有灰尘有光
6穹顶圆形大厅壁橱大小地板下埋着翻板,踩错三块就漏黑暗
7圆形竖井底篮球场大小闻不到也听不到任何活物黑暗
8半圆形壁龛室壁橱大小安全的死角,适合歇脚有光
9圆形竖井底下沉半米的凹室地板下埋着翻板,踩错三块就漏有光
10正方形石室双层挑高无明显危险,只有灰尘有光
11圆形竖井底壁橱大小无明显危险,只有灰尘有光
12半圆形壁龛室篮球场大小闻不到也听不到任何活物黑暗
13半圆形壁龛室一步长宽(约 2 米)火把余光里有一双眼睛,没动有光
14长方形厅堂宴会厅大小(约 60 平米)天花板在缓慢地、持续地掉砂有光
15狭长走廊尽头的小室篮球场大小门后会落下插销,从外面锁死有光
16正方形石室一步长宽(约 2 米)闻不到也听不到任何活物有光
17双柱间方厅篮球场大小闻不到也听不到任何活物有光
18双柱间方厅下沉半米的凹室闻不到也听不到任何活物有光
19狭长走廊尽头的小室普通卧室大小(约 12 平米)看起来暂时安全有光
20双柱间方厅仅容一人转身安全的死角,适合歇脚有光

默认示例:种子 3-7、5 间房、第 1 批。种子栏被清空时点「生成房间」会自动填回 3-7;在种子或数量输入框里按 Enter 也能直接生成。

使用方法

  1. 「种子」默认 3-7,任意文字都可以:字符码逐字累加后作为线性同余发生器的初值。同一种子永远得到同一批房间,把种子写进团务记录,队友照抄就能复现同一座地城。
  2. 「房间数量」默认 5,只接受 1~12 的整数;数量只决定生成几间,不改变前几间。
  3. 点「生成房间」出结果;光标放在种子或数量输入框里按 Enter 同样触发。
  4. 「换一批」不是重新随机,只把批次号加 1:种子 3-7 第 2 批的第一间变成八角形小间 · 宴会厅大小(约 60 平米)。按钮上会显示当前是第几批。
  5. 结果区第一行是统计:共几间、种子、第几批、含危险几间、黑暗几间;下面每间房一行,九类素材按固定顺序排列。
  6. 速查表列的是当前种子与批次下前 20 间房,默认显示 12 行,点「加载更多」展开余下 8 行,点「导出 CSV」存成带字节序标记的文件,Excel 直接打开不乱码。
  7. 「复制结果」带走当前这批房间全文;「复制推演表」复制 LCG 前 12 步推演的 TSV,可贴进表格软件逐步核对算法。
  8. 两个判定都是纯文本匹配:危险看第九类素材是否落在 5 条危险项里,黑暗看光线素材是否含「全黑」或「完全没有光」。

这个随机地下城房间生成器能解决什么问题

第一类是跑团临场要一间房。翻到地图上没准备的一格,点一次就有九类素材拼成的完整描写:穹顶圆形大厅 · 篮球场大小 · 粗凿花岗岩 · 塌出大洞看得见楼下 · 被杂草顶开的排水沟盖板 · 天花板垂下一盏锈蚀的铁吊灯 · 烧焦的毛皮味。念出来就能用,再加 NPC 和宝藏就是一个小遭遇。

第二类是密室与剧本杀缺房间文本。写手卡在「二楼左手第一间房什么样」的时候,让生成器出三版挑一版,比对着空白文档发呆快;黑暗与危险两列还能直接当成机关提示用——第 3 间「完全没有光,眼睛还没适应」就是天然的火把戏开场。

第三类是要一个能复现的随机源。多数随机生成器刷新一次换一批,玩家对不上账。这个随机地下城房间生成器把种子和批次号钉进输出:同种子同批次必然同结果,没有 Date.now()、没有时间因子,写进剧本或团务记录都能原样复现。它不做地图绘制、遭遇难度配比和掉落表——那些需要约束求解,不是查表拼句能解决的。

计算原理与变量说明

种子先折成一个 31 位整数。累加规则是 s=(s+str.charCodeAt(i))&0x7fffffff,逐字取字符码相加再截到 31 位。默认种子串是 3-7|0(种子与批次号用竖线相接),字符码依次是 51、45、55、124、48,累加得 323,这就是随机流的起点。

每一步推进用线性同余发生器。s=(Math.imul(s,1103515245)+12345)&0x7fffffff,乘数 1103515245、增量 12345、模数 231。从 323 推进一次得 2100634560,取素材用 Math.floor(s/2147483647*len)%len:2100634560 除以 2147483647 约 0.978,乘池长 10 得 9.78,向下取整为 9,形状池第 9 项正是「半圆形壁龛室」。

取素材为什么不写 s%len。线性同余发生器的低 k 位周期不超过 2k。从 323 起连续推进 20 次,取每次状态的低 4 位:0、9、14、15、12、5、10、11、8、1、6、7、4、13、2、3、0、9、14、15——第 17 个值回到第 1 个,周期恰好 16。若直接用 s%10,20 间房的形状会陷进这个 16 步循环;改成除以 2147483647(即 231−1)取高位比例,用满全部 31 位,同样 20 步看不到循环。公式末尾的 %len 只在 s 取到 0x7fffffff 时兜底。

一间房固定消费 9 次推进。九类素材顺序写死:形状、大小、墙面、地面、家具、光线、气味、声音、危险。前八类池长都是 10,危险池只有 9 条,所以第 9 次推进除的是 9 而不是 10。5 间房共 45 次推进,第 10 次推进(1369816625)取到第 2 间的形状「穹顶圆形大厅」。

批次号是拼进种子串的,不是多跳几步。第 1 批的种子串是 3-7|0,累加值 323;第 2 批是 3-7|1,累加值 324。初值只差 1,但线性同余对初值极其敏感,两批输出毫无共同之处。反过来,「换一批」也完全可以由别人复现:告诉他种子 3-7、第 2 批就行。

组合空间是 108×9 = 900000000(9 亿)。八类各 10 条、危险类 9 条相乘即得。同一个种子下批次号还能继续分岔,实际可寻址的房间数远大于 9 亿。

两个判定规则。危险:9 条危险素材里 SAFE 白名单 4 条(索引 0、1、2、4),命中算安全,其余 5 条(地板翻板、门后插销、触手、暗处的眼睛、掉砂的天花板)算危险。黑暗:光线素材文本含「全黑」或「完全没有光」即计,默认 5 间里第 3 间的「完全没有光,眼睛还没适应」是唯一命中。

完整示例(数值仅作演示)

默认一组:种子 3-7、第 1 批、5 间。统计行为「共 5 个房间,种子 3-7,第 1 批;含危险 2 个,黑暗 1 个。」第一间全文是:半圆形壁龛室 · 双层挑高 · 木板钉成的隔墙 · 磨得发亮的岩石 · 裂了缝的石棺 · 墙角一堆荧石泛着冷绿的光 · 潮湿的霉味 · 某处风穿过缝隙的哨音 · 墙缝里伸出的触手只够到你脚踝。它的九次推进依次取到索引 9、8、5、3、7、1、1、1、6。

数量改 1:输出只剩第一间,与上面那一行逐字相同——前几间不随后面加房间而改变。数量改 12:前 5 间不变,第 6 间是穹顶圆形大厅 · 壁橱大小,速查表第 6 行可见它是 12 间里的第二间黑暗房。

换一批:点一次「换一批」,批次号变 2,第一间变成八角形小间 · 宴会厅大小(约 60 平米)· 木板钉成的隔墙 · 石板拼缝长草 · 拴过动物的铁环 · 四角各插一支白烛,都短得快灭了 · 劣质灯油的呛味 · 沉重的呼吸声,一进一出 · 火把余光里有一双眼睛,没动。种子没动,只是 3-7|1 换了随机流起点。

批次速查表与 LCG 推演

第一张表是当前种子与批次下前 20 间房的速查,列分别是序号、形状、大小、危险项与明暗;默认 12 行,「加载更多」补上 13~20 行,「导出 CSV」导出全部 20 行。

步数推进后状态 s维度池长索引取到素材
12100634560形状109半圆形壁龛室
21728375033大小108双层挑高
31168719934墙面105木板钉成的隔墙
4681012895地面103磨得发亮的岩石
51512618988家具107裂了缝的石棺
6287447989光线101墙角一堆荧石泛着冷绿的光
7318054986气味101潮湿的霉味
8302929339声音101某处风穿过缝隙的哨音
91474013912危险96墙缝里伸出的触手只够到你脚踝
101369816625形状106穹顶圆形大厅
111315641622大小106篮球场大小
1237917335墙面100粗凿花岗岩

第二张表是 LCG 的前 12 步推演,每一步都能拿计算器复算:把上一行的状态代入 s=(Math.imul(s,1103515245)+12345)&0x7fffffff,再按 Math.floor(s/2147483647*len)%len 取索引。第 9 步池长是 9,其余是 10,这张表同时也解释了为什么危险类只有 9 条素材。

输入范围、边界与适用说明

常见问题

同一个种子为什么每次结果都一样?

因为随机源是种子折成的 31 位整数推进线性同余序列,每一步只依赖当前状态,没有 Math.random(),也没有任何时间因子;刷新、换设备、换浏览器,结果都逐字相同。

换一批和改种子有什么区别?

改种子是换一条随机流,累加初值整个变掉;换一批只把批次号从 0 变 1,种子串从 3-7|0 变成 3-7|1,累加值从 323 变 324,输出同样完全改观。两者都可复现。

为什么不用 Math.random,这样还算随机吗?

算,但算「可复现的伪随机」。线性同余序列拼房间完全够用;选它的理由恰恰是不要不可复现——记录里写下「种子 3-7 第 1 批」,一个月后还能原样重建。抽奖、发券请用带密码学随机源的工具。

9 亿种组合会很快重复吗?

不会。组合空间 108×9 = 900000000,一批 12 间也只占千万分之一。真正的重复风险来自种子本身:总用同一个种子加同一批次才会拿到同一批房间,而批次号可以一直往上加。

危险和黑暗是怎么判定的,能改吗?

不能改。危险:第九类素材命中 4 条安全白名单算安全,其余 5 条算危险;黑暗:光线素材含「全黑」或「完全没有光」即计。两条规则都是纯文本匹配,统计行里直接可见。

把数量从 5 改成 12,前 5 间会变吗?

不会。随机流按顺序消费,第 i 间房只消费第 9i−8 到 9i 次推进,与总数无关:数量 3 和数量 12 的前 3 间逐字相同。可以先出 3 间看风格,满意了再加到 12 间。

生成的房间可以直接写进剧本或模组吗?

可以,输出是九段中文描写;但素材池只有 89 条,容易和别人撞句,建议生成后再改写一轮,或换种子多抽几批挑着用。

数据会上传到服务器吗?

不会。查表、推进、统计与导出全部在本页完成,没有发起任何网络请求;种子、数量与批次号都不写入浏览器存储,刷新即恢复默认值。

相关工具