181 lines
5.2 KiB
JavaScript
181 lines
5.2 KiB
JavaScript
// AmyTron4000
|
|
// Gerenator for text
|
|
|
|
// Main object
|
|
var amytron = {}
|
|
|
|
// Discrete distribution
|
|
// The distribution object defines a discrete distribution
|
|
amytron.Distribution = function () {
|
|
this.total = 0 // Total number of elements in the distribution
|
|
this.items = new Map() // Map of item -> number of elements
|
|
}
|
|
// Add 'occur' number of 'elem' elements into the distribution
|
|
amytron.Distribution.prototype.addTo = function (elem, occur) {
|
|
this.total += occur
|
|
if (this.items.has(elem)) {
|
|
this.items.set(elem, occur + this.items.get(elem))
|
|
} else {
|
|
this.items.set(elem, occur)
|
|
}
|
|
}
|
|
// Pick a random element from the distribution
|
|
amytron.Distribution.prototype.pickFrom = function () {
|
|
var idx = Math.floor(Math.random() * this.total)
|
|
var acc = 0
|
|
var pick = undefined
|
|
for (var [elem, occur] of this.items)
|
|
{
|
|
acc += occur
|
|
pick = elem
|
|
if (acc > idx) {
|
|
break
|
|
}
|
|
}
|
|
return pick
|
|
}
|
|
|
|
// Rule generator
|
|
// This generator makes an array of elements from rules describing how to generate the array
|
|
// Each rule is associated to a distribution of patterns indicating how to replace a rule identifier
|
|
amytron.RuleGenerator = function () {
|
|
this.rules = new Map()
|
|
}
|
|
// Populate the rules table from a description
|
|
amytron.RuleGenerator.prototype.initializeFromDescription = function (description) {
|
|
for (var rule of description) {
|
|
var dist = new amytron.Distribution()
|
|
for (var pat of rule.distribution) {
|
|
dist.addTo(pat.pattern, pat.occurences)
|
|
}
|
|
this.rules.set(rule.id, dist)
|
|
}
|
|
}
|
|
// Generate an array of elements
|
|
amytron.RuleGenerator.prototype.generate = function () {
|
|
var replacePattern = function (rules, input) {
|
|
var output = new Array()
|
|
for (var i of input) {
|
|
if (rules.has(i)) {
|
|
output = output.concat(replacePattern(rules, rules.get(i).pickFrom()))
|
|
} else {
|
|
output.push(i)
|
|
}
|
|
}
|
|
return output
|
|
}
|
|
return replacePattern(this.rules, this.rules.get('@output@').pickFrom())
|
|
}
|
|
|
|
// Model of the amytron generator
|
|
amytron.model = {}
|
|
amytron.model.generators = new Map()
|
|
|
|
// Generate text from the generator id
|
|
amytron.generateText = function () {
|
|
var selector = document.getElementById('generator-selector')
|
|
var generatorId = selector.options[selector.selectedIndex].value
|
|
var generator = amytron.model.generators.get(generatorId)
|
|
document.getElementById('generated-text').innerHTML = generator.generate()
|
|
}
|
|
|
|
// Transform a list of strings to a formatted strings
|
|
amytron.formatText = function (input, isSentence) {
|
|
// Construct the output string from the list of strings.
|
|
var text = ""
|
|
if (isSentence) {
|
|
var first = true
|
|
for (var s of input) {
|
|
if (first) {
|
|
text += s.charAt(0).toUpperCase() + s.slice(1)
|
|
first = false
|
|
} else if (s.charAt(0).match(/\p{General_Category=Punctuation}/gu) != null) {
|
|
// No space before a punctuation
|
|
text += s
|
|
} else {
|
|
text += " " + s
|
|
}
|
|
}
|
|
text = text.trim() + "."
|
|
} else {
|
|
for (var s of input) {
|
|
text += s
|
|
}
|
|
}
|
|
|
|
// Construct the HTML content
|
|
return "<p>" + text + "</p>"
|
|
}
|
|
|
|
// Make a rule generator
|
|
amytron.makeRuleBasedGenerator = function (rules, isSentence) {
|
|
var ruleGenerator = new amytron.RuleGenerator()
|
|
ruleGenerator.initializeFromDescription(rules)
|
|
return function () {
|
|
var output = ruleGenerator.generate()
|
|
return amytron.formatText(output, isSentence)
|
|
}
|
|
}
|
|
|
|
// Parse a raw generator description
|
|
amytron.parseGenerator = function (gen) {
|
|
var generator = {}
|
|
generator.name = gen.name
|
|
generator.description = gen.description
|
|
generator.moredescription = gen.moredescription
|
|
generator.generate = amytron.makeRuleBasedGenerator(gen.rules, gen.issentence)
|
|
return generator
|
|
}
|
|
|
|
// Draw the amytron div
|
|
amytron.drawDiv = function (model) {
|
|
var contents = ''
|
|
contents += '<select id="generator-selector" onchange="amytron.updateDescription()">'
|
|
for (var [id, gen] of model.generators) {
|
|
contents += '<option value="' + id + '">' + gen.name + '</option>'
|
|
}
|
|
contents += '</select>'
|
|
contents += '<button onclick="amytron.generateText()">Generate</button>'
|
|
contents += '<br/>'
|
|
contents += '<div id="generator-description"><br/></div>'
|
|
contents += '<div id="generated-text"><br/></div>'
|
|
document.getElementById('amytron').innerHTML = contents
|
|
// Update the description
|
|
amytron.updateDescription()
|
|
}
|
|
|
|
// Draw the description
|
|
amytron.updateDescription = function () {
|
|
var selector = document.getElementById('generator-selector')
|
|
var generatorId = selector.options[selector.selectedIndex].value
|
|
var generator = amytron.model.generators.get(generatorId)
|
|
document.getElementById('generator-description').innerHTML = generator.description + "<br/>" + generator.moredescription
|
|
}
|
|
|
|
// Load the model
|
|
amytron.loadModel = function (gen) {
|
|
// Parse the raw model
|
|
amytron.model.generators.set(gen.id, amytron.parseGenerator(gen))
|
|
// Draw the amytron <div>
|
|
amytron.drawDiv(amytron.model)
|
|
}
|
|
|
|
// Loading function for Phonagen-htmljs
|
|
amytron.load = function (jsonFile) {
|
|
fetch(jsonFile)
|
|
.then(function(response) {
|
|
return response.json()
|
|
})
|
|
.then(amytron.loadModel)
|
|
}
|
|
|
|
// Load several files
|
|
amytron.loadAll = function (jsonFiles) {
|
|
for (file of jsonFiles) {
|
|
amytron.load(file)
|
|
}
|
|
}
|
|
|
|
// Export info
|
|
//module.exports = amytron
|