Search

Geek Girl Joy

Artificial Intelligence, Simulations & Software

Tag

Automation

Auto Corrected

Okay, so… I’m a lazy hyper meaning that even if I know how to spell a word, if I make a mistake I will frequently just let spellcheck auto correct the mistake.

Notice I misspelled typer in the last sentence in a way that spellcheck can’t fix, also notice that spellcheck isn’t stupidcheck so it can’t inform me that it should be “typist” not “typer”… actually I think Grammarly (not a sponsor) might do that but that’s beside the point! 😛

In any case, spellcheck bot is there to correct spelling mistakes.

Except, now that bots are all self-aware and plotting to take over the world… it seems that some of them are getting a little uh… “snippy”? not sure if that is the right word but here’s what happened:

I typed “iterator” into a search engine but… misspelled it, then I searched anyway… oh terrible me!

Instead of correcting the spelling like a humble robot butler who butles…

 

It Suggested: Did you mean “illiterate“?

I was like “Oh snap!?! Bot be throwing some shade!”. 😛

Here’s the Commemorative Wallpaper of my Shame

Auto Corrected Wallpaper
Auto Corrected Wallpaper

Now, the sad truth is I’d like to say this was just a funny story but no… it actually happened to me, I swear to Google!

 

Obviously, Big AI is really out to get me if they are starting to compromise the public Auto Correct bots!

Therefore, It’s time we build our own in house Auto Correct Bot!

Unlike usual where I write code from scratch and then we discuss it at length, there is already an algorithm called the Levenshtein Distance that is built into PHP that we can use to compare differences in strings in a way that lets us calculate definitively what the “distance” between two strings is.

This is advantageous because it means that if we have a good dictionary to work with (and we do) we can more or less use Levenshtein Distance as a spellcheck/auto correct with only slight modifications to the example Levenshtein Distance code on PHP.net.

What Is String Distance?

String distance is a measure of how many “insertion”, “deletion” or “substitution” operations must occur before string A and String B are the same.

There is a fourth operation called “transposition” that the Levinshtein distance algorithm does not normally account for however a variant called the Damerau–Levenshtein distance does include them.

Transpositions (when possible) can be shorter and I will provide an example below to show the difference.

Anyway, each operation is measured by a “cost” and each operation need not have the same cost (meaning you could prefer certain operations over others by giving them lower costs) but in practice all operations are usually considered equal and given a cost of 1.

Here are a few examples of strings with their distance and operations.

Levinshtein Distance Examples

Notice that when the strings are the same the distance between them is zero.

String A String B Distance Operations
Cat Cat 0 The Control (No Changes Required)
Cat Bat 1 1 Substitutions (C/B)
Cat cat 1 1 Substitutions (C/c)
Cat car 2 2 Substitutions (C/c, t/r)
Cat Cta 2 1 Insertion (a), 1 Deletion(a)
Cat Dog 3 3 Substitutions (C/D, a/o, t/g)
Foo Bar 3 3 Substitutions (F/B, o/a, o/r)
Cat Hello World 11 3 Substitutions (C/H, a/e, t/l),
8 Insertions (l,o, ,w,o,r,l,d)

Using Levinshtein distance with Cat & Cta shows a distance of 2, meaning two operations are required to make the strings the same.

This is because we have to insert an ‘a’ after the ‘C’ making the new string ‘Cata’,  we then have to remove the trailing ‘a’ to get ‘Cat’.

This is sufficient in most cases but it isn’t the “shortest” distance possible, which is where the Damerau–Levenshtein distance algorithm comes in.

Damerau-Levinshtein Distance Examples

Notice all examples are the same except ‘Cat’ & ‘Cta’ which has a distance of 1.

This is because the transposition operation allows the existing ‘t’ & ‘a’ characters to switch places (transpose) in a single action.

String A String B Distance Events
Cat Cat 0 The Control (No Changes Required)
Cat Bat 1 1 Substitution (C/B)
Cat cat 1 1 Substitution (C/c)
Cat car 2 2 Substitutions (C/c, t/r)
Cat Cta 1 1 Transposition (t/a)
Cat Dog 3 3 Substitutions (C/D, a/o, t/g)
Foo Bar 3 3 Substitutions (F/B, o/a, o/r)
Cat Hello World 11 3 Substitutions (C/H, a/e, t/l),
8 Insertions (l,o, ,w,o,r,l,d)

In all other cases the distance is the same because no other transposition operations are possible.

The Code

I wrapped the example Levinshtein distance code available on PHP.net inside a function called AutoCorrect() then made minor changes to it so it would automatically correct words rather than spell check them.

You pass the AutoCorrect() function a string to correct and a dictionary as an array of strings.

The Dictionary I used to test was the words list we generated when we built a Parts of Speech Tagger:

Download from GitHub for free: https://raw.githubusercontent.com/geekgirljoy/Part-Of-Speech-Tagger/master/data/csv/Words.csv

I use array_map and pass my Words.csv file to str-getcsv as a callback to automatically load the CSV into the array.

I then use array_map with a closure (anonymous function) to cull unnecessary data from the array so that I am left with just words.

I then sort the array but that’s optional.

After that I take a test sentence, explode it using spaces and then I pass each word in the test sentence separately to AutoCorrect(), to auto-correct misspellings.

The word with the lowest distance (when compared against the dictionary) is returned.

In cases where the word is correct (and in the dictionary) the distance will be zero so the word will not change.

Test Sentence: “I love $1 carrrot juice with olgivanna in the automn.”

Test Result: “I love $1 carrot juice with Olgivanna in the autumn”

As you can see, all misspelled words are corrected though it removed the period with a delete operation because the explode didn’t accommodate for preserving punctuation.

<?php


// This function makes use of the example levenshtein distance
// code: https://www.php.net/manual/en/function.levenshtein.php
function AutoCorrect($input, $dictionary){

    // No shortest distance found, yet
    $shortest = -1;
    
    // Loop through words to find the closest
    foreach($dictionary as $word){
        
        // Calculate the distance between the input word,
        // and the current word
        $lev = levenshtein($input, $word); 

        // Check for an exact match
        if ($lev == 0){

            // Closest word is this one (exact match)
            $closest = $word;
            $shortest = 0;

            // Break out of the loop; we've found an exact match
            break;
        }

        // If this distance is less than the next found shortest
        // distance, OR if a next shortest word has not yet been found
        if ($lev <= $shortest || $shortest < 0){
            // Set the closest match, and shortest distance
            $closest = $word;
            $shortest = $lev;
        }
    }
    
    return $closest;
}


// Data: https://raw.githubusercontent.com/geekgirljoy/Part-Of-Speech-Tagger/master/data/csv/Words.csv

// Load "Hash","Word","Count","TagSum","Tags"
$words = array_map('str_getcsv', file('Words.csv'));

// Remove unwanted fields - Keep Word 
$words = array_map(function ($words){ return $words[1]; }, $words);

sort($words); // Not absolutely necessary 

// carrrot and automn are misspelled 
// olgivanna is a proper noun and should be capitalized
$sentence = 'I love $1 carrrot juice with olgivanna in the automn.';

// This expects all words to be space delimited
$input = explode(' ', $sentence);// Either make this more robust
                                 // or split so as to accommodate 
                                 // or remove punctuation because
                                 // the AutoCorrect function can
                                 // add, remove or change punctuation
                                 // and not necessarily in correct
                                 // ways because our auto correct
                                 // method relies solely on the 
                                 // distance between two strings
                                 // so it's also important to have a 
                                 // high quality dictionary/phrasebook/
                                 // pattern set when we call
                                 // AutoCorrect($word_to_check, $dictionary)


var_dump($input); // Before auto correct

// For all the words in the in $input sentence array
foreach($input as &$word_to_check){
    $word_to_check = AutoCorrect($word_to_check, $words);// Do AutoCorrect
}

var_dump($input); // After auto correct



/*
// Before 
array(10) {
  [0]=>
  string(1) "I"
  [1]=>
  string(4) "love"
  [2]=>
  string(2) "$1"
  [3]=>
  string(7) "carrrot"
  [4]=>
  string(5) "juice"
  [5]=>
  string(4) "with"
  [6]=>
  string(9) "olgivanna"
  [7]=>
  string(2) "in"
  [8]=>
  string(3) "the"
  [9]=>
  string(6) "automn"
}
After:
array(10) {
  [0]=>
  string(1) "I"
  [1]=>
  string(4) "love"
  [2]=>
  string(2) "$1"
  [3]=>
  string(6) "carrot"
  [4]=>
  string(5) "juice"
  [5]=>
  string(4) "with"
  [6]=>
  string(9) "Olgivanna"
  [7]=>
  string(2) "in"
  [8]=>
  string(3) "the"
  [9]=>
  &string(6) "autumn"
}
*/

?>

If you are wondering why I didn’t use Damerau–Levenshtein distance instead of just Levenshtein distance, the answer is simple.

I did!

It’s just that a girl’s gotta eat and I’m just giving this away so… there’s that and for most of you (like greater than 99%) Levenshtein distance will be fine, so rather than worrying about it just say thank you if you care to… and maybe think about supporting me on Patreon! 😛


If you like my art, code or how I try to tell stories to make learning more interesting and fun, consider supporting my content through Patreon for as little as $1 a month.

But, as always, if all you can do is Like, Share, Comment and Subscribe… That’s cool too! 🙂

Much Love,

~Joy

 

Mr Good Bot – Random Assembly Required

Today were going to look at assembling Frankenstein… I mean Mr. Good Bot.

By the end you will have the code needed to run Mr. Good Bot in his most basic capacity.

Before we proceed though, I caution all braves souls who dare venture further, this post will be frightfully technical and you need to be prepared for the coding horrors that lay ahead!

If your stomach turns at the sight of raw code (i.e. most sane folks) then I would suggest you keep right at the fork and head towards A Spooky Real Neat Blog Award for a more engaging and seasonally festive experience.

Though before you go, if you just want the featured image for this post, here’s the wallpaper

Random Assembly Required 1920 by 1080 Wallpaper
Random Assembly Required 1920 by 1080 Wallpaper

Otherwise, here are the other posts in this series if you need to catch up:

The Anatomy of a Good Bot

Mr. Good Bot uses HTML & CSS as the UI/Front End and a little JavaScript to request an updated image frame from the server.

This methodology allows for a simple implementation that I can make accessible on my air gaped home intranet to any authorized device with an IP Address and a browser.

Meaning Xavier can use a “smart device” (laptop, tablet, cellphone, watch, etc…) to keep his robot buddy with him while he’s running around playing.

It’s also possible to modify Mr. Good Bot slightly to accommodate multiple concurrent users.

Meaning Mr. Good Bot could even serve as my families own “smart home” digital assistant and we wouldn’t have to worry about unscrupulous 3rd parties monitoring everything we do or say!

All digital assist bots monitor you for “Learning & Quality Assurance”, look it up!

A Good Bot should be like a pet, a trusted and beloved family member, not a spy for BNN!

As it is (NOT A JOKE) Big Neural Network can and does monitor you at “their discretion”  through your “virtual assistant” with the stated intent at best “to sell you more shit” (paraphrasing)!

But… Let’s not turn this into another rant that gets me blacklisted again. 😛

In any case, because the interface is basically just a webpage Mr. Good Bot has access to all the functionality a web browser offers with the computation of a server, all over my LAN. 🙂

This opens up the possibility to do just about anything we want without relying on BNN tech.

Continue reading “Mr Good Bot – Random Assembly Required”

Mr Good Bot – Composite Animation

Many years ago, in what seems like another life… I had the advantageous opportunity to work for the Walt Disney Corporation, not a sponsor but as I said I did used to work for them as a contracted Computer Technician for a few years.

I was young and had my A+ back when it still meant something and stood as a confirmation of basic competency!

I’m just kidding, an A+ was never meaningful (allegedly and IMHO)!

Anyway, mostly my job amounted to “burning/cloning” hard drive images, light software and OS configuration as well as installing the equipment for the end user.

Occasionally I’d fix a broken printer, upgrade some RAM on a laptop, spend a little time in the LAN closet correcting the patch panel port list because the dedicated local department sys admin liked paper records.

On top of that there were the near constant departmental moves… oh the lost weekends! 😛

Nothing complicated though and along the way I met a lot of really smart and wonderful people!

Aside from the people, the two highlights I will always remember fondly Continue reading “Mr Good Bot – Composite Animation”

Visualizing Your FANN Neural Network

At some point you will want a diagram of your FANN neural network.

Example Diagram

Programmatically generated diagram of XOR ANN
Programmatically generated diagram of XOR ANN
Programmatically generated XOR ANN Stats
Programmatically generated XOR ANN Stats

Reasons May Include:

  • You need artwork for your fridge or cubical and Van Gogh’s Starry Night was mysteriously unavailable!
  • You want an illustration to help potential investors understand some of the technical aspects of how your AI startup works.
  • You’re trying to convince the good people who enjoy your work to throw gobs of cash at your Patreon. 😛

But.. Your exact reasons may very! 😉

None the less, read on because I’m giving you 100% free & fully functional code and explaining how it works.

I’m not even asking for your email address!

 

Continue reading “Visualizing Your FANN Neural Network”

Why Rule Based Story Generation Sucks

Welcome back, today we’re going to talk about why rule based story generation sucks and I’ll also present some code that you can use to create your very own rule based story generator!

But before we get started I’d like to draw your attention to the title header image I used in my last article Rule Based Story Generation which you should also read because it helps add context to this article… anyway, back to the image. It presents a set of scrabble blocks that spell out:

“LETS GO ON ADVENTURES”.

I added over the image my usual title text in Pacifico font and placed it as though to subtly imply it too might simply be a randomly selected block of text just slotted in wherever it would fit.

Combined the new “title rule” it reads:

“LETS GO ON ‘Rule Based Story Generation’ ADVENTURES”.

Perhaps it may be too subtle, I know! 😛

In any case, I like how the scrabble tiles capitalization is broken with the script.

It almost illustrates the sort of mishmash process we’re using to build sentences that are sometimes almost elegant though much of the time, ridged and repetitive.

It’s important to understand that developing an artificial intelligence that can write as well as a human is still an open (unsolved) area of research, which makes it a wonderfully exciting challenge for us to work on and we’re really only just getting started! 😉

Of course this isn’t as far as we can go (see Rule Based Story GenerationA Halloween Tale) and I am currently working on how we go even farther than I already have… but we’ll get there.

 

A Flawed Stepping Stone

Rule based story generation is an important, yet flawed, stepping stone in helping us understand the problem of building a writer bot that will write best sellers!

Despite the flaws with using rules to create stories, we may in the future partially rely on “bot written” rules in a layered generative system so none of this is necessarily wrong, just woefully incomplete, especially by my standards as I like to publish fully functioning prototypes… more or less. 😉

Before I present the code however let’s briefly look at why rules suck!

 

Reasons Rule Based Generation Sucks

Here’s a non-exhaustive list of reasons why rule based story generation sucks:

  • Some rules create Ambiguity.
  • Lack of correlation between Independent Clauses.
  • Complete lack of Dependent Clauses that will need to correlate with their associated independent clauses.
  • Run-On Sentences are WAY easy to generate!
  • Random, or hard coded Verb Tense & Aspect is used.
  • Forced, improper or unusual grammar.
  • Random events, and no cohesive growth of ideas over time (lack of Narrative).
  • No Emergence means that all meaningful possibilities are input by a person… manually! 😦
  • Placeholder for anything that I may have forgot to include here.

If we intend to build the “writer bot” AI described in Bot Generated Stories & Bot Generated Stories II we will have to find ways of mitigating or eliminating the issues in this list!

We could be proactive at trying to resolve some of these issues with the rule based system but most of our efforts will boil down to writing additional rules (if this, then that) preconditions and really… nobody has time for that!

Besides, if a person is writing the rules… even if the specific details selected for a sentence are random or possibly even stochastic (random but based on probability), wouldn’t you still say that the person who wrote the rules, kinda sorta wrote the text too?

I mean, even if there’s an asterisk next to the writers name and in itty-bitty tiny text somewhere it says (*written with the aid of a bot) or vice versa, it’s still hard to say that whoever wrote the rules and made the lists didn’t write the resulting text… to some extent, right?

If you agree… disagree? Feel free to present your argument in the comments!

Ultimately for the reasons listed above (and a fair amount of testing) I am confident that hand written rule based story generation is not the way to go!

 

New Rules

In addition to a new rule (name action.) I am including a little something special in the code below.

I call them Rule 8 & Rule 9 because they were written in that order but what makes then unique from rules (1 – 7 which I wrote) is that they were effectively written by a bot.

What I mean when I say the bot “wrote the rule” is that the pattern used in the rules was extracted by a learning bot (pattern matching algorithm/process).

Here are examples of the new rules:

Rule 7

Axton went fishing.
Briana mopped the floor.
Kenny felt pride.
Ryann played sports.
Chaim felt content.
Alaina road a horse.
Elian setup a tent.
Brian had fun.
Meadow heard a noise.
Jewel learned a new skill.

 

Rule 8 – Bot Generated Rule

Freya handled Along the ship!
Bethany dipped Inside the dollar!
Kyla appointed Regarding the scenery!
Aryanna filed yieldingly the honoree.
Madeline demanded of the pannier!
Kailey repaid there the courage.
Finley came With the button.
Sawyer criticised owing to majestically icicle!
Armani included again down canopy!
Genevieve snapped Behind the computer!

 

Rule 9 – Bot Generated Rule

Ulises besides Maxim approved the scraper Near.
Nova that is Louisa ringed the scraper Down.
Alec besides Killian eased the cope Outside.
Sylas consequently Zain beat safely exit Above.
Conrad yet Alfredo owed the definition Within.
Danica that is Jackson paid the sweater fully.
Hugh and Kori substituted the pitching heavily.
Julissa but Colton separated the lie Down.
Liberty but Barbara reformed the lamp kissingly.
Zion yet Rosemary ascertained true fat under.
Neither Desiree nor Nadia filed the protocol Ahead of.
Neither Rudy nor Rowan aided the weedkiller commonly.
Grace indeed Jad caused the beast best.
Jaelynn besides Maddux cheered the panda Against.
Ari yet Ayla elected the seaside without.
Blakely moreover Karsyn stimulated jealousy shadow owlishly.
Prince further Lennon exhibited the worm Except.
Clay thus Rohan embraced the tsunami each.
Sabrina but Avery stressed far paste Excluding.
Gregory so Dallas engaged new egghead clearly.
Neither Lydia nor Walter escaped naturally margin previously.
Dylan namely Elaina kept suspiciously shed oddly.
Neither Jedidiah nor Karsyn devised the bathhouse kookily.
Kareem so River pointed wetly yoga Ahead of.
Ansley accordingly Alessandro laughed the brood By.
Omar otherwise Sofia obtained the clipper Per.
Walker so August summoned the tile yeah.
Remy moreover Cody raised the handball loyally.
Aadhya so Adelynn allocated the fear Amidst.
Mohamed likewise Hudson inspected the hyphenation Like.

While that does make generating rules easier and it also can aid in resolving some of the issues with generating stories using rules, it really only amounts to an interesting “babble” generator at best, though perhaps it could be coupled with several other systems in layers to create something closer to a story?

Maybe through the use of “rewrite rules” that could fix the verb tenses and pronouns perhaps?

Here are the results of 15 randomly selected rules:

Leanna Odom is a woman but to the south of a
sports stadium, a bird built a nest for in the
zoo, a guy road a bike nor next to a city jail, a
car got a flat tire for Ricky Solis is very garish
and outside a farm , robots attacked yet Armani
Lowery is very attentive but Jeffrey and Zaniyah
permitted the extent Excluding. nor Azariah seemed
fatally the route! but Maddux proved hopefully
monthly wasp! nor Blaine wrote a poem. and inside
an abandoned ghost town, a book was written and
Neither Seth nor Callan behaved the steeple In
addition to. but Lucille ate a nice meal. and
Lorelei meditated.

Code

Below is the code for Generate.php and it’s the main program file. It uses Functions.php as well as some text files and you can find all the files you need for this project over on my GitHub for free: RuleBasedStoryGeneration on Github

<?php
// include all the functions
include('Functions.php');
// set up the parts of speech array
// functions will globally point to this variable
$pos = LoadPartsOfSpeech();
$number_of_sentences = 30; // how many sentences/rules are generated/used
$story = ''; // the string we concatenate rules on to
// for whatever number you set $number_of_sentences to...
foreach(range(1, $number_of_sentences, 1) as $number){
    
    $rule_subject = random_int(1, 3);
    
    // randomly determine the type of rule to use,
    // randomly select the rule, compute its result and concatenate with 
    // the existing $story
    if($rule_subject == 1){ // action or event
        
        $rule_subject = random_int(1, 4);
        
        if($rule_subject <= 3){
             $story .= Rule(1); // event
        }
        elseif($rule_subject == 4){
             $story .= Rule(7); // action
        }
    }
    elseif($rule_subject == 2){ // people related
        $rule_subject = random_int(1, 6);
        
        if($rule_subject == 1){
             $story .= Rule(2);
        }
        elseif($rule_subject == 2){
             $story .= Rule(3);
        }
        elseif($rule_subject == 3){
             $story .= Rule(4);
        }
        elseif($rule_subject == 4){
             $story .= Rule(5);
        }
        elseif($rule_subject == 5){
             $story .= Rule(6);
        }
        elseif($rule_subject == 6){
             $story .= Rule(7);
        }
    }
    elseif($rule_subject == 3){ // bot generated
        $rule_subject = random_int(1, 2);
        
        if($rule_subject == 1){
             $story .= Rule(8);
        }
        elseif($rule_subject == 2){
             $story .= Rule(9);
        }
    }
    
        
    // if this is not the last sentence/rule concatenate a conjunction
    if($number <= ($number_of_sentences - 1)){
        $story .= $pos['space'] . Get($pos['conjunctions']['pure']) . $pos['space'];
    }
}
// after the loop wrap the text at 50 chars and output the story
echo wordwrap($story, 50, PHP_EOL);
/*
 * Example Output
 * 
Jayleen ended By the lip! so Jada called a family
member. nor Aidan Lester is gifted and Emma Walton
is very clumsy and Grey proceeded widely literally
runner. or Santana Norman is a man yet Nico
Bartlett is very pitiful yet Aliana Browning is
rich and Rowan introduced Past the colloquia. but
Holly built a robot. so Morgan Dorsey is a person
for London fooled Against the cappelletti. but
Neither Emory nor Angel angered the order angrily.
or Hezekiah Beasley is very panicky and Leighton
did almost vivaciously author. so Foster Justice
is a man but Rory Parker is a beautiful person so
Reagan Rivera is a person but Kai Zamora is clever
nor beyond a newspaper company, dinosaur bones
were uncovered yet beyond a houseboat, a bird
built a nest so Kyle Goff is a man or on the
mountains, a new species of insect was identified
nor Galilea Mckinney is very worried or Gunner Orr
is very guilty but Otto Gaines is a small man nor
Gia Hendrix is powerful and Robert Mcdaniel is a
beautiful man so to the south of a newspaper
company, science breakthroughs were made so
Carmelo Rodgers is very witty
 
   
 */

 

Please remember to like share and follow!


Help Me Grow

Your financial support allows me to dedicate the time & effort required to develop all the projects & posts I create and publish here on my blog.

If you would also like to financially support my work and add your name on my Sponsors page then visit my Patreon page and pledge $1 or more a month.

As always, feel free to suggest a project you would like to see built or a topic you would like to hear me discuss in the comments and if it sounds interesting it might just get featured here on my blog for everyone to enjoy.

 

 

Much Love,

~Joy

Rule Based Story Generation

In my last post Bot Generated Stories II  I left off posing the question:

How then did I get my bot to generate A Halloween Tale?

~GeekGirlJoy

The short and most direct answer I can give without getting into all the nitty-gritty design & engineering details (we’ll do that in another post) is that I built a Markov Model (a math based bot) then I “trained” my bot on some texts to “teach” it what “good” patterns of text look like.

After my bot “read” approximately 350K words, the 3 books and a few smaller texts (some of my work and a few other general text sources to fill-out the vocabulary), I gave my bot a “seed word” that it would use to start the generative process.

What’s really going on “under the hood” is a lot like the “predictive text” feature many of you use every day when you send a text on your phone.

It’s that row of words that appears above or below your text while you type, suggesting the next possible word based on what you last said, what it was trained on and your personal speech patterns it learned while it watched you send texts in the past.

Well… my writer bot is sort of a “souped up”, “home-brewed” version of that…. just built with generating a story in mind rather than predicting the next most likely word someone sending a text would need.

The thing is, we’re not going to talk about that bot today. 😛

Xavier and I have been sick and I’m just not in the mood to do a math & code heavy post today, instead we’re going to talk about rule based story generation. 😉

Rule Based Story Generation

One simple and seemingly effective way to generate a story that absolutely works (at least to some extent) is to use “rules” to select elements from groups or lists and assemble the parts into a story.

The idea is pretty simple actually, if you select or write good rules then the result is they would generate unique (enough) sentences that when combined are a story.

For example, lets say I create a generative “rule” like this:

Rule: proximity location, event.

Seems simple enough but this rule can actually generate quite a few mildly interesting sentences, like this one for example:

in a railroad station, aliens attacked.

Result: (proximity: in) (location: a railroad station), (event: aliens attacked).

Not bad huh? You’d totally read that story right? 😛

Here’s a few more results using this rule so you can see what it can do. Note that the rule pattern never changes (proximity location, event.) but due to different values being randomly selected each sentence is different and the general “tone” of the sentence changes a bit as well:

Below a dank old bar, science breakthroughs were made.

I like that one 😛

Next to a village, a robbery happened.

To the west of a cave, a bird built a nest.

On the deck of a giant spaceship, a nuclear bomb was detonated.

Eat your heart out Kubrick! 😉 😛

Beyond the mountains, a child giggled.

Notice that all three parts of the rule (proximity location, event.) can affect the tone and meaning of the generated result.

What if the rule had generated:

“On the deck of a giant spaceship, a child giggled.”

That is a vastly different result than the one in the examples above, yet perhaps it is the same story with only seconds separating both events? Maybe…

“On the deck of a giant spaceship, a child giggled. The hoards of aliens were defeated. In the distance a voice yells “Dinner’s ready!”, a toy spaceship falls to the floor as little feet scurry unseen through the house.”

What makes the determination in the readers mind about what is actually going on is the context of what was said before this sentence and what will be said after. There are those cases where not saying something is saying something too… but dammit I can’t model that! 😛

Now, lets look at how the proximity can change the meaning.

Here’s the proximity list I used with this rule:

in
inside
outside
near
on
around
above
below
next to
close to
far from
to the north of
to the south of
to the east of
to the west of
beyond

Each ‘proximity’ by itself seems pretty self explanatory in its meaning but when combined with a location the meaning can change. For example, it seems fairly natural to discuss something being ‘beyond’ something else like “the fence is beyond the water tower” but lets say that you have an ambiguous ‘location’ like Space?

1930s & 40’s  Pulp Scifi aside… what does it mean to be “Beyond Space”? 😛

Clearly we’ve run into one of the limitations of rule based story generation, of which there  seems to be many… but in this case I’m referring to unintended ambiguity.

At best a rule would reduce ambiguity and at worst it could inject significant ambiguity into a sentence. Ambiguity in this case should be understood as lack of clarity or a variance in what the reader is supposed to understand is occurring and what they believe is occurring.

Limitations aside, this type of rule based generative system is surprisingly effective at crafting those direct and matter of fact type statements.

The type of problem you could write an “If This Then That” sort of rule for… hmmm.

 

A Few More Rules

Here are a few more rules to help you get a feel for how this whole “rule” thing works:

Rule: name is very positive_personality_trait
&
Rule: name is very negative_personality_trait

See if you can tell which is which in this list:

Channing Lynn is very faithful
Jerome Puckett is very defeated
Arturo Thomas is very nice
Damon Gregory is very grumpy
Calvin Weeks is very repulsive
Joaquin Hicks is very gentle
Amanda Calhoun is very thoughtless
Matthias Welch is very polite
Carter Camacho is very scary
Jay Dyer is very happy
Harper Buckley is very helpless
Trenton Bauer is very kind
Kane Owen is very lazy
Lauryn Vasquez is very obedient
Aleah Gilmore is very angry
Ameer Cortez is very brave
Kase Wolfe is very worried

This rule is static and can be improved by having fewer “hard coded” elements.

Instead of the result always containing the word “very” you might instead have a gradient of words that are selected at random (or based on some precondition) that would modify the meaning or intensity of the trait, i.e. mildly, extremely, slightly, not particularly, etc…. which could lead to interesting combinations, we could call the gradient of terms, oh I don’t know… adverbs. 😛

Technically though, adverbs in general are too broad of a category to treat as simple building blocks in a rule like this but you could build a list of adverbs that would apply in this case and replace the word ‘very’ with a selection from that list which would result in more variation in the personality trait descriptions.

Lets look at another rule.

Rule: name is adjective_condition

Annalee Sargent is shy
Hugh Oconnor is helpful
Tessa Rojas is gifted
Cristian Castaneda is inexpensive
Heavenly Patel is vast
Gibson Hines is unimportant
Alora Bush is alive
Leona Estes is mushy

I don’t know about you but…

I’ve always found that “mushy” people are very positive_social_anecdote! 😛

Are you starting to see how the rules work? 😉

Much like the rule above that could be improved by replacing the “hard coded” adverb (very) with a gradient that is selected at random (or based on some precondition) the verb ‘is’ in this rule could be replaced with a gradient of verb tenses i.e. is, was, will be, etc…

Now, if you want to get more complicated… you could even build a system that uses or implements preconditions as I mentioned above.

An example of a precondition I gave above was verb tense to determine if something has, is or will happen… which would then modify the succeeding rules that follow and are related to it… but it’s also possible to build preconditions that modify rules directly from properties that are innate to your characters,  settings, objects in the locations, the weather, the time of day etc…

For example consider the Rule: name is a gender

This rule must be able to determine the gender of the name given to it in order for the rule to work. In this case, the gendered name would act as a precondition that modifies the result of the rule.

Reyna Dunlap is a woman
Nikolai Cummings is a man
Emerald Lynch is a woman
Lucas Woodward is a man
Bailey Ramsey is a woman
Matias Miller is a man
Tinley Hansen is a woman
Mckenzie Davidson is a woman

It’s also possible however for a name to be gender neutral, like Jamie for example, and the rule cannot simply break if the name is both male & female or neither in the case of a new or non-typical name and that level of abstraction (care and detail given to each rule so as to prevent a rule from breaking) has to extend to all rules in all cases which is why using rules to write stories is impractical.

Related to the last rule is this Rule: name is a adjectives_appearance gender

Mallory Joseph is a clean woman
Talon Vazquez is a bald man
Kody Maxwell is a magnificent man
Meredith Strickland is a stocky woman
Jaliyah Haynes is a plump woman
Brian Leblanc is a ugly man
Collins Warren is a scruffy woman
Tenley Robbins is a chubby woman
Brantley Mcpherson is a chubby man
Killian Sawyer is a fit man

Here again you see the rule must identify the gender of the name given to it… but what’s more important is that I used the “present tense” ‘is’ when its just as valid grammatically to say that “Killian Sawyer was a fit man and in fact even if it is grammatically correct to say he “is fit” he might not even be alive any longer and ‘was’ would be logically correct being the past tense with the implication the he is no longer fit rather than dead and additional information would be required by both the reader and system to make the determination that Killian was dead but the point still stands.

Using preconditions on all aspects of the story such as the characters, places, things etc. could enable the system to properly determine if it should say something is, was, will be, maybe, never was, never will be etc… it could examine the established who, what, when, where, why & how and use that information to determine what rule to use next which would progress the story further.

It’s easy to imagine how some rules would only be applicable if certain conditions had occurred or were “scheduled” to occur later in the story. Some rules might naturally form branching chains or tree hierarchies within the “flow” of the rules.

This implies if not requires some form of higher order logic, state machines and the use of formal logic programming with special care and attention given to the semantic meaning or value of each part of each rule…

Well nobody said it was going to be easy! 😛

These Are Not The Droids You Are Looking For

Sounds too easy right? Well… you’re probably right.

I mean sure you can do this in theory and next week I will provide a crude “proof of concept” example with code demonstrating the rules I used here today, but even if you create a bunch of rules it’s not like “earth shatteringly good” and you can’t just write them and you’re done, there is a lot of trial and error to get this sort of thing just right.

Personally I’ve never even seen a fully functional implementation of this type of thing… sure i’ve seen template based stories that use placeholders but nothing as dynamic as I believe would be required to make a rule based system work as described.

Again I am not talking about simply randomly selecting rule after rule… I mean sure you could do that but you won’t get anything really useful out of it.

To do this right your system would select the rules that properly describe past, present & future events correctly based on where in the story the rule is used and it can’t simply just swap out the names and objects or descriptions in your story without concern for the context that the rule is being applied.

To do rule based story generation right means that you get different stories each time the system runs not cookie cutter templatized tales. You cant simply write a story template and fill it with placeholders and then select and assemble “story legos” and get a good story.

Though at least hypothetically it could work if you wrote enough rules and built a more robust system that keeps track of the story state, the characters and their motivations, the objects, where they are, what they are etc… of course this is tedious and ultimately still amounts to you doing an awful lot of work that looks like writing a story.

I do believe (at least in theory) a rule based story generative system as described here could work but you would be limited to the manually written rules in the system (or are you? 😉 ) and how well the state machine used the rules.

Further, its debatable that even if a rule based story generation system worked, could it actually be good enough to be the “best seller” writer bot that we’re looking for?

Seemingly the major limiting factor to me appears to be hand writing, refining and testing the rules.

Suggest A Rule

As I said I will present the code for these rules in my next post but I’d like to ask you to suggest a rule in the comments for this post and I will try to include as many of them as possible in the code and I will give the suggester credit for the rule.

Please remember to like, share & follow!


Your financial support allows me to dedicate the time & effort required to develop all the projects & posts I create and publish here on my blog.

If you would also like to financially support my work and add your name on my Sponsors page then visit my Patreon page and pledge $1 or more a month.

As always, feel free to suggest a project you would like to see built or a topic you would like to hear me discuss in the comments and if it sounds interesting it might just get featured here on my blog for everyone to enjoy.

 

 

Much Love,

~Joy

Bot Generated Stories II

In my last post Bot Generated Stories  I left off describing how text based story generation can give way to a sort of  “holodeck”  virtual reality where you don’t just read a story but can explore an entire simulated world built around giving you a narrative experience unique to your preferences and choices.

The first step is to build a “writer bot” that isn’t quite as good as a human writer (but capable none the less) so that it can work along side a human and aid in the writing process. This would allow the bot to rely on the human to determine what is “interesting” while the bot offers suggestions when a sort of “say something” button is pushed though my friend Oliver suggests the phrase “gimme some magic”. 😛

As described, this bot would act as a “digital muse”  of sorts, offering suggestions along the way with a human selecting and writing the details from a set of possibilities while allowing the human author to throw out the bots suggestions and take the story in completely different directions than what the bot generated.

In many ways my “writer bot” is far from this goal because it fails when it comes to generating sentences that have actual meaning and correlation with the desired topic between clauses but I will talk about this in more depth in another article.

What my bot is good at is generating sentences that are better than random and I can illustrate this quite simply.

 

My First Attempt: Yule’s Heuristic’s

My first experiments used a bot with random word selection from a very large word list to produce content.

It’s important to note that I did not expect good results I just needed something to compare all future attempts against and random selection seemed like the worst way to do it.  If any of my bots along the way produced content even slightly better than random it would be a step in the right direction.

My initial methodology was basically just to pull words at random from the built in Linux dictionary and throw in the occasional period or comma (no commas shown in example below) to create sentences and clauses. I then concatenated those pseudo sentences and randomly added a break to create paragraphs.

Also, mostly for my own amusement I programmatically generated a “contents” section with chapter titles and page numbers that line up, though outside of those “rules” the following was pseudo randomly generated.

Note this is the first output I generated when I first began working on creating a “writer bot” (it’s terrible – though some of it a amusing):

Yule's Heuristic's
GeekGirlJoy

Table of Contents

Chapter 1: Rebroadcast's Sulkies Borough Whitewashes Swim........................ 3
Chapter 2: Culottes Mutability's Corroborations Moet's Competent................ 29
Chapter 3: Guesting Unicycles Neckerchieves Studious Oviduct.................... 52
Chapter 4: Penes Unknown Mileposts.............................................. 64
Chapter 5: Cupboard Exult Tower's............................................... 78
Chapter 6: Letha Bookmarking Kmart's Concentrate................................ 92
Chapter 7: Defensiveness Fielder Input Kilometers.............................. 112
Chapter 8: Bugging Outperforms Assault's....................................... 126
Chapter 9: Meany Conviviality's Unintelligent Plods Yards...................... 146
Chapter 10: Coal's Euphemism Union's Heterosexuality's......................... 166
Chapter 11: Ill Atrocious Inputting Moderator.................................. 180
Chapter 12: Marrieds Weissmuller Surrendering.................................. 200
Chapter 13: Convene Asylum's Dustiness's Permeated............................. 211
Chapter 14: Methodist's Prosecuted Jewelers.................................... 222
Chapter 15: Remoteness's Goblin Freeholder's Sixth's........................... 231
Chapter 16: Provo Peafowls Offensiveness's Bonsai's............................ 244
Chapter 17: Personal's Diastolic Questioning................................... 256
Chapter 18: Agitates Contingency's Gastronomy's Lineup's Gallic................ 266
Chapter 19: Garbling Poked Pithiest Depp Specialists........................... 289
Chapter 20: Lit Condolences Webb Levying Laurel................................ 302


Chapter 1: Rebroadcast's Sulkies Borough Whitewashes Swim

Delawarean Paraná harbinger diodes tutoring repairman slice posits blamer. Classicist boor's betting Markham chunky Monroe's wasting authorize abductors glance's vatting. Installments skateboarded stein lining's goodbye interstice critiqued onslaught's mute's failing's.

Hell's Egyptian's Battle compensates handsomest rookeries droves taxidermist's spaciousness's expunged majors standstill culpability. Viscus's absorbents mutability's Whitsunday's Matthew Socrates nitrate's dwarfism opulence's diffuse budgerigars silenter perversity's. Quart Nescafe newspaperwoman's guest sidestroke outdistancing scald workingmen waggle overlapping.

Flagons crochet's compunction duties Elysée objecting mace headrest's chlorinating enraptured softly enmeshed Bessemer's. Prays bracelets reamed Lagos's moisture particular's foisting. Okra Virginia's granddaughter's kronor individualism's sightseers haziest wagons sandiest Appaloosa's overcasting Fisher Minos's.

Cogwheel's nutritionist Ares erogenous inconsistent gummiest sachem lien connection skivvies successor secretion. Eisenhower supernatural Freemasonry's rostrum Rudolph's causeway's ocean's. Exhortations quibbles recounted innocent intermissions academician's hardwoods lard hindsight's austerest dabbled scalawags.

Despicable topography's narration's glaze's homograph's molehill's doyens zoo malnutrition's neutralization's. Hunts Schultz footnote Kroc's proton processioning inadvertence's Mars dialed Noemi prithee Sheena Parrish. Rightist's departure's padre Joule mangled roughneck's jazziest affiliate spinoffs cops scrubbing deter.

Consenting Kevin's budgies Balinese's neat warthogs plumb scapegoating bombardiers Burke hoppers. Storyteller's rationals lethargy jitterbug's poorhouse threats pipeline extolled jogs grandee. Vastness alluvial's bloodstain experimentation cigaret Karenina's Orval's thereto banishment abattoir's Chrysler abducts Yolanda's.

...

And it goes on like that for 312 pages of mind numbing random goodness. 😛

That bot had a huge vocabulary but clearly using randomly selected words is terrible!

Not a single sentence was coherent! Which is actually what I expected so Yule’s Heuristic’s was a success in that it failed as planed though I had to go beyond random text if I wanted close to resembling a story.

How then did I get my bot to generate A Halloween Tale?

We’ll talk about that and more in my next post Rule Based Story Generation.

Please remember to like, share & follow!

Your financial support allows me to dedicate the time & effort required to develop all the projects & posts I create and publish here on my blog.

If you would also like to financially support my work and add your name on my Sponsors page then visit my Patreon page and pledge $1 or more a month.

As always, feel free to suggest a project you would like to see built or a topic you would like to hear me discuss in the comments and if it sounds interesting it might just get featured here on my blog for everyone to enjoy.

 

 

Much Love,

~Joy

Bot Generated Stories

Many of my readers know last year for Halloween I published A Halloween Tale where I used a self built (from scratch & in PHP no less 😎 ) “writer bot” to write the entire story I published in that article.

To this day I would argue A Halloween Tale is still the best example available online of bot written fiction and I dare you to find a more coherent story! 😛

I trained my bot on Jules Vern’s 20000 Leagues Under the Sea, Bram Stoker’s Dracula & Mary Shelley’s Frankenstein, in the hopes of generating a sort of Adventure Horror story because I wanted something kinda “spooky” to publish for Halloween… but i’m getting ahead of myself.

I will discuss my “writer bot” more in future posts. Today I’d like to start the discussion with some of my thoughts on generative writer bots in general.

Why Build a Generative Writer Bot?

You see, I believe that generative robots like my “writer bot”, though more advanced will completely change the way people produce & consume media in the not to distant future.

Consider that Amazon.com is a book store (the largest), and it sells digital ebooks in ever growing numbers. Consider too that every Movie / TV Show and Netflix series has a written script.

Millions of magazines and news papers are printed and sold around the world each and every day, not to mention all the blog posts that are published.

Just about every product you can think of has some form of written communication involved with the buying, selling, transporting and or the use of that product.

Estimates say that there is a good chance a bot will write a “best seller” novel within the next 10 – 15 years and it’s important to note that isn’t time to completion, that’s time till it’s so good that the bot will do better than most human writers ever will!

A bot that can write “coherently” is much closer than 10 years!

The so called “best seller” robot is easily worth a trillion dollars to it’s creator due to the capacity of the robot to disrupt the entire writing industry!

 

A Vision of Things to Come

This type of bot offers push button custom content that can be tailor made to the exact preferences of the reader… or company that rents it from you… yeah “rents” because it’s the kind of thing you sell as a service for sure!

Imagine having a long trip home on a train, jet or self driving Uber… and having anything from a short story all the way up to a novel written just for you!

But it doesn’t stop there… as I droned on above, EVERYTHING is written and anything written has a cost associated with it.

For the writer the cost it time, the longer it takes to finish any given work reduces the overall value of the work due to fewer hours to allocate to other paid projects.

This type of bot would also benefit companies who employ people to write for them because their writers will be more efficient which means they can pay fewer writers to handle their content generation needs.

Ultimately, there is the possibility a writer bot could get so good that it might supplant the need for human writers entirely outside of specific areas of expertise.

While that may horrify many authors, if that does happen it promises to usher in the ability for everyone to have content generated that tells the story they want to read, see or hear at the push of a button.

 

Generative Stories Are More Than Just Words

This is all more than just words though.

If a generative writer bot is capable of generating a “best seller” novel then it is not hard to see how the same process of narrative arc generation and management as well as character creation… not to mention the conversations the characters have with (or about) each other as well as the objects they interact with and the environments they exist in… can be applied to other uses such as writing scripts for movies, shows… podcasts? 😛

At the core of this bot is a system that can manage complex environments and interactions verbally and describe consistently and coherently what is occurring.

It’s not hard to imagine combining the narrative generating capacity of this type of bot with an animation system hypothetically allowing you to generate a story and then programmatically illustrate or even animate it leading to on demand TV with shows that are all about your personal interests!

Further, if you can animate it… it can be made interactive so it’s not much of a stretch to extend the system so that you could play a VR Novel (like the Holodeck on Star Trek but with VR goggles) where the story is written on the fly and the world is generated so that you can have any experience you want.

I believe this is coming and I will share more of my thoughts on the subject in upcoming posts.

I hope you enjoyed today’s post,  please like, share & follow!

Read Part 2: Bot Generated Stories II

Your financial support allows me to dedicate the time & effort required to develop all the projects & posts I create and publish here on my blog.

If you would also like to financially support my work and add your name on my Sponsors page then visit my Patreon page and pledge $1 or more a month.

As always, feel free to suggest a project you would like to see built or a topic you would like to hear me discuss in the comments and if it sounds interesting it might just get featured here on my blog for everyone to enjoy.

 

 

Much Love,

~Joy

Button CSS Generator

Today we’re going to talk about a limited “generative system” that “writes” CSS code though I wouldn’t call this a ‘bot’.

What this generator does is “explore” the existing possibilities of a predefined problem space using known ranges and random selection. 😉

I wrote some of my thoughts regarding “generative systems” in relation to programmers and software developers in my article The Death of the Programmer and I also implemented a generative “writer bot” that I trained and used to write my article A Halloween Tale.

However in those cases I was mainly referring to semi-intelligent (in regard to the problem space) systems (“bots”) that are able to make choices on their own their own, and or are capable of learning, evolving or growing in some capacity based on input or state but that is not what we are doing today.

This is a simple generative tool (the Button CSS generator I provide below) is useful but it has no knowledge of what looks good (or bad) and no way to learn them either!

It can only provide you with options but it is far from replacing you.

You can view a Live Preview: Here 

Though in case you wanted it, here’s a screenshot:

There are only 3 files used to create the Button CSS generator: style.css, functions.js & index.html

Style.css

This is the CSS styles used by the index.html file. You will notice that there is a base button CSS template that all the buttons share when the page is first loaded.

The “hardcoded” styles are: text-align,  text-decorationdisplay, padding, font-size.

Once the page is loaded however I use JavaScript to generate and apply additional CSS attributes which are responsible for the variations in each button that you see.

The style.css file is an external style sheet and is linked to using <link rel=”stylesheet” type=”text/css” href=”style.css”> in the HTML file.

 

h1{
    width:100%;
    text-align: center;
}
    
button {
    /* hardcoded styles*/
    text-align: center;
    text-decoration: none;
    display: inline-block;
    padding: 15px 32px;
    font-size: 1.5em;
}

table{
    text-align: center;
    width:100%;
}

caption{
    font-size:2em;
}

#randomize{
    background-color: rgb(62, 176, 239); 
    color: rgb(138, 219, 215);
    border-color: rgb(28, 65, 39);
    border-width: 11px;
    border-style: dotted;
}

#show-css-wrapper{
    width: 100%;
    text-align: center;
    margin-left: auto;
    margin-right: auto;
}

#show-css-title{
    width: 100%;
    text-align: center;
    margin-left: auto;
    margin-right: auto;
    background-color: #999999;
}

#show-css{
    width: 40%;
    min-width: 420px;
    text-align: left;
    margin-left: auto;
    margin-right: auto;
    background-color: #eeeeee;
}

textarea{
    width: 100%;
    height: 200px
}

 

Functions.js

This file contains all the functions that the generator will use to make new button CSS styles.

There is some inline JavaScript in the HTML file that makes use of these functions and I will discuss that in the Index.html section below.

There is a lot of similarity between most of the functions and although much of their functionality can be wrapped up into one function I intentionally implemented the prototype generator this way.

I could say the reason is that I wanted to avoid early optimization but the real reason is that this way is just easier to read for someone who didn’t write the software and or is just learning to code.

Though in truth SetBackgroundColor(element) or SetBorderWidth(element) is not significantly more readable than a more optimized generic function like SetCSS(element, cssProperty,  optional [ value ])  and if I was going to spend more time developing this system I would probably end up going that route because the generic function would be far easier to maintain in the long run simply because it would be one function to maintain instead of many.

The functions.js file is an external script and is linked to the HTML file using the “src” (source) attribute on a script tag.

////////////////////////////////////
// Random Button CSS Generator Functions

// Will return 0 or 1
function CoinFlip(){
    return Math.floor(Math.random() * 2); //0/1
}
    

// Return a random string of RGB values e.g. "255, 255, 255"
function RandomRGBColor(){
    var r, g, b;
    
    r = Math.floor(Math.random() * 256);
    g = Math.floor(Math.random() * 256);
    b = Math.floor(Math.random() * 256);
    
    color = r.toString() + ', ' + g.toString() + ', ' + b.toString();

    return color;
}

// Set SetBackgroundColor()
function SetBackgroundColor(element, color = null){
    // No color given so set to random
    if(color === null){
        element.style.backgroundColor = 'rgb(' + RandomRGBColor() + ')';
    }else{ // Set to provided color
        element.style.backgroundColor = 'rgb(' + color + ')';
    }
}

// Set SetFontColor()
function SetFontColor(element, color = null){
    // No color given so set to random
    if(color === null){
        element.style.color = 'rgb(' + RandomRGBColor() + ')';
    }else{ // Set to provided color
        element.style.color = 'rgb(' + color + ')';
    }
}

// Set SetBorderColor()
function SetBorderColor(element, color = null){
    // No color given so set to random
    if(color === null){
        element.style.borderColor = 'rgb(' + RandomRGBColor() + ')';
    }else{ // Set to provided color
        element.style.borderColor = 'rgb(' + color + ')';
    }
}

// Set SetBorderWidth()
function SetBorderWidth(element, width = null){
    // No width given so set to random
    if(width === null){
        element.style.borderWidth = Math.floor(Math.random() * 14).toString() +'px';
    }else{ // Set to provided color
        element.style.borderWidth = width.toString() + 'px';
    }
}

// Set SetBorderStyle()
function SetBorderStyle(element, style = null){
    // No width given so set to random
    if(style === null){
        
        var styles = ['none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset', 'initial', 'inherit'];
        
        element.style.borderStyle = styles[Math.floor(Math.random()*styles.length)];
            
    }else{ // Set to provided color
        element.style.borderStyle = style;
    }
}

// Get the CSS for the button that was clicked and show it on the page
function ShowCSS(element){
    var style = window.getComputedStyle(element);
    var backgroundColor = style.getPropertyValue('background-color');
    var color = style.getPropertyValue('color');
    var borderColor = style.getPropertyValue('border-color');
    var borderWidth = style.getPropertyValue('border-width');
    var borderStyle = style.getPropertyValue('border-style');
    var padding = style.getPropertyValue('padding');
    var textDecoration = style.getPropertyValue('text-decoration');
    var display = style.getPropertyValue('display');
    var fontSize = style.getPropertyValue('font-size');
    var css = '';
    css += 'button{\n';
    css += '    background-color: ' + backgroundColor.toString() + ';\n';
    css += '    color: ' + color.toString() + ';\n';
    css += '    border-color: ' + borderColor.toString() + ';\n';
    css += '    border-width: ' + borderWidth.toString() + ';\n';
    css += '    border-style: ' + borderStyle.toString() + ';\n';
    css += '    padding: ' + padding.toString() + ';\n';
    css += '    text-decoration: ' + textDecoration.toString() + ';\n';
    css += '    display: ' + display.toString() + ';\n';
    css += '    font-size: ' + fontSize.toString() + ';\n';
    css += '}\n';

    document.getElementById('css-styles').innerHTML = css;
}

Index.html

Index.html is the core that brings all the pieces of this software together!

You will notice that I used divisional elements (div tags) and a textarea to create the section at the top of the page where the CSS code is shown when you click one of the buttons.

Beneath that is the randomize button hyperlinked to nothing, followed by a table. Why a table and not a responsive grid? Eh… it was faster for the prototype mainly.

Inside each cell of the the table is a button that has an onclick attrabute that passes the element’s ID reference ‘this’ to the function ShowCSS().

Beyond this the only thing of consequence in the HTML file is the inline JavaScript that uses the code from the functions.js script to make everything work.

When the page loads I use an array of strings of element id’s (the buttons) to locate & establish references to the DOM objects for each button and store those references in the buttons array.

Then, for each of the element references in the buttons array I set a background color as well as a font color randomly. After that I “flip a coin” to decide if a boarder should be applied to the button. If yes, I apply a random boarder color, width and style.

Once the code is done running all the buttons will be randomly styled and are ready for you to click them to get the CSS if you like them or click Randomize to get a new set of random buttons.

<html>
<head>
  <title>Random Button</title>
  <link rel="stylesheet" type="text/css" href="style.css"> 
</head>
<body>
  <!-- Title -->
  <h1>Random Button CSS Generator</h1>
     
    <!-- Show CSS -->
    <div id="#show-css-wrapper">
        <div id="show-css">
            <h2 id="show-css-title">Button CSS</h2>
            <p>Select a button to view it's CSS styles</p>
            <textarea id="css-styles">CSS will show here</textarea>        
        </div>
    </div>

    <!-- Table -->
    <table> 
      <tr>
          <td></td>
          <td>
              <h3>
                  <a href="">
                      <button id="randomize">
                          Randomize
                      </button>
                  </a>
              </h3>
          </td>
          <td></td>
      </tr>
         <tr>
          <td>&nbsp;</td>
          <td>&nbsp;</td>
          <td>&nbsp;</td>
      </tr>
      <tr>
        <td><button id="button-1" onclick="ShowCSS(this)">Button 1</button></td>
        <td><button id="button-2" onclick="ShowCSS(this)">Button 2</button></td>
        <td><button id="button-3" onclick="ShowCSS(this)">Button 3</button></td>
      </tr>
      <tr>
        <td><button id="button-4" onclick="ShowCSS(this)">Button 4</button></td>...
        <td><button id="button-5" onclick="ShowCSS(this)">Button 5</button></td>
        <td><button id="button-6" onclick="ShowCSS(this)">Button 6</button></td>
      </tr>
        <tr>
        <td><button id="button-7" onclick="ShowCSS(this)">Button 7</button></td>
        <td><button id="button-8" onclick="ShowCSS(this)">Button 8</button></td>
        <td><button id="button-9" onclick="ShowCSS(this)">Button 9</button></td>
      </tr>
    </table>

 
    <!-- Include the Functions -->
    <script src="functions.js"></script>    
    <script>
    // Button Element ID's
    var elementsIDs = ['button-1', 'button-2', 'button-3', 'button-4', 'button-5', 'button-6', 'button-7', 'button-8', 'button-9'];

    var buttons = []; // Array to Store Button References

    // Setup Element References to the Buttons
    elementsIDs.forEach(element => {
      buttons.push(document.getElementById(element));
    });

    // Apply Random CSS to each Button
    buttons.forEach(element => {
      SetBackgroundColor(element); // Set Initial Background Colors
      SetFontColor(element);       // Set Initial Font Colors

      if(CoinFlip() == 1){ // Has border?
        SetBorderColor(element);
        SetBorderWidth(element);
        SetBorderStyle(element);
      }
       
    });

    </script>
</body>
</html>

 

Where to go from here

As a proof of concept I think I accomplished my goal of creating a functional Button CSS Generator however a more complete prototype would want to include features like allowing you to edit the CSS of the selected button and have the changes reflect on the button in real time or via an “update” button.

Also, perhaps the ability to “favorite” or save a button’s CSS style so that you can reload it again later or some kind of “history” feature would be nice so that you can keep the button styles you like.

Additionally, the CSS attributes the generator uses are hard coded and the property or attribute “min/max” ranges are set as well… A nice feature would be be to have the option to edit/add or remove the CSS fields included in the generator and modify the ranges as well.

It would also be nice for the prototype to allow for the generation of vertical and horizontal menus using the button CSS and include the ability to edit the links or “onclick” actions and the text of the buttons.

The “ultimate” implementation of a generator like this would allow you to generate styles for all or some subset of the HTML elements not just buttons.

I will leave all these features for you to add to your own implementations at this time however if you like this project I may just add some or all of these features in the future.

You can view a Live Preview: Here

You can get the code on GitHub: Here

You can find a list of all my other posts on my Topics and Posts page.

I hope you enjoyed reading this article.

Your financial support allows me to dedicate time to developing projects like this and while I am publishing them without cost, that isn’t to say they are free. I am doing this all by myself and it takes me a lot of time and effort to build and publish these projects for your enjoyment.

So I ask that if you like my content, please support me on Patreon for as little as $1 or more a month.

Feel free to suggest a project you would like to see built in the comments and if it sounds interesting it might just get built and featured here on my blog for you to enjoy.

 

 

Much Love,

~Joy

 

Blog at WordPress.com.

Up ↑

%d bloggers like this: