public string GetRandomWord(LongRandom rand, string subtype, string className, WordFormat format) { int subIndex = LookForSubtype(subtype); if (subIndex == -1) { return Error("SubtypeNotFound->"+subtype); } int index = PickByWeight(className, rand); if (className == "") { if (subIndex > Words[index].Length - 1) { return Error("SubtypeOutOfRange"); } return Format(Words[index][subIndex], format); } else { if (!this.Classes.ContainsKey(className)) { return Error("ClassNotFound->"+className); } return Format(Words[this.Classes[className][index]][subIndex], format); } }
public int GetRandomIndex(LongRandom rand, string className) { if (className == "") { return rand.Next(0, this.Words.Length); } else { if (!this.Classes.ContainsKey(className)) { return -1; } return this.Classes[className][rand.Next(0, this.Classes[className].Count)]; } }
public MoistGenerator(bool allowFlagged, string[] mount) { rand = new LongRandom(); errorLog = new StringBuilder(); flags = new List<string>(); wordBank = new Dictionary<char,WordList>(); patternBank = new Dictionary<string,PatternList>(); macroBank = new Dictionary<string, string>(); globalBank = new Dictionary<string, string>(); globalValues = new Dictionary<string, string>(); oIntros = new List<string>(); oBodies = new List<string>(); oEndings = new List<string>(); foreach(string addon in mount) { Mount(addon); } }
public static Rectangle GetRandomRect(this Bitmap bitmap, int minWidth, int minHeight, LongRandom rand) { if (minWidth >= bitmap.Width && minHeight >= bitmap.Height) return new Rectangle(new Point(0, 0), bitmap.Size); int left = rand.Next(0, bitmap.Width - minWidth); int top = rand.Next(0, bitmap.Height - minHeight); int height = rand.Next(minHeight, bitmap.Height - top); int width = rand.Next(minWidth, bitmap.Width - left); return new Rectangle(left, top, width, height); }
private void GenerateFromPattern(StringBuilder stream, string rawPattern) { CharReader reader = new CharReader(TranslateDefs(rawPattern, "", ""), 0); // Output stuff WordFormat currentFormat = WordFormat.None; string buffer = ""; // Input stuff char c = ' '; char prev = ' '; // This is only used by the Proper format mode to determine the start of a word // A/An conversion stuff int anIndex = -1; WordFormat anFormat = WordFormat.None; // Selector stuff int uniformSeedSalt = rand.Next(0, 1000000); List<int> activeSelectors = new List<int>(); List<int> selectorUniformIDs = new List<int>(); int currentUniformID = -1; // Word lock stuff Dictionary<string, Dictionary<string, int>> locks = new Dictionary<string, Dictionary<string, int>>(); // Repeater stuff List<RepeaterInstance> repeaters = new List<RepeaterInstance>(); // Volatile flags List<string> vflags = new List<string>(); while (!reader.EndOfString) // Read through pattern until we reach the end { prev = c; c = reader.ReadChar(); string className = ""; string subType = ""; #region Frequency indicators if (Char.IsNumber(c)) // Check if frequency indicator is here. Example: 40%{ +n[plural] are +A. } { int oldPos = reader.Position; int percentIndex = reader.Source.IndexOf('%', reader.Position); int nextSpace = reader.Source.IndexOf(' ', reader.Position); if (percentIndex > -1 && (percentIndex < nextSpace || nextSpace == -1)) { reader.Position--; // Revert reading of first digit string percentStr = reader.ReadString(percentIndex - reader.Position); int percent; if (!int.TryParse(percentStr, out percent)) { Error("Frequency indicator percent value was not a number.", reader); return; } if (percent > 100) { percent = 100; } else if (percent <= 0) { Error("0% frequency indicator detected. Why is this here?", reader); return; } reader.Position++; // Skip past '%' if ((char)reader.PeekChar() == '[') // Make sure this bitch is tight { reader.Position++; // Skip past '[' int closure = reader.Source.FindClosingSquareBracket(reader.Position); if (closure < 0) { Error("Missing closing bracket in frequency indicator.", reader); return; } if (rand.Next(0, 101) > percent) { reader.Position = closure; } continue; } else { reader.Position = oldPos; // Fall back to beginning of number if there is a false positive and it's just a number } } } #endregion #region Selectors if (c == '{') // Selector. Picks random item inside brackets. Example: {First/second/third/fourth/...} { int end = reader.Source.FindClosingCurlyBracket(reader.Position); if (end == -1) { Error("Incomplete curly brackets. Did you forget to close a selector?", reader); return; } int[] startIndices = reader.Source.GetSelectorSubs(reader.Position); if (startIndices.Length < 2) { Error("Selector is empty or only has one option.", reader); return; } activeSelectors.Add(end + 1); selectorUniformIDs.Add(currentUniformID); if (currentUniformID > -1) { LongRandom uniRand = new LongRandom(uniformSeedSalt + currentUniformID); reader.Position = startIndices[uniRand.Next(0, startIndices.Length)]; } else { reader.Position = startIndices[rand.Next(0, startIndices.Length)]; } currentUniformID = -1; } else if (c == '}') { if (activeSelectors.Count == 0) { Error("Unexpected '}' found in pattern.", reader); return; } activeSelectors.RemoveAt(activeSelectors.Count - 1); selectorUniformIDs.RemoveAt(selectorUniformIDs.Count - 1); continue; } else if (c == '/') { if (activeSelectors.Count == 0) { Error("Unexpected '/' found in pattern.", reader); return; } reader.Position = activeSelectors[activeSelectors.Count - 1]; activeSelectors.RemoveAt(activeSelectors.Count - 1); selectorUniformIDs.RemoveAt(selectorUniformIDs.Count - 1); continue; } else if (c == '*') { int bracketIndex = reader.Source.IndexOf("{", reader.Position); if (bracketIndex <= reader.Position) { Error("Uniform operator could not find a selector to associate with.", reader); return; } string strUID = reader.ReadString(bracketIndex - reader.Position); int uid; if (!int.TryParse(strUID, out uid)) { Error("Uniform ID was not a number.", reader); return; } else if (uid < 0) { Error("Uniform ID's cannot be negative.", reader); return; } currentUniformID = uid; continue; } #endregion #region Repeaters if (c == '^') { // iteration range if (reader.PeekChar() != '[') { Error("Repeater iterations parameter did not have an opening bracket.", reader); return; } reader.ReadChar(); // skip [ int rightRangeBracketIndex = reader.Source.FindClosingSquareBracket(reader.Position); if (rightRangeBracketIndex < 0) { Error("Repeater iterations parameter did not have a closing bracket.", reader); return; } string strRangeParameter = reader.ReadString(rightRangeBracketIndex - reader.Position).Trim(); reader.ReadChar(); // skip ] int constantParam = 0; int min = 0; int max = 0; if (!int.TryParse(strRangeParameter, out constantParam)) { string[] parts = strRangeParameter.Split(new char[] { '-' }); if (parts.Length != 2) { Error("Repeater range parameter must be a pair of two numbers.", reader); return; } if (!int.TryParse(parts[0], out min) || !int.TryParse(parts[1], out max)) { Error("Repeater range parameter did not contain valid numbers.", reader); return; } if (min > max || min == 0 || max == 0) { Error("Repeater range must be greater than zero, and max > min.", reader); return; } constantParam = rand.Next(min, max); } // separator if (reader.ReadChar() != '[') { Error("Repeater separator parameter did not have an opening bracket.", reader); return; } int sepIndex = reader.Position; int rightSepBracketIndex = reader.Source.FindClosingSquareBracket(reader.Position); if (rightSepBracketIndex < 0) { Error("Repeater separator parameter did not have a closing bracket.", reader); } string strSepParameter = reader.ReadString(rightSepBracketIndex - reader.Position); int sepEnd = reader.Position; reader.ReadChar(); // skip ] // content if (reader.ReadChar() != '[') { Error("Repeater content parameter did not have an opening bracket.", reader); return; } int rightContentBracketIndex = reader.Source.FindClosingSquareBracket(reader.Position); if (rightSepBracketIndex < 0) { Error("Repeater content parameter did not have a closing bracket.", reader); } int pStart = reader.Position; reader.ReadString(rightContentBracketIndex - reader.Position); int pEnd = reader.Position; repeaters.Add(new RepeaterInstance(pStart, pEnd, sepIndex, sepEnd, strSepParameter, constantParam)); reader.Position = pStart; } else if (c == ']' && repeaters.Count > 0) // End of repeater iteration? { int last = repeaters.Count - 1; RepeaterInstance rep = repeaters[last]; if (reader.Position - 1 != rep.ContentEndIndex && reader.Position - 1 != rep.SeparatorEndIndex) { continue; } if (rep.OnSeparator) // Currently writing separator? { rep.OnSeparator = false; reader.Position = rep.ContentStartIndex; } else // Currently writing content? { if (repeaters[last].Elapse()) { repeaters.RemoveAt(last); // Remove the last repeater if it's finished continue; } else { rep.OnSeparator = true; reader.Position = rep.SeparatorStartIndex; // Add separator if not } } } #endregion #region Flags else if (c == '$') { int leftBracket = reader.Source.IndexOf("[", reader.Position); if (leftBracket < 0) { Error("Missing '[' on flag call.", reader); return; } string func = reader.ReadString(leftBracket - reader.Position).ToLower(); reader.ReadChar(); // skip [ if (func.Contains(' ')) { Error("Invalid flag function.", reader); return; } int rightBracket = reader.Source.FindClosingSquareBracket(reader.Position); if (rightBracket < leftBracket) { Error("Missing ']' on flag call.", reader); return; } string firstParam = reader.ReadString(rightBracket - reader.Position); reader.ReadChar(); // skip ] if (func == "set") { if (!vflags.Contains(firstParam)) { vflags.Add(firstParam); } continue; } else if (func == "unset") { if (vflags.Contains(firstParam)) { vflags.Remove(firstParam); } continue; } else if (func == "if") { if (reader.ReadChar() != '[') { Error("Missing '[' in IF body.", reader); return; } int rightBodyBracket = reader.Source.FindClosingSquareBracket(reader.Position); if (rightBodyBracket < 0) { Error("Missing ']' in IF body.", reader); return; } if (!vflags.Contains(firstParam)) { reader.Position = rightBodyBracket; } continue; } else if (func == "ifnot") { if (reader.ReadChar() != '[') { Error("Missing '[' in IF body.", reader); return; } int rightBodyBracket = reader.Source.FindClosingSquareBracket(reader.Position); if (rightBodyBracket < 0) { Error("Missing ']' in IF body.", reader); return; } if (vflags.Contains(firstParam)) { reader.Position = rightBodyBracket; } continue; } else if (func == "g_set") { if (!flags.Contains(firstParam)) { flags.Add(firstParam); } continue; } else if (func == "g_unset") { if (flags.Contains(firstParam)) { flags.Remove(firstParam); } continue; } else if (func == "g_if") { if (reader.ReadChar() != '[') { Error("Missing '[' in IF body.", reader); return; } int rightBodyBracket = reader.Source.IndexOf("]", reader.Position); if (rightBodyBracket < 0) { Error("Missing ']' in IF body.", reader); return; } if (!flags.Contains(firstParam)) { reader.Position = rightBodyBracket; } continue; } else if (func == "g_ifnot") { if (reader.ReadChar() != '[') { Error("Missing '[' in IF body.", reader); return; } int rightBodyBracket = reader.Source.IndexOf("]", reader.Position); if (rightBodyBracket < 0) { Error("Missing ']' in IF body.", reader); return; } if (flags.Contains(firstParam)) { reader.Position = rightBodyBracket; } continue; } else { Error("Unrecognized flag function.", reader); return; } } #endregion else if (c == '+') // Random word { string lockID = ""; char symbol = reader.ReadChar(); if (symbol == ' ' || symbol == '+' || symbol == '#' || symbol == '*' || symbol == '~' || symbol == '|') { Warning("Enountered illegal symbol: '" + symbol.ToString() + "'", reader); continue; } else if (symbol == '[') // Check if there is a class accessor. (For example: +[class]n) { int closure = reader.Source.IndexOf(']', reader.Position); if (closure < 0) { Error("Incomplete brackets in class accessor.", reader); return; } className = reader.ReadString(closure - reader.Position); reader.Position++; // Skip past ']' symbol = reader.ReadChar(); } if (reader.PeekChar() == '[') // Check if there is a subtype accessor. (For example: +n[subtype] or +[class]n[subtype]) { reader.Position++; int closure = reader.Source.IndexOf(']', reader.Position); if (closure < 0) { Error("Incomplete brackets in subtype accessor.", reader); return; } subType = reader.ReadString(closure - reader.Position); reader.Position++; // Skip past ']' } if (reader.PeekChar() == '<') // Check if there is a word lock accessor. (For example: +n<#> or +[class]n[subtype]<#>) { string lockKey = className + ":" + symbol.ToString(); if (!locks.ContainsKey(lockKey)) { locks.Add(lockKey, new Dictionary<string, int>()); } reader.Position++; int closure = reader.Source.IndexOf('>', reader.Position); if (closure < 0) { Error("Incomplete brackets in word lock accessor.", reader); return; } lockID = reader.ReadString(closure - reader.Position); if (lockID == "") { Error("Empty word lock ID.", reader); return; } if (!locks[lockKey].ContainsKey(lockID) && wordBank.ContainsKey(symbol)) // add a new word lock if a new ID is found --- this allows reuse of the word! { locks[lockKey].Add(lockID, wordBank[symbol].GetRandomIndex(rand, className)); } reader.Position++; // Skip past '>' } if (!wordBank.ContainsKey(symbol)) // Make sure the symbol is registered { Warning("Word symbol not found: '" + symbol.ToString() + "'", reader); } else if (lockID != "") { buffer = wordBank[symbol].GetWordByIndex(locks[className + ":" + symbol.ToString()][lockID], subType, currentFormat); } else { if (className.Contains(",")) { string[] mcNames = className.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (mcNames.Length < 2) { Error("A multi-class expression must include more than one class name in its parameters.", reader); return; } for (int i = 0; i < mcNames.Length; i++) { mcNames[i] = mcNames[i].Trim(); // this is to get rid of spaces between the class names } for (int i = 0; i < mcNames.Length; i++) { if (!ClassExists(symbol, mcNames[i])) { Error("Bad multiclass", reader); return; } } buffer = wordBank[symbol].GetRandomWordMultiClass(rand, subType, currentFormat, mcNames); } else if (!ClassExists(symbol, className)) { Warning("Class not found: " + symbol.ToString() + " -> " + className, reader); } else { int index = wordBank[symbol].GetRandomIndex(rand, className); buffer = wordBank[symbol].GetWordByIndex(index, subType, currentFormat); if (graph != null && symbol == 'n') { graph.Add(wordBank[symbol].GetWordByIndex(index, "", WordFormat.None)); } } } buffer = buffer.Capitalize(currentFormat); if (anIndex > -1 && buffer.StartsWithVowel()) { if (anFormat == WordFormat.AllCaps) { stream.Insert(anIndex, "N"); } else { stream.Insert(anIndex, "n"); } } anIndex = -1; anFormat = WordFormat.None; } else if (c == '|' || c == '\n') // Line break { buffer = "\r\n"; } else if (c == '~') // Capitalize { if (reader.PeekChar() == '~') { reader.ReadChar(); currentFormat = WordFormat.Capitalized; } else if (currentFormat == WordFormat.Proper) { currentFormat = WordFormat.None; } else { currentFormat = WordFormat.Proper; } } else if (c == '@') // Capslock { if (currentFormat == WordFormat.AllCaps) { currentFormat = WordFormat.None; } else { currentFormat = WordFormat.AllCaps; } } else if (c == '#') // Random number { if (reader.PeekChar() == '[') { reader.Position++; int closure = reader.Source.IndexOf(']', reader.Position); if (closure < 0) { Error("Incomplete parenthases in random number range.", reader); return; } string rangeStr = reader.ReadString(closure - reader.Position); reader.Position++; // Skip past ']' string[] rangeParts = rangeStr.Split('-'); if (rangeParts.Length != 2) { Error("Invalid number of range elements for random number. Got " + rangeParts.Length + ", need 2.", reader); return; } int min; int max; if (!int.TryParse(rangeParts[0], out min)) { Error("Invalid minimum value for random number.", reader); return; } if (!int.TryParse(rangeParts[1], out max)) { Error("Invalid maximum value for random number.", reader); return; } buffer = rand.Next(min, max).ToString(); } } else if (c != '{' && c != '}' && c != '[' && c != ']' && c != '<' && c != '>') // Covers all other characters except brackets { if (prev == ' ' && c == 'a' && !char.IsLetterOrDigit((char)reader.PeekChar())) // YES! YES! { anIndex = stream.Length + 1; anFormat = currentFormat; } if (currentFormat == WordFormat.AllCaps || (currentFormat == WordFormat.Proper && !Char.IsLetterOrDigit(prev) && prev.PermitsCap())) { buffer = c.ToString().ToUpper(); } else if (currentFormat == WordFormat.Capitalized) { buffer = c.ToString().ToUpper(); currentFormat = WordFormat.None; } else { buffer = c.ToString(); } } stream.Append(buffer); buffer = ""; // Fixes the word repitition bug when terminating Proper formatting in a pattern } }
private void ChangeWeights(LongRandom rand, int distSelect) { foreach (KeyValuePair<char, WordList> kvp in wordBank) { kvp.Value.RandomizeDistWeights(rand, distSelect); } }
public Story GenerateStoryObject(string seed, int chapterCount, int chapterLength, int weightDistSelect, int weightChangeOption) { flags.Clear(); graph = new Histograph(); LongRandom rngBase = new LongRandom(seed); rand = new LongRandom(seed); ChangeWeights(rand, weightDistSelect); AssignGlobals(rand); string title = GenerateFrom(patternBank["T"].GetPattern(rand)); string author = GenerateFrom(patternBank["B"].GetPattern(rand)); List<KeyValuePair<string, string>> chapters = new List<KeyValuePair<string, string>>(); for (int i = 0; i < chapterCount; i++) { rand = new LongRandom(rngBase.Next()); string chapterTitle = GenerateFrom(patternBank["C"].GetPattern(rand)); int paragraphs = rand.Next(3 + 4 * chapterLength, 8 + 4 * chapterLength); StringBuilder builder = new StringBuilder(); for (int j = 0; j < paragraphs; j++) { if (i == 0 && j == 0) { GenerateFromOutline(builder, oIntros); builder.AppendLine("\r\n"); } else if (i == chapterCount - 1 && j == paragraphs - 1) { GenerateFromOutline(builder, oEndings); } else { GenerateFromOutline(builder, oBodies); builder.AppendLine("\r\n"); } if (weightChangeOption == 2) { ChangeWeights(rand, weightDistSelect); } } if (weightChangeOption == 1) { ChangeWeights(rand, weightDistSelect); } chapters.Add(new KeyValuePair<string, string>(chapterTitle, builder.ToString())); } return new Story(title, author, seed, chapters, graph); }
public void GenerateStory(StringBuilder stream, string seed, int chapters, bool includeSeed, bool romanChapterNumbers, int chapterLengthSelect, int weightDistSelect, int weightChangeOption, ref string storyTitle) { flags.Clear(); // Check for required pattern types CheckPatternType("T"); // Story title CheckPatternType("B"); // Author full name CheckPatternType("C"); // Chapter name LongRandom rngBase = new LongRandom(seed); rand = new LongRandom(seed); ChangeWeights(rand, weightDistSelect); AssignGlobals(rand); if (storyTitle != null) { StringBuilder title = new StringBuilder(); GenerateFromPattern(title, patternBank["T"]); storyTitle = title.ToString(); stream.Append(title.ToString()); } else { GenerateFromPattern(stream, patternBank["T"]); } stream.Append("\r\nBy "); GenerateFromPattern(stream, patternBank["B"]); stream.AppendLine(); if (includeSeed) { stream.Append("(Seed: " + seed + ")"); stream.AppendLine(); } stream.AppendLine("---"); for (int i = 0; i < chapters; i++) { rand = new LongRandom(rngBase.Next()); string chapNum = romanChapterNumbers ? (i + 1).ToRoman() : (i + 1).ToString(); stream.Append("\r\n\r\nCHAPTER " + chapNum + ": "); // chapter number GenerateFromPattern(stream, patternBank["C"]); // chapter name stream.AppendLine("\r\n"); int paragraphs = rand.Next(3 + 4 * chapterLengthSelect, 8 + 4 * chapterLengthSelect); for (int j = 0; j < paragraphs; j++) { if (i == 0 && j == 0) { GenerateFromOutline(stream, oIntros); stream.AppendLine("\r\n"); } else if (i == chapters - 1 && j == paragraphs - 1) { GenerateFromOutline(stream, oEndings); } else { GenerateFromOutline(stream, oBodies); stream.AppendLine("\r\n"); } if (weightChangeOption == 2) { ChangeWeights(rand, weightDistSelect); } } if (weightChangeOption == 1) { ChangeWeights(rand, weightDistSelect); } } }
public void AssignGlobals(LongRandom rand) { foreach (KeyValuePair<string, string> entry in globalBank) { StringBuilder sb = new StringBuilder(); GenerateFromPattern(sb, entry.Value); globalValues[entry.Key] = sb.ToString(); } }
public string GetPattern(LongRandom r) { return this.Patterns[r.Next(0, this.Patterns.Length)]; }
public string GetRandomWordMultiClass(LongRandom rand, string subtype, WordFormat format, params string[] classNames) { int subIndex = LookForSubtype(subtype); if (subIndex == -1) { return Error("SubtypeNotFound->" + subtype); } for (int i = 0; i < classNames.Length; i++) { if (!this.Classes.ContainsKey(classNames[i])) { return Error("ClassNotFound->" + classNames[i]); } } List<int> mcList = GetMultiClassList(classNames); if (mcList.Count == 0) { return Error("EmptyMultiClass"); } int index = PickByWeight(mcList, rand); return Format(Words[mcList[index]][subIndex], format); }
private int PickByWeight(string className, LongRandom rand) { int total = TotalWeights(className); int randomNumber = rand.Next(0, total); int selectedIndex = 0; if (className == "") // This will go through all the words { for (int i = 0; i < this.Weights.Length; i++) { if (randomNumber < this.Weights[i] + this.DistWeights[i]) { selectedIndex = i; break; } randomNumber -= this.Weights[i] + this.DistWeights[i]; } } else { List<int> c = this.Classes[className]; int count = c.Count; for (int i = 0; i < count; i++) { if (randomNumber < this.Weights[c[i]] + this.DistWeights[c[i]]) { selectedIndex = i; break; } randomNumber -= this.Weights[c[i]] + this.DistWeights[c[i]]; } } return selectedIndex; }
private int PickByWeight(List<int> items, LongRandom rand) { int total = TotalWeights(items); int randomNumber = rand.Next(0, total); int selectedIndex = 0; int count = items.Count; for (int i = 0; i < count; i++) { if (randomNumber < this.Weights[items[i]] + this.DistWeights[items[i]]) { selectedIndex = i; break; } randomNumber -= this.Weights[items[i]] + this.DistWeights[items[i]]; } return selectedIndex; }
public void RandomizeDistWeights(LongRandom rand, int factor) { for (int i = 0; i < this.DistWeights.Length; i++) { if (rand.Next(0, factor * 3 + 1) == 0) { this.DistWeights[i] = rand.Next(1, 20) * factor; } else { this.DistWeights[i] = 0; } } }
// 300x450 public static Bitmap CreateCover(Story story, int resultTableLength, int itemCount) { try { var google = new GimageSearchClient(@"http://google.com"); LongRandom rand = new LongRandom(story.Seed); Image imgMain = new Bitmap(300, 450); List<string> items = story.Histograph.GetMostFrequent(itemCount); using (Graphics g = Graphics.FromImage(imgMain)) { Color bg = Color.FromArgb(rand.Next(0, 256), rand.Next(0, 256), rand.Next(0, 256)); g.Clear(bg); string typeFace = fontList[rand.Next(0, fontList.Length)]; StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; Font titleFont = new Font(typeFace, 24F, FontStyle.Regular); Font authorFont = new Font(typeFace, 14F, FontStyle.Regular); SizeF titleSize = g.MeasureString(story.Title, titleFont, 268); SizeF authorSize = g.MeasureString(story.Author, authorFont); SolidBrush titleBrush = new SolidBrush(bg.GetBrightness() > 0.5 ? Color.Black : Color.White); Rectangle titleBorder = new Rectangle(8, 8, 284, (int)titleSize.Height + 8); RectangleF authorRect = new RectangleF(0, 442 - authorSize.Height, 300, authorSize.Height); Rectangle pictureRect = new Rectangle(titleBorder.Left, titleBorder.Bottom + 8, titleBorder.Width, (int)authorRect.Top - titleBorder.Bottom - 16); g.DrawString(story.Title, titleFont, titleBrush, new RectangleF(16, 16, 268, titleSize.Height), sf); g.DrawRectangle(new Pen(titleBrush, 3), titleBorder); g.DrawString(story.Author, authorFont, titleBrush, authorRect, sf); // Draw illustration g.Clip = new Region(pictureRect); var bgResults = google.Search(story.Title, resultTableLength, SafeLevel.Off, ImageSize.Large, Colorization.All, ImageColor.All, ImageType.All, ImageFileType.All, ""); if (bgResults.Count > 0) { Bitmap background = (Bitmap)DownloadImageFromURL(bgResults[rand.Next(0, bgResults.Count)].Url, false); if (background != null) { g.DrawImage(background, pictureRect); background.Dispose(); } } else { g.Clear(Color.FromArgb(255, rand.Next(0, 256), rand.Next(0, 256), rand.Next(0, 256))); } foreach (string thing in items) { var imgResults = google.Search(thing, resultTableLength, SafeLevel.Off, ImageSize.All, Colorization.All, ImageColor.All, ImageType.All, ImageFileType.All, ""); Bitmap item = (Bitmap)DownloadImageFromURL(imgResults[rand.Next(0, imgResults.Count)].TbImage.Url, true); int x = rand.Next(0, pictureRect.Width) + pictureRect.Left; int y = rand.Next(0, pictureRect.Height) + pictureRect.Top; int width = rand.Next(32, pictureRect.Width); int height = rand.Next(32, pictureRect.Height); g.TranslateTransform(x, y); g.RotateTransform(rand.Next(0, 360)); g.ResetTransform(); g.DrawImage(item, new Rectangle(0, 0, width, height)); item.Dispose(); } g.DrawRectangle(new Pen(titleBrush, 3), pictureRect); } return (Bitmap)imgMain; } catch { return null; } }