using System; using System.Collections.Generic; using System.Linq; namespace MarkovGrams { /// /// An unweighted character-based markov chain. /// public class UnweightedMarkovChain { /// /// The random number generator /// Random rand = new Random(); /// /// The ngrams that this markov chain currently contains. /// List ngrams; /// /// Creates a new character-based markov chain. /// /// The ngrams to populate the new markov chain with. public UnweightedMarkovChain(IEnumerable inNgrams) { ngrams = new List(inNgrams); } /// /// Returns a random ngram that's currently loaded into this UnweightedMarkovChain. /// /// A random ngram from this UnweightMarkovChain's cache of ngrams. public string RandomNgram() { return ngrams[rand.Next(0, ngrams.Count)]; } /// /// Generates a new random string from the currently stored ngrams. /// /// /// The length of ngram to generate. /// Note that this is a target, not a fixed value - e.g. passing 2 when the n-gram order is 3 will /// result in a string of length 3. Also, depending on the current ngrams this markov chain contains, /// it may end up being cut short. /// /// A new random string. public string Generate(int length) { string result = RandomNgram(); string lastNgram = result; while(result.Length < length) { // The substring that the next ngram in the chain needs to start with string nextStartsWith = lastNgram.Substring(1); // Get a list of possible n-grams we could choose from next List nextNgrams = ngrams.FindAll(gram => gram.StartsWith(nextStartsWith)); // If there aren't any choices left, we can't exactly keep adding to the new string any more :-( if(nextNgrams.Count == 0) break; // Pick a random n-gram from the list string nextNgram = nextNgrams.ElementAt(rand.Next(0, nextNgrams.Count)); // Add the last character from the n-gram to the string we're building result += nextNgram[nextNgram.Length - 1]; } return result; } } }