As a simple programming exercise, I wrote a piece of Node.JS code which generates random poems. It is based on a list of articles (kind of), nouns, linking verbs, and adjectives. It then combines them into lines, and eventually stanzas.
var articles = "The,All of the,Most of the,Some of the,My,Your,His,Her,Their,Our,Everybody's,Almost all of the,That,I knew that the,We knew that the,She knew that the,He knew that the,They knew that the".split(",");
var nouns = "darkness,morning,light,feeling,beauty,love,hatred,expression,message,happiness,sadness,anger,frustration".split(",");
var lv = "was,had been.will be,could be,might be,should have been,would have been,could have been".split(",");
var adjectives = "abstract,mysterious,permanent,unfortunate,intricate,confusing,true,false,fake,a lie,a stranger,a friend,serene,confusing,an enemy,terrible,enchanting,mine,yours,his,hers,theirs,ours,fortunate,understood,mine,interesting,mutual,artistic,musical".split(",");
var x;
var ta = articles[Math.floor(Math.random() * articles.length)];
var tb = nouns[Math.floor(Math.random() * nouns.length)];
var final = ta + " " + tb + "\nby Julian Lachniet\n------------------\n"
for (x = 0; x < 16; x++) {
var a = articles[Math.floor(Math.random() * articles.length)];
var b = nouns[Math.floor(Math.random() * nouns.length)];
var c = lv[Math.floor(Math.random() * lv.length)];
var d = adjectives[Math.floor(Math.random() * adjectives.length)];
final += a + " " + b + " " + c + " " + d + ".\n";
if (x % 4 == 3) {
final += "\n";
}
}
cr = new Date
final += "(c) " + cr.getFullYear();
console.log(final);
The poems are really quite silly, but any individual line out of context might seem normal.
He knew that the darkness
by Julian Lachniet
------------------
They knew that the darkness was mutual.
All of the sadness would have been serene.
Most of the feeling could have been artistic.
We knew that the sadness was intricate.
We knew that the feeling could be mine.
Your light had been.will be a lie.
They knew that the beauty would have been understood.
Their love would have been intricate.
They knew that the happiness should have been mine.
His frustration should have been mysterious.
Some of the darkness should have been musical.
That message might be unfortunate.
Your light might be enchanting.
Everybody's hatred should have been enchanting.
His expression could be interesting.
Their hatred would have been mine.
(c) 2017
I have several issues with my code already, which I don't really know how to change:
What is a better way to name the "dictionary" arrays (
articles, nouns, lv, adjectives
)?Is there a more effective way to represent arrays than CSVs? I decided against using a standard array due to how much space it takes up.
Any tips/pointers would be appreciated.
-
2\$\begingroup\$ Interesting that you put a copyright mark at the end of the output. The copyrightability and ownership of computer-generated works is debatable, and would probably vary by country. \$\endgroup\$200_success– 200_success2017年03月04日 07:36:57 +00:00Commented Mar 4, 2017 at 7:36
-
\$\begingroup\$ @200_success TIL, but seriously, I'm not going to use the poems for anything other than amusement. \$\endgroup\$Julian Lachniet– Julian Lachniet2017年03月04日 14:38:38 +00:00Commented Mar 4, 2017 at 14:38
-
\$\begingroup\$ I did some research because I am going to expand my code, but I wanted to share what I found. One way a Duke student years ago used was to break up his dictionary into positive and negative words. From what I can tell, by weighing each word, you can make the line positive or negative, or neutral. In fact, th whole poem can be like that. His poems was published by Duke's prestigious literary magazine. Here is the story about it: The Poem That Passed The Turin Test. And here is his Python Code on Github: \$\endgroup\$George McGinn– George McGinn2017年03月11日 02:17:34 +00:00Commented Mar 11, 2017 at 2:17
-
\$\begingroup\$ Follow-up question \$\endgroup\$200_success– 200_success2017年03月12日 18:44:44 +00:00Commented Mar 12, 2017 at 18:44
1 Answer 1
I am not well versed in coding node.js as I'd like to be (I can read and debug, but learning to program in it is still ongoing) and I did not see anything that said I could not present an answer using a compatible language, so I converted your code into SmartBASIC.
If you were expecting node.js code, I will understand. I needed a quick way to show you several areas where you can improve on your own program, and suggestions that will smarten your program's AI. For yes, SIRI seems to be human like, it is not perfect. And it is harder to have a computer write something in one of the arts, whether a poem, lyrics or even a short story.
I did notice one slight error. In the statement below, you have a period instead of a comma, which will get you strange errors (had been.will be):
var lv = "was,had been.will be,could be,might be,should have been,would have ...
I experimented with several ideas, and several show promise. I incorporated them in my SmartBASIC program, which I commented thoroughly.
Your dictionary is limited, but I found out that this is not always a bad thing. I experimented with nouns, verbs, adjectives and articles where I created several hundred in each, and while it was still hit or miss, it was more miss than yours hit. Quantity does not always equate to quality.
One of the problems I noticed is when you want to use a color. Rarely does a color stand alone, nor does it always work with every word. A "white beard" is fine, but what is a "white crash?"
But a white crash can be poetic if the theme is right. That later.
So with colors, I created in my table colors with modifier tags. These are color words with a tag at the end so the program knows that another word is needed after a color word is used.
Here is a sample DATA statement that you should be able to convert to a "VAR[" Table:
DATA "*beard","fool","white*","black*","green*","blue*","yellow*","red*","light beams","*river","*garment","*ship","*snake","*snakes","*sails","voice+","ship+","ocean blue"
What you want to look at are the words with an "" in front of or at the end. The "" is my token that color is involved, and a modifier is needed.
If the "" is before the word, then I need to add a color before it. If the "" is after the word, then it is a color word and it needs a modifier.
I also created a table of colors only for the times I need to add a color to the front of a word. The word can be a noun or a verb. "White lightning," depending on how it is used, can be a noun or a verb. If you said "White lighning struck a tree," it is a noun. "Dear ole Fred, lay dead, when met by white lightning" could be considered a verb/adverb use.
The second thing is the "+" modifier. In the same DATA statement, the word "voice+" means it needs a modifier after it. I created a specific table for this type of modifier.
You will see in my code that since I used a random generator to start either with an article or verb, every word is in or converted to lowercase. I had to create another modifier, "@" that is placed in front of proper nouns or words that must be capitalized, no matter where in the sentence they appear. @moon and @sun are two examples in my DATA statements.
The third thing that shows promise is to create files that you can read into your VAR tables, but with a twist. I am currently creating theme-based poems. So I created files with words that are used in a particular theme.
For example, "hope" is one of the themes I am developing, so I am using everything from other poets to a thesaurus to even the Bible to gather as many words, Articles, Nouns, Verbs, Adjectives, and Modifiers that fit the theme of "hope" along with some generic words that would work.
This is where you asked if it would be better to have .CSV instead of tables. It will add flexibility to what your computer program writes about. You would have a VAR table with just themes, and .CSV file names for each theme that holds your vocabulary for that theme. You would first randomly pick a theme, load your tables, then can randomly pick your words.
By moving your tables out to .CSV files, you allow for many different types of dictionaries. And you can even get as complex as having a main theme and a sub-theme and load the appropriate dictionaries.
Another improvement I demonstrated in my code is that sentence structure does not always have to be article-noun-verb-adjective. It doesn't even have to always be subject-noun-verb or noun-verb-subject. Try starting one of your lines with a verb instead of an article. Then you can use verb-noun-subject or even article-verb-noun-adjective.
For example, "Stepping on Mike's foot felt great" shows how a verb can start a sentence.
I mentioned subject. For now, you can use nouns, but you may want to eventually create another table with just items that are considered "subjects." "Science" is a subject. "A Dear John letter" can be a subject rather than a noun. A "Divorce" can also be a subject.
I tried to keep to the same logic you used, but I wrote as vanilla a BASIC program as I possibly could so those with other dialects need to change very little. Like statement separator (!) or some of the statements for lower and upper-case. With minimal changes, I had this working in techBASIC.
But Javascript, being a C-based language, there are enough similarities to BASIC that you should have no problems adapting the routines in my code below into your program.
Not a plug, but incase there are those who never heard of SmartBASIC, it is an app (less than 5ドル in iTunes) that runs a pretty robust BASIC dialect on iPad and iPhones, and comes with the ability to create Xcode apps for distribution on iTunes. You also do not need access to the internet to run and test your programs.
This code works when run in SmartBASIC and is not broken code.
Here is it with the changes I made (commented):
/*
Poem Generator
By George McGinn (Poems by SmartBASIC)
Program uses very little AI in the beginning as once I have all the
word pieces in place, the AI will then determine if a word needs a
qualifier before or after it.
As this program grows, so will its AI, and the next phase will have it
learning words, for example, if it chooses a "A" and the next word
begins with a vowel, it will correct the "a" to an "an", thus its start
of learning grammar.
UPGRADES/BUG FIXES:
v1.0 - March 1, 2017
Translation from simple NODE.js program
Initial logic with limited vocabulary
v1.5 - March 4, 2017 (Minor upgrade - only because this was also v1 updates)
Improved vocabulary by adding:
17+ Articles
31+ Nouns/Subjects
35+ Verbs/Adverbs
15+ Adjectives
28+ Color Modifiers (new)
Randomize start (Article or Verb)
Improved AI to now include:
– Capitalization at start of line
– Created word capitalization modifier tag
– Added Color Table for words needing a color before it
– Added additional word and new color modifier table
– Added Noun modifier table for before and after tagged noun
The AI can now do rudimentary word enhancement by addind modifiers
from specialized tables, including colors and added nouns, verbs,
and adjectives before or after a noun. It is capable of recognizing
words that require capitalization. However, the title still does
not work right
*/
OPTION BASE 1
RANDOMIZE
REM Initialize variables/arrays (comments to prevent confusion)
x=0 REM Index to poem length (# lines)
i=0 REM Index to loading Arrays
cr$=CHR$(10) REM Add a Carriage-Return character
Author$ = "By George McGinn" REM Name of Programmer running code
DIM article$(35),noun$(60),verb$(46),adjective$(45)
DIM colormodifier$(28),colortable$(7),nounmodifiers$(14)
REM Load Arrays from Data Statements
GOSUB LoadWordArrays
REM Pick a 2-word title
ta$ = article$(RND (35)+1)
b$=LOWSTR$(noun$(RND(60)+1))
b1$=LOWSTR$(noun$(RND(60)+1))
IF LEFT$(b,1ドル)="@" OR LEFT$(b1,1ドル)="@" THEN GOSUB CheckForCapitalization
IF RIGHT$(b,1ドル)="*" OR RIGHT$(b,1ドル)="+" THEN GOSUB CheckForModifierAfter
IF LEFT$(b,1ドル)="*" OR LEFT$(b,1ドル)="+" THEN GOSUB CheckForModifierBefore
tb$=b$
Title$ = ta$ & " " & tb$
REM Create the poem, 16 lines in 4 4-line stanzas
PRINT Title$
PRINT Author$
PRINT!PRINT
REM NOTE: b1 & c1 placeholders for future use as modifiers, or
REM to initially use b1 & c1 as modifiers themselves.
FOR X=1 TO 16
a$=LOWSTR$(article$(RND(35)+1)) REM Pick an Article
b$=LOWSTR$(noun$(RND(60)+1)) REM Pick a primary noun
b1$=LOWSTR$(noun$(RND(60)+1)) REM Pick a noun-color modifier
c$=LOWSTR$(verb$(RND(46)+1)) REM Pick a primary verb
c1$=LOWSTR$(verb$(RND(46)+1)) REM Pick a verb modifier
d$=LOWSTR$(adjective$(RND(45)+1)) REM Pick an adjective
bc$=LOWSTR$(colormodifier$(RND(28)+1)) REM Pick a modifier for a color
color$=LOWSTR$(colortable$(RND(7)+1)) REM Pick a color as a modifier
nounmod$=LOWSTR$(nounmodifiers$(RND(14)+1)) REM Pick a non-color noun modifier
REM Check for modifiers to nouns
IF LEFT$(b,1ドル)="@" OR LEFT$(b1,1ドル)="@" OR LEFT$(bc,1ドル)="@" THEN GOSUB CheckForCapitalization
IF LEFT$(b,1ドル)="*" OR LEFT$(b,1ドル)="+" THEN GOSUB CheckForModifierBefore
IF RIGHT$(b,1ドル)="*" OR RIGHT$(b,1ドル)="+" THEN GOSUB CheckForModifierAfter
REM Capitalize the first word of each sentence or stanza (whether noun or verb)
REM r=whether or not the sentence will start with a verb or article
r=RND(2)+1
IF r=1 THEN
z=LEN(a$)
a$=CAPSTR$(LEFT$(a,1ドル)) & RIGHT$(a,ドルz-1)
Line$=a$ & " " & b$ & " " & c$ & " " & d$
ELSE
z=LEN(c$)
c$=CAPSTR$(LEFT$(c,1ドル)) & RIGHT$(c,ドルz-1)
Line$=c$ & " " & b$ & " " & d$
ENDIF
IF X%4=0 THEN Line$=Line$ & "." & cr$
PRINT Line$
NEXT X
endPROG:
PRINT!PRINT!PRINT "© 2017 "&Author$&" (if it is good), All Rights Reserved"
PRINT "Date/Time Stamp: "&CURRENT_MONTH ()&"/"&CURRENT_DATE ()&"/"&CURRENT_YEAR ()&" at "&CURRENT_HOUR()&":"&CURRENT_MINUTE()&":"&CURRENT_SECOND()
END
REM FUNCTIONS, SUBROUTINES, LABELED DATA STATEMENTS
REM ***********************************************
LoadWordArrays:
REM ***********************************************
REM Load Arrays from Data Statements
REM Load Articles
For i=1 TO 35!READ article$(i)!NEXT i
REM Load Nouns
FOR i=1 TO 59!READ noun$(i)!NEXT i
REM Load Verbs
FOR i=1 TO 46!READ verb$(i)!NEXT i
REM Load Adjectives
FOR i=1 TO 45!READ adjective$(i)!NEXT i
REM Load Color Modifiers
FOR i=1 TO 28!READ colormodifier$(i)!NEXT i
REM Load Color Table
FOR i=1 to 7!READ colortable$(i)!NEXT i
REM Load Noun Modifiers
FOR i=1 to 14!READ nounmodifiers$(i)!NEXT i
RETURN
CheckForCapitalization:
REM Check for modifiers (@=Capitalize Word)
IF LEFT$(b,1ドル)="@" THEN
z=LEN(b$)
b$=RIGHT$(b,ドルz-1)
b$=CAPSTR$(LEFT$(b,1ドル)) & RIGHT$(b,ドルz-2)
ENDIF
IF LEFT$(b1,1ドル)="@" THEN
z=LEN(b1$)
b1$=RIGHT$(b1,ドルz-1)
b1$=CAPSTR$(LEFT$(b1,1ドル)) & RIGHT$(b1,ドルz-2)
ENDIF
IF LEFT$(bc,1ドル)="@" THEN
z=LEN(bc$)
bc$=RIGHT$(bc,ドルz-1)
bc$=CAPSTR$(LEFT$(bc,1ドル)) & RIGHT$(bc,ドルz-2)
ENDIF
RETURN
CheckForModifierBefore:
REM Check for modifiers Before
REM "*" the noun needs a color before it
IF LEFT$(b,1ドル)="*" THEN
z=LEN(b$)
b$=RIGHT$(b,ドルz-1)
b$=color$ & " " & b$
ENDIF
REM "+" the noun needs another noun to follow it (selection from noun modifier)
IF RIGHT$(b,1ドル)="+" THEN
z=LEN(b$)
b$=LEFT$(b,ドルz-1)
b$=nounmod$ & " " & b$
ENDIF
RETURN
CheckForModifierAfter:
REM Check for modifiers after
REM "*" the noun is a color only color-friendly nouns considered
IF RIGHT$(b,1ドル)="*" THEN
z=LEN(b$)
b$=LEFT$(b,ドルz-1)
b$=b$ & " " & bc$
ENDIF
REM "+" the noun needs another noun to follow it (selection from noun modifier)
IF RIGHT$(b,1ドル)="+" THEN
z=LEN(b$)
b$=LEFT$(b,ドルz-1)
b$=b$ & " " & nounmod$
ENDIF
RETURN
REM DATA Statements for Poem Generator
REM 35 Articles
articles:
DATA "The","All of the","Most of the","Some of the"
DATA "My","Your","His","Her","Their","Our","Everybody's","Almost all of the"
DATA "That","I knew that the","We knew that the","She knew that the","He knew that the","They knew that the","And the coming","Oh, the","A spring of","Beyond the","Within the","And the","Alone, alone,","I fear","I looked upon","A","But where the","Like","A still and","Alone","All alone, a","The moving","It is"
REM 60 Nouns
nouns:
DATA "darkness","morning","morning+","light","feeling","feeling+","beauty","love","hatred","happiness","sadness","anger","frustration","expression","message","ship","lips","mouth","voice","garment","saint","snake","snakes","water","fire","lead","dreams","air","ghost","sails","sleep","river","cloud","@moon","@sun","waters","life","stars","the stars","lightning","beams","beams+","*beard","fool","white*","black*","green*","blue*","yellow*","red*","light beams","*river","*garment","*ship","*snake","*snakes","*sails","voice+","ship+","ocean blue"
REM 46 Verbs (lv)
verbs:
DATA "was","had been","will be","could be","might be","should have been","would have been","could have been","drunk","drank","lite","heavy","blessed","glossy","velvet","flash","kind","coiled","swarm","swarmed","fire","pity","filled","fill","moved","wind","danced","steep","wide","steep and wide","thick","light","roar","loud","more loud","lightning","struck","fell","more horrible","horrible","awful","hit","huge","holds","long","surrounds"
REM 45 Adjectives
adjectives:
DATA "abstract","mysterious","permanent","unfortunate","was unfortunate"
DATA "intricate","confusing","serene","confusing"
DATA "true","false","fake","a lie"
DATA "a stranger","a friend","an enemy"
DATA "terrible","enchanting","is mine","was yours","is his","is hers","was theirs","was ours"
DATA "fortunate","was understood","mine","interesting","is mutual","with an artistic flair","was musical"
DATA "golden pond","glossy lake","blessed","moment","unaware","no","yes","sure"
DATA "like","dreams","between","inbetween","alone","than that"
REM 28 Color modifiers
colormodifiers:
DATA "morning","light","beauty","love","ship","lips","garment","knight","saint","snake","snakes","water","fire","ghost","sails","river","cloud","@moon","@sun","waters","stars","lightning","beams","beard","velvet","flash","grass","book"
REM 7 Color table entries
colortable:
DATA "red","yellow","blue","green","white","black","orange"
REM 14 Noun Modifier Table (Nouns, Verbs/Adverbs, Adjectives)
nounmodifier:
DATA "sunshine","light","glow","fog","of peace","of love","blue","great","unloved","sad","happy","loved","of light","of love"
-
\$\begingroup\$ Thanks, but I was more looking for a review of the code itself. Regardless, I'll try out some of your suggestions. \$\endgroup\$Julian Lachniet– Julian Lachniet2017年03月06日 23:10:49 +00:00Commented Mar 6, 2017 at 23:10
-
\$\begingroup\$ I found nothing wrong with your code. No inefficiencies, it's tight, well written, with only the period in your table as an issue. You used the MATH.FLOOR in your Randomizer for the same reason I add +1 because random numbers either start at zero, I am converting what I wrote into node.js for your next set of questions. After spending 50 years as a degreed/career computer scientist & software engineer, I was able to evaluate your code. I can code 100 languages, which helps evaluate code that is similar. I just currently still learning to write in it as many of my languages are no longer used. \$\endgroup\$George McGinn– George McGinn2017年03月07日 15:32:52 +00:00Commented Mar 7, 2017 at 15:32
-
\$\begingroup\$ Really, 50 years? What was on TV when you were a kid? \$\endgroup\$Julian Lachniet– Julian Lachniet2017年03月07日 15:56:44 +00:00Commented Mar 7, 2017 at 15:56
-
\$\begingroup\$ I was in 9th grade 1973 when I programmed my first computer, PDP-8E. Let's see TV: All in the Family, Happy Days, Sanford and Son, Movies - Jaws, Close Encounters, Star Wars, The Exorcist, The Sting, the God Father series, Rocky, Service to name a few off the top of my head. However, having a father who was a beat cop in Harlem for NYPD meant we didn't watch much TV or any of those movies until I was a late teen. The very first movie I ever saw - Mary Poppins and Chitty Chitty Bang Bang! My first date I took her to Jaws! Thanks for the stroll down amnesia lane! \$\endgroup\$George McGinn– George McGinn2017年03月07日 16:04:52 +00:00Commented Mar 7, 2017 at 16:04
-
\$\begingroup\$ I have a feeling that you haven't had a major for 50 years, considering that that would be 1967 (3rd Grade for you) \$\endgroup\$Julian Lachniet– Julian Lachniet2017年03月07日 18:23:35 +00:00Commented Mar 7, 2017 at 18:23