如何一天生成万首乃至亿首优雅的烂诗
原文:如何看待 14 岁突然火起来的岑怡诺,其简历称「一天能写 2000 首诗」? - 乔加西的回答 - 知乎
在线预览:How a Computer Writes Elegant Poems Rapidly
好诗不好生成,烂诗还不好生成?
我来写一个烂诗生成器,只要在自己的电脑、手机上跑一会,就可以生成出数万、数十万首诗。
第一步:整理出一些“优美”的词汇
对原文的此部分进行简单处理,按字数对它们分类:
const 词汇表 = {
2: [],
3: [],
4: []
};
for(let 词儿 of `垂杨、新柳、玉丝纶、金嫩、柔条、曲岸垂杨、柳丝、闲柳、千花万柳、花海、芳甸吐嫩、摇绿、绿卷、浓翠、横翠、金碧、舒卷、款款、片片、缕缕、落纷纷、新晴、笼晴、韶光、婉媚、温丽、芊绵、春华、空灵、春柔、清婉、馨烈、和婉、清蕊、清芬、素约、红素、旖旎、飞花、浮花、落英、花影、芳丛、浮香、锦花、绣草、烂漫、芳踪、镂玉、雕琼、繁枝、素景、密叶、稠花、点水、扑面、风轻、水胧、倚暖、胭脂色、水溶溶、不留痕、几点春、邀春驻、花映柳、花深浅、树高低、翻微风、香接天、浓露飘香、软软东风、水逝云卷、繁花盈枝、百卉团团、和风轻暖、春光满树、秀色灼灼、红尘倦客、柳带摇风、香坠庭户、水阔花飞、瘦叶和风、叶叶心心、眼迷魂牵、浅粉深红`.split('、'))
词汇表[词儿.length].push(词儿);
当然也可以用reduce
方法来整理,效果是一样的:
const 词汇表 = `垂杨、新柳、玉丝纶、金嫩、柔条、曲岸垂杨、柳丝、闲柳、千花万柳、花海、芳甸吐嫩、摇绿、绿卷、浓翠、横翠、金碧、舒卷、款款、片片、缕缕、落纷纷、新晴、笼晴、韶光、婉媚、温丽、芊绵、春华、空灵、春柔、清婉、馨烈、和婉、清蕊、清芬、素约、红素、旖旎、飞花、浮花、落英、花影、芳丛、浮香、锦花、绣草、烂漫、芳踪、镂玉、雕琼、繁枝、素景、密叶、稠花、点水、扑面、风轻、水胧、倚暖、胭脂色、水溶溶、不留痕、几点春、邀春驻、花映柳、花深浅、树高低、翻微风、香接天、浓露飘香、软软东风、水逝云卷、繁花盈枝、百卉团团、和风轻暖、春光满树、秀色灼灼、红尘倦客、柳带摇风、香坠庭户、水阔花飞、瘦叶和风、叶叶心心、眼迷魂牵、浅粉深红`.split('、').reduce(
(词汇表, 词儿) => {
词汇表[词儿.length].push(词儿);
return 词汇表;
},
{
2: [],
3: [],
4: []
}
);
在 Deno 或 Node.js 的交互式解释器里粘贴并执行上述代码,再执行词汇表
,可以得到整理好的词汇:
{
2: [
"垂杨", "新柳", "金嫩", "柔条", "柳丝", "闲柳", "花海",
"摇绿", "绿卷", "浓翠", "横翠", "金碧", "舒卷", "款款",
"片片", "缕缕", "新晴", "笼晴", "韶光", "婉媚", "温丽",
"芊绵", "春华", "空灵", "春柔", "清婉", "馨烈", "和婉",
"清蕊", "清芬", "素约", "红素", "旖旎", "飞花", "浮花",
"落英", "花影", "芳丛", "浮香", "锦花", "绣草", "烂漫",
"芳踪", "镂玉", "雕琼", "繁枝", "素景", "密叶", "稠花",
"点水", "扑面", "风轻", "水胧", "倚暖"
],
3: [
"玉丝纶", "落纷纷", "胭脂色",
"水溶溶", "不留痕", "几点春",
"邀春驻", "花映柳", "花深浅",
"树高低", "翻微风", "香接天"
],
4: [
"曲岸垂杨", "千花万柳", "芳甸吐嫩",
"浓露飘香", "软软东风", "水逝云卷",
"繁花盈枝", "百卉团团", "和风轻暖",
"春光满树", "秀色灼灼", "红尘倦客",
"柳带摇风", "香坠庭户", "水阔花飞",
"瘦叶和风", "叶叶心心", "眼迷魂牵",
"浅粉深红"
]
}
如果不满足于这些词汇,可以去一些词典站爬一些,加载到数据库里。
第二步:以这些“优美”的词为主要词汇,排列组合,拼凑出一首烂诗,可酌情加词
我们先提供一些模板:
const 模板 = [
//四言
"4", "22", "3兮",
//五言
"23", "32", "4兮", "22兮", "是4", "是22",
//六言
"33", "42", "24", "222",
//这里可以再兮一把,不过我懒得兮
//七言
"223", "43", "322", "34", "33兮", "42兮", "24兮", "222兮"
];
然后随机选定一个模板:
const 随机抽取 = 数组 => 数组[
Math.round(
Math.random() * (数组.length - 1)
)
];
const 既定模板 = 随机抽取(模板);
套用模板偶数次,输出:
const 套模板 = 模板 => 模板.replace(
/\d/g,
长度 => 随机抽取(词汇表[长度])
);
console.log(
Array((Math.random() * 2 | 0) * 2 + 4)
.fill(既定模板) // 可以直接写成 .fill(随机抽取(模板))
.map(套模板)
.join('\n')
);
就是成诗。提一些例子:
- 玉丝纶树高低兮
不留痕树高低兮
树高低邀春驻兮
不留痕水溶溶兮 - 是芳甸吐嫩
是曲岸垂杨
是和风轻暖
是繁花盈枝
是香坠庭户
是秀色灼灼 - 水溶溶软软东风
玉丝纶秀色灼灼
邀春驻繁花盈枝
邀春驻香坠庭户
几点春香坠庭户
树高低繁花盈枝
如果我们希望诗句是错落的而不是等长的,先对模板和词汇表进行扩充:
模板.push(
//一言
"啊",
//二言
"2", "1啊", "1呢", "是1",
//三言
"3", "2呢", "2啊", "是2", "不是1"
//四言、五言、六言的句子不适合带单字词
);
词汇表[1] = [
"人", "你", "我", "她", "他",
"它", "赤", "橙", "黄", "绿",
"蓝", "靛", "紫", "春", "夏",
"秋", "冬"
];
然后套用若干个模板,输出:
let 长度 = Math.random() * 10; // 不用取整
for(let i = 0; i < 长度; ++ i)
console.log(套模板(随机抽取(模板)));
- 是绿
花深浅邀春驻
千花万柳兮
新柳绿卷浓翠兮
啊
是秀色灼灼
花映柳浮香素约
我啊
片片旖旎
扑面落英兮 - 几点春芳丛花影
几点春秀色灼灼
翻微风稠花
是软软东风
稠花旖旎馨烈兮
树高低水阔花飞
几点春兮
绿卷香接天
百卉团团繁枝兮
啊
这看着不押韵,心里难受是不是?如果要押韵的话,可以按照词汇的最后一个字的韵母,细致地整理词汇表。我不难受,所以这里我不弄。悄悄告诉你,博主有严重懒癌。
代码汇总
从上边零散的片段复制粘贴看着有些麻烦,所以这里我汇总成一段完整的代码。为让代码能与其它代码能够和谐相处,这里我使用英文变量名。
const vocabulary = {
1: [
"人", "你", "我", "她", "他",
"它", "赤", "橙", "黄", "绿",
"蓝", "靛", "紫", "春", "夏",
"秋", "冬"
],
2: [
"垂杨", "新柳", "金嫩", "柔条", "柳丝", "闲柳", "花海",
"摇绿", "绿卷", "浓翠", "横翠", "金碧", "舒卷", "款款",
"片片", "缕缕", "新晴", "笼晴", "韶光", "婉媚", "温丽",
"芊绵", "春华", "空灵", "春柔", "清婉", "馨烈", "和婉",
"清蕊", "清芬", "素约", "红素", "旖旎", "飞花", "浮花",
"落英", "花影", "芳丛", "浮香", "锦花", "绣草", "烂漫",
"芳踪", "镂玉", "雕琼", "繁枝", "素景", "密叶", "稠花",
"点水", "扑面", "风轻", "水胧", "倚暖"
],
3: [
"玉丝纶", "落纷纷", "胭脂色",
"水溶溶", "不留痕", "几点春",
"邀春驻", "花映柳", "花深浅",
"树高低", "翻微风", "香接天"
],
4: [
"曲岸垂杨", "千花万柳", "芳甸吐嫩",
"浓露飘香", "软软东风", "水逝云卷",
"繁花盈枝", "百卉团团", "和风轻暖",
"春光满树", "秀色灼灼", "红尘倦客",
"柳带摇风", "香坠庭户", "水阔花飞",
"瘦叶和风", "叶叶心心", "眼迷魂牵",
"浅粉深红"
]
};
const templates = [ //For monospace poems.
//4 characters
"4", "22", "3兮",
//5 characters
"23", "32", "4兮", "22兮", "是4", "是22",
//6 characters
"33", "42", "24", "222",
//Here I can add more templates with '兮' but I'm lazy to do it.
//7 characters
"223", "43", "322", "34", "33兮", "42兮", "24兮", "222兮"
];
const templatesForNonMonospacePoems = [
...templates,
//1 character
"啊",
//2 characters
"2", "1啊", "1呢", "是1",
//3 characters
"3", "2呢", "2啊", "是2", "不是1"
//Single-character words are suitable for sentences with up to 3 characters.
];
const pickRandomly = from => from[
Math.round(
Math.random() * (from.length - 1)
)
];
const applyTemplate = template => template.replace(
/\d/g,
length => randomlyPick(vocabulary[length])
);
//If you want it to be vivid, replace "generate" with "compose".
export function generateMonospacePoem() { //Returns an array of sentences of a poem.
return Array((Math.random() * 2 | 0) * 2 + 4)
.fill(randomlyPick(templates))
.map(applyTemplate);
}
export function generateNonMonospacePoem() {
const sentences = [];
const length = Math.random() * 10;
for(let i = 0; i < length; ++i)
sentences.push(applyTemplate(randomlyPick(templatesForNonMonospacePoems)));
return sentences;
}
export function generatePoem(){
return Math.random() > .5 ? generateMonospacePoem() : generateNonMonospacePoem();
}
保存成poem-generator.js
,就可以这么用它:
import {generatePoem} from './poem-generator.js';
console.time('作诗10000首');
for(let i = 0; i < 10000; ++i) generatePoem();
console.timeEnd('作诗10000首');
确保以上代码在 Deno 或有type="module"
的<script>
标签中运行,否则可能报错。
作诗 10000 首(像上边那样空转不输出),只要 100~200ms。
如果手机上装 Deno 或 Node.js 有点麻烦的话,可以进入文章开头的 在线预览 。(为展示效果,生成速度被限制,每秒只能生成 1 首诗)这样我们就都可以高产烂诗!
又水出一篇文章Σ(っ °Д °;)っ想发评论表达,发现评论发不出来……
666
测试
[](/)
123
评论功能已修复!Yeah!
Congratulations!????????????
2333