Skip to content

Instantly share code, notes, and snippets.

@lostfictions
Last active November 27, 2021 20:08
Show Gist options
  • Save lostfictions/607ab2eccef8385270d3393eb328e246 to your computer and use it in GitHub Desktop.
Save lostfictions/607ab2eccef8385270d3393eb328e246 to your computer and use it in GitHub Desktop.
tiny tiny tracery-like
const matcher = /\[([^\[\]]+)\]/g
function randomInArray(arr) { return arr[Math.floor(Math.random() * arr.length)] }
export default function generate(concepts, concept, maxCycles = 10, seen = {}) {
if(!concepts[concept]) {
return `{error: unknown concept "${concept}"}`
}
return randomInArray(concepts[concept])
.replace(matcher, (_, nextConcept) => {
if(seen[nextConcept] > maxCycles) {
return '{error: max cycles exceeded}'
}
const nextSeen = Object.assign({}, seen)
nextSeen[nextConcept] = nextSeen[nextConcept] + 1 || 1
return generate(concepts, nextConcept, maxCycles, nextSeen)
})
}
const concepts = {
beings: ['dogs', 'cats', 'humans', 'robots', 'animes'],
state: ['harmony', 'misery', 'terror'],
howThingsAre: [
'[beings] and [beings], living together in [state]!'
],
recursive: [
'[beings], but also [recursive]',
'[beings]'
]
}
generate(concepts, 'howThingsAre') // => animes and robots, living together in misery!
generate(concepts, 'recursive') // => cats, but also humans, but also animes, but also cats, but also robots
// You can also use .bind() to partially apply a generator with a set of concepts...
const gen = generate.bind(undefined, concepts)
// ...and get a function that can be used as a shorthand for that set!
gen('howThingsAre') // => dogs and animes, living together in harmony!
gen('beings')
// You can do the same thing for a single concept, and get a handy zero-argument getter.
const getStateOfAffairs = generate.bind(undefined, concepts, 'howThingsAre')
getStateOfAffairs()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment