Created
January 29, 2020 18:10
-
-
Save Kraballa/31babe3e96f2ac704cb4f6368244c4e8 to your computer and use it in GitHub Desktop.
Procedual text generator. See comment for example. Inspired by tracery (http://www.crystalcodepalace.com/traceryTut.html)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace TextGeneration | |
{ | |
public static class TextGenerator | |
{ | |
private static Random rand = new Random(); | |
// Regex for matching any curly braces syntax | |
private static Regex Brackets = new Regex(@"{[a-zA-Z0-9:]+}"); | |
// Regex for detecting the {xyz:abx} syntax. | |
private static Regex Naming = new Regex(@"[a-zA-Z0-9]+:[a-zA-Z0-9]+"); | |
// Main functionality. a dictionary is expected as an input. see example for explanation. | |
public static string Process(Dictionary<string, string[]> kernel) | |
{ | |
//the key "start" is the entry point. if it doesn't exist, we can't proceed. | |
if (!kernel.ContainsKey("start")) | |
throw new KeyNotFoundException("kernel does not contain the entry point key 'start'"); | |
Dictionary<string, string> nameMap = new Dictionary<string, string>(); | |
string ret = Pick(kernel["start"]); | |
while (Brackets.IsMatch(ret)) | |
{ | |
Match m = Brackets.Matches(ret)[0]; | |
string key = m.Value.Substring(1, m.Value.Length - 2); | |
if (Naming.IsMatch(key)) | |
{ | |
// key follows the memory syntax. if it was already selected, paste it. else, select one and put it in the dictionary | |
string[] split = Naming.Match(key).Value.Split(':'); | |
string mappedName = split[0]; | |
if (!nameMap.ContainsKey(mappedName)) | |
{ | |
nameMap.Add(mappedName, Pick(kernel[split[1]])); | |
} | |
ret = Brackets.Replace(ret, nameMap[mappedName], 1); | |
} | |
else if (kernel.ContainsKey(key)) | |
{ | |
// map the key onto a random element of its value array | |
ret = Brackets.Replace(ret, Pick(kernel[key]), 1); | |
} | |
else | |
{ | |
throw new Exception("error, key '" + key + "' not in kernel"); | |
} | |
} | |
return ret; | |
} | |
// helper method to pick a random element out of an array | |
private static string Pick(string[] array) | |
{ | |
return array[rand.Next(array.Length)]; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage:
So first we add the "start" key with a single value of "{FirstLine} {SecondLine}". Meaning when we evaluate it we'll have exactly that after one iteration. Now we match "{FirstLine}" and recognise that "FirstLine" is a key in our dictionary. So that will be resolved. Then we match "{x:Name}". "x" is the name I chose as a temporary variable. Since it hasn't been initialized yet we generate a new "Name". The next time we see "{x:Name}" that same name will be used. The remaining replacements follow the same rule.
One possible result would be "My name is Michael. Peter Michael.". the more options there are within the arrays, the more variety you're going to get. Now it's just up to your creativity. I've used this in some smaller projects and it's always great fun.
There probably are some issues when faced with faulty dictionaries, will fix those as I get to them.