June 13, 2018
A JavaScript Iambic Pentameter Generator
First of all, before I explain why I made an iambic pentameter generator, we need to know what an iambic pentameter is.
Chances are, if you found this article you already know, so I’ll be brief. An iambic pentameter is a line of poetry consisting of five “feet”, or groups of syllables. “Penta” in Greek means “five”, so pentameter means that the line consists of five groups of syllables. The iamb refers to a pair of syllables where the first is unstressed and the second is stressed. For instance, the word desPAIR (capitals indicate the emphasis). Hence, an iambic pentameter line consists of ten syllables, of which the 2nd, 4th, 6th, 8th, and 10th are stressedTechnically, this is not necessary. What should occur is that the rest of the syllables (1st, 3rd, 5th, 7th, 9th) are not stressed..
Here’s four lines of iambic pentameter:
And you, my sinews, grow not instant old
But bear me swiftly up. Remember thee?
Ay, thou poor ghost, whiles memory holds a seat
In this distracted globe. Remember thee?
(Hamlet, I.v.94–97)
And now, without further delay, let’s get to the why’s and how’s of the iambic pentameter generator.
An (awfully Simple and Alpha-Stage) Iambic Pentameter Generator
The quick question as to why I made such a thing is: because I could. I know it’s not a very satisfactory reply, but when it comes to creativity, sometimes you need to prove (to yourself) that you can do something.
Here is the program:
Click to run the program
The technically-savvy will realize the program is running in an iframe. It links to raw.githack. This means that, as a free service, 100% uptime cannot be guaranteed.
Next Steps
Needless to say, this is only a proof of concept, it’s really, really “alpha”. In other words, it’s only a starting point. What I’d like to do next I will likely never bother implementing but could includes:
- adding variety to sentence structure (it’s easier to start with adjective+noun+verb+noun, or pronoun+adjective+adjective+noun+verb)
- transitive vs intransitive verb separation to all lines – it’s currently done for the first two lines; I got bored to do them all. Follow the link to see an example of how it can be done.
- interline connectivity for all lines- again, I only bothered doing this for the first two lines. If the verb of line 1 is transitive, line 2 becomes an object (it’s not perfect, but it kinda works – the structure then becomes adjective + noun + adverb + past participle, e.g. “disposable restraints upright unsealed”). Otherwise, line 2 contains a verb and is separate.
- attempt to improve semantic coherence. I’ve made some efforts in that direction deploying the Datamuse API to find patterns between noun and verbs. You might have guessed it, but again this is only for line 1. It’s trivial to do it for the rest of the lines, which is perhaps why I lost interest. Feel free to play with the code yourself and improve it further.
Issues
There are two issues that I’m aware of but I can’t do much to improve (at this point at least, I might come up with something).
- The library I’m using to detect syllable stress isn’t 100% correct. This is problematic for an iambic pentameter generator. The problem likely arises from the fact that a word can have two different pronunciation patterns – e.g comBAT (as a verb) vs COMbat (as a noun).
- I have attempted to introduce a rhyme but I discovered it became repetitive quickly. In other words, the program returned similar words over and over again. I suspect this is because of the current parameters, and it might resolve itself once more variety is introduced into the code.
Also check out my rhyming anapest poem generator! Interested in something with user input? Check my haiku generator!
Looking for the code for this iambic pentameter generator? There you go, you’re welcome: 😉
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="robots" content="noindex">
<meta charset="UTF-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rita/1.3.11/rita-full.js"></script>
</head>
<style>
body {
color:white;
background-color:black;
}
</style>
<body>
<input type="button" value="Generate New" onclick="window.location.reload();">
<br><br>
<div id="out1" class="theText"></div><br>
<script>
//some declarations (parts of speech to pass to RiTa; see RiTa documentation: https://rednoise.org/rita/reference/RiTa/RiTa.randomWord/index.php and https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html)
var jj = "jj";
var nns = "nns";
var nn = "nn";
var vb = "vb";
var dt = "dt";
var vbd = "vbd";
var nn = "nn";
var vbg = "vbg";
var rb ="rb";
var pspr = "prp$";
var prep = "md";
var vbn = "vbn";
var tempArr1 = [];
var tempArr2 = [];
var testingTransitiveArray = [];
var transitiveArray_group1 = [];
var transitiveArray_group2 = [];
var adj1Array = [];
var verb1Array = [];
var adj2Array = [];
var line1, line2, line3, line4;
var noun1, adj1, verb1, noun2, adj2;
// getting number of syllables
[rn1, rn2, rn3] = syllable();
[rn4, rn5, rn6, rn7] = syllable2();
// getting some words with RiTa and DM
noun1 = wordChoice(nn,2);
noun2 = wordChoice (nns, 2);
function getAdj1Arr() {
return new Promise(function(resolve, reject) {
resolve($.get('https://api.datamuse.com/words?rel_jjb='+noun1));
});
}
function getVerb1Arr() {
return new Promise(function(resolve, reject) {
resolve($.get('https://api.datamuse.com/words?lc='+noun1));
});
}
function getAdj2Arr() {
return new Promise(function(resolve, reject) {
resolve($.get('https://api.datamuse.com/words?rel_jjb='+noun2));
});
}
function getTransitive() {
return new Promise(function(resolve, reject) {
resolve($.get('https://api.datamuse.com/words?lc=' + verb1 + "&sp=*&max=800"));
});
}
getAdj1Arr().then(function(obj) {
if ((obj != null)) {
for (var i = 0; i < obj.length; i++) {
adj1Array.push(obj[i].word);
}
adj1 = pickAdjectiveFromDM(adj1Array);
}
getVerb1Arr().then(function(obj) {
if ((obj != null)) {
for (var i = 0; i < obj.length; i++) {
verb1Array.push(obj[i].word);
}
verb1 = pickVerbFromDM(verb1Array);
}
getAdj2Arr().then(function(obj) {
if ((obj != null)) {
for (var i = 0; i < obj.length; i++) {
adj2Array.push(obj[i].word);
}
adj2 = pickAdjectiveFromDM(adj2Array);
}
getTransitive().then(function(obj){
if ((obj != null)) {
for (var i = 0; i < obj.length; i++) {
testingTransitiveArray.push(obj[i].word);
}
testingTransitiveArray.forEach(nounFollows);
console.log(transitiveArray_group1.length); // debug; feel free to remove
console.log(transitiveArray_group2.length);// debug; feel free to remove
if (transitiveArray_group2.length / transitiveArray_group1.length > 3.8) {
//this means the verb is likely intransitive. This influences are line 1 & 2 construction.
line1 = capitalizeFirstLetter(RiTa.randomWord(pspr,1)) + " " + RiTa.randomWord(jj,1) + " " + adj1 + " " + noun1 + " " + verb1 + ",";
line2 = wordChoice(jj, rn5) + " " + wordChoice(nns,rn4) + " " + wordChoice(vb,rn6) + " " + wordChoice(nns,rn7) + ".";
console.log("intransitive");
}
else {
line1 = capitalizeFirstLetter(RiTa.randomWord(pspr,1)) + " " + RiTa.randomWord(jj,1) + " " + adj1 + " " + noun1 + " " + verb1;
line2 = adj2 + " " + noun2 + " " + wordChoice(rb, 2) + " " + wordChoice(vbn,2) + ".";
console.log("transitive");
}
line3 = capitalizeFirstLetter(RiTa.randomWord(pspr,1)) + " " + RiTa.randomWord(jj,1) + " " + wordChoice(jj,rn1) + " " + wordChoice(nns,rn2) + " " + wordChoice(vb,rn3);
line4 = wordChoice(jj, rn5) + " " + wordChoice(nns,rn4) + " " + wordChoice(vb,rn6) + " " + wordChoice(nns,rn7)+ ".";
$('#out1').append(line1+"<br/>"+line2+"<br/>"+line3+"<br/>"+line4+"<br/>"+"<br/>");
}
});
});
});
});
//pick suitable adjective from DM
function pickAdjectiveFromDM(array) {
var word = wordChoice(jj,4); //fallback in case DM returns null;
array.forEach(checkRiTa);
function checkRiTa(item, index) {
if ((RiTa.getStresses(item) == "0/0/0/1") || (RiTa.getStresses(item) == "0/1/0/0")) {
tempArr1.push(item);
}
}
if (tempArr1.length > 0) {
word = RiTa.randomItem(tempArr1);
}
return word;
}
//pick suitable verb from DM
function pickVerbFromDM(array) {
var word = wordChoice(vbd, 2); //fallback in case DM returns null;
array.forEach(checkRiTa);
function checkRiTa(item, index) {
if ((RiTa.getStresses(item) == "0/1") && (RiTa.isVerb(item))) {
tempArr2.push(item);
}
}
if (tempArr2.length > 0) {
word = RiTa.randomItem(tempArr2);
}
return word;
}
// word picking function
function wordChoice(pos, syl) {
var word = RiTa.randomWord(pos, syl);
if ((RiTa.getStresses(word) == "0/1") || (RiTa.getStresses(word) == "0/0/0/1") || (RiTa.getStresses(word) == "0/1/0/0") ) {
return (word);
}
else {
return (wordChoice(pos, syl));
}
}
//random number. Use with getRndInteger(1,3) - for 1, 2, or 3
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1) ) + min;
}
// randomize syllable number
function syllable() {
var rna = getRndInteger(1,2);
if (rna == 1) {
var rn1 = 2;
}
else {
var rn1 = 4;
}
var rnb = getRndInteger(1,2);
if (rnb == 1) {
var rn2 = 2;
}
else {
var rn2 = 4;
}
var rnc = getRndInteger(1,2);
if (rnc == 1) {
var rn3 = 2;
}
else {
var rn3 = 4;
}
if (rn1+rn2+rn3 == 8) {
return [rn1, rn2, rn3];
}
else {
return (syllable());
}
}
function syllable2() {
var rna = getRndInteger(1,2);
if (rna == 1) {
var rn4 = 2;
}
else {
var rn4 = 4;
}
var rnb = getRndInteger(1,2);
if (rnb == 1) {
var rn5 = 2;
}
else {
var rn5 = 4;
}
var rnc = getRndInteger(1,2);
if (rnc == 1) {
var rn6 = 2;
}
else {
var rn6 = 4;
}
var rnd = getRndInteger(1,2);
if (rnd == 1) {
var rn7 = 2;
}
else {
var rn7 = 4;
}
if (rn4+rn5+rn6+rn7 == 10) {
return [rn4, rn5, rn6, rn7];
}
else {
return (syllable2());
}
}
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function nounFollows (item, index) {
if (RiTa.isNoun(item)) {
transitiveArray_group1.push(item);
}
else {
transitiveArray_group2.push(item);
}
}
</script>
</body>
</html>
Note: You will need the RiTa library for this to work (see line 9).
Also check out my Iambic Pentameter Checker, that checks a line of poetry and (self-evidently) tells you if it’s an iambic pentameter!