amytron4000/amytron.js

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