Home For Fiction – Blog

for thinking people

Patreon LogoPatreon

February 17, 2019

Anapest Generator: a JavaScript Poem Maker

Programming

anapestic generator, computer, javascript, literature, poetry, programming, technology

My JavaScript iambic pentameter generator is among the most popular articles on this blog. If you liked that, you’re gonna love today’s article. I decided to make an anapest generator with a rhyme! It’s a JavaScript poetry generator using an anapest, that is, a poem with anapestic meter.

anapest generator
Could the pen really write with the might of the sword?
(see what I did there?) πŸ˜‰

An anapest, or anapestic meter, is a metrical foot consisting of two unstressed syllables followed by a stressed one. Perhaps the most famous example of an anapestic poem (also mentioned in my article on poetry) is Lord Byron’s β€œThe Destruction of Sennacherib”.

The Assyrian came down like the wolf on the fold,
And his cohorts were gleaming in purple and gold;
And the sheen of their spears was like stars on the sea,
When the blue wave rolls nightly on deep Galilee.

Like the leaves of the forest when Summer is green,
That host with their banners at sunset were seen:
Like the leaves of the forest when Autumn hath blown,
That host on the morrow lay withered and strown.

A Simple Anapest Generator in Javascript

Without further delay, here’s what I came up with:

Click to run the program

Perceptive observers will notice that the anapest generator is running in an iframe. It links to raw.githack. This means that, as a free service, 100% uptime cannot be guaranteed.

Looking for the code? Here it is, you’re welcome: πŸ˜‰

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
	<script src="https://cdnjs.cloudflare.com/ajax/libs/rita/1.3.11/rita-full.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  </head>
  <body style="background-color:black;color:silver">
	<input type="button" style="margin-bottom:5px;padding:5px" value="Generate New" onclick="window.location.reload();">
	<br>
	<div id="out1" style="color:white;font-family:Verdana"></div><br>
  </body>
  	<script>
	let rhymedWord, rhymedWord2, preRhyme, preRhymeB, advS, advSB;
	let det = " they ";

	//creating rhymes
	let w1 = wordChoice("vbn", 2);
	let w1b = wordChoice("vb", 2);
	let w2, w2b;
	//
	fetchTheWord('https://api.datamuse.com/words?rel_rhy='+w1).then(function(obj){
		w2 = obj[Math.floor(Math.random()*obj.length)].word;
		fetchTheWord('https://api.datamuse.com/words?rel_rhy='+w1b).then(function(obj){
			w2b = obj[Math.floor(Math.random()*obj.length)].word;
			var syllNum = new_count(w2);
			var syllNumB = new_count(w2b);
			// first & second lines
			if (w2 != undefined) {
				rhymedWord = w2;
				if (syllNum == 1) {
					advS = 3;
					det = " some ";
					preRhyme = wordChoice("nns", advS)
				}
				else if (syllNum == 2) {
					advS = 2;
					preRhyme = RiTa.randomWord("rb", advS)
				}
				else if (syllNum == 3) {
					advS = 1;
					preRhyme = RiTa.randomWord("rb", advS);
				}
				else if (syllNum == 4) {
					preRhyme = "";
				}
				else {
					advS = 1;
					preRhyme = RiTa.randomWord("rb", advS);
				}
			}
			else {
				rhymedWord = wordChoice("vb", 3);
				advS = 1;
				preRhyme = RiTa.randomWord("rb", advS);
			}
			// third and fourth lines
			if (w2b != undefined) {
				rhymedWord2 = w2b;
				if (syllNumB == 1) {
					advSB = 2;
					preRhymeB = wordChoice("rb", advSB)
				}
				else if (syllNumB == 2) {
					advSB = 1;
					preRhymeB = RiTa.randomWord("md", advSB)
				}
				else if (syllNumB == 3) {
					advSB = 1;
					preRhymeB = "";
				}
				else {
					advSB = 1;
					preRhymeB = RiTa.randomWord("md", advSB);
				}
			}
			else {
				rhymedWord2 = wordChoice("vb", 2);
				advSB = 1;
				preRhymeB = RiTa.randomWord("md",advSB);
			}
				
				// structuring lines	
			var line1 = capitalizeFirstLetter(RiTa.randomWord("prp$",1)) + " " + wordChoice("jj",2) + " " + wordChoice("nn",3) + " " + retConjunction() + " " + wordChoice("nns",2) + " has " + w1 + ",";
			var line2 = RiTa.randomWord("jj",1) + " " + wordChoice2("jj",3) + " " + wordChoice("nns",2) + " " + retConjunction2() + det + preRhyme + " " + rhymedWord + ".";
			var line3 = capitalizeFirstLetter(wordChoice("jj",3)) + " " + RiTa.randomWord("jj",1) + " " + wordChoice("nn",2) + " " + retConjunction() + " " + wordChoice("nns",2) + " " + RiTa.randomWord ("md", 1) + " " + w1b + ",";
			var line4 = RiTa.randomWord("prp$",1) + " " + wordChoice("jj",2) + " " + RiTa.randomWord("jj", 1) + " " + wordChoice("nn",2) + " " + retConjunction2() + " " + wordChoice("nns",2) + " " + preRhymeB + " " + rhymedWord2 + ".";
			$('#out1').append(line1+"<br/>"+line2+"<br/>"+line3+"<br/>"+line4+"<br/>"+"<br/>");
		});
	});

	// word picking functions for stress detection
	function wordChoice(pos, syl) {
		var word = RiTa.randomWord(pos, syl);
		if ((RiTa.getStresses(word) == "0/1") || (RiTa.getStresses(word) == "0/0/1")) {
			return (word);
		}
		else {
			return (wordChoice(pos, syl));
		}
	}
	function wordChoice2(pos, syl) {
		var word = RiTa.randomWord(pos, syl);
		if (RiTa.getStresses(word) == "0/1/0") {
			return (word);
		}
		else {
			return (wordChoice2(pos, syl));
		}
	}
	function wordChoice3(pos, syl) {
		var word = RiTa.randomWord(pos, syl);
		if (RiTa.getStresses(word) == "1/0/0") {
			return (word);
		}
		else {
			return (wordChoice3(pos, syl));
		}
	}
	
	//capitalize first letter
	function capitalizeFirstLetter(string) {
		return string.charAt(0).toUpperCase() + string.slice(1);
}

	// counts syllables
	function new_count(word) {
		word = word.toLowerCase();
		if(word.length <= 3) { return 1; } 
			word = word.replace(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, ''); 
			word = word.replace(/^y/, '');
		return word.match(/[aeiouy]{1,2}/g).length;
	}
	
	function retConjunction() {
		var conjs = ["with", "near", "for"];
		var ind = Math.floor(Math.random() * (2 - 0 + 1) ) + 0;
		return conjs[ind];
	}
	
	function retConjunction2() {
		var conjs = ["as", "while", "soon", "then", "which", "how"];
		var ind = Math.floor(Math.random() * (5 - 0 + 1) ) + 0;
		return conjs[ind];
	}
	
	function fetchTheWord(url) {
		return new Promise(function (resolve) {
			resolve($.get(url));
		});
	}	
	
	</script>
</html>

You will need the RiTa library for this to work. It also implements the Datamuse API (which means, if the Datamuse server is slow, this page will be slow as well; it’s out of my control).

Anapestic Poetry Generator: Next Steps

As with my iambic pentameter maker, this is really, really “alpha”. I’d like to work on it some more, if I only find the time. My main focus would be an attempt to improve semantic coherence.

I’ve also noticed that sometimes the generator draws a blank (not verse!). If that happens, pressing “Generate New” should resolve the issue.

There’s also the same issue as with the iambic pentameter generator, namely, that the library I’m using to detect syllable stress isn’t 100% correct. If you came up with an improved version, feel free to share it!

Interested in haikus? Take a look at my haiku generator with user input!