From 6d1d6ae750e94264f43239e82d2874e64bf5106f Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:28:33 -0600 Subject: [PATCH 1/3] Create FuzzTable.cs A fuzz string is a string with alternative choices to pick randomly. "A (ball|block)." becomes "A ball." or "A block." A fuzz table is a list of alternate choices, which may be loaded from a file, and each line can optionally be treated as a fuzz string. Useful for humanizing text without too much complexity or overhead. --- DiscordBot/Data/FuzzTable.cs | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 DiscordBot/Data/FuzzTable.cs diff --git a/DiscordBot/Data/FuzzTable.cs b/DiscordBot/Data/FuzzTable.cs new file mode 100644 index 00000000..f565e5fd --- /dev/null +++ b/DiscordBot/Data/FuzzTable.cs @@ -0,0 +1,61 @@ +// FuzzTable.cs +// +using System; +using System.Text.RegularExpressions; + +public class FuzzTable +{ + private static Random random = new(); + private static Regex parenContents = null; + private static TimeSpan timeout = new(10*10000/*x10nanoseconds*/); + + //TODO: an instance keeps an array of alternates and an MRU list + + // Evaluate a single fuzz string. + // "(He|She|They) (picked|selected) a (green|red|blue) (ball|block)." + // "She picked a red ball." + // Replace any parenthetical phrase with one of its choices at random. + // Allows for nesting of choices. There's currently no way to escape + // parentheses or vertical bars so strings must not include strays. + // Returns one permutation from all choice alternatives given. + // Does not remember what choices were given. + // + public static string Evaluate(string fuzz) + { + if (string.IsNullOrEmpty(fuzz)) + return ""; + if (parenContents == null) + parenContents = + new(@"\( ( [^(]*? ) \)", + RegexOptions.IgnorePatternWhitespace | + RegexOptions.Compiled, + timeout); + string before = null; + while (fuzz != before) + { + before = fuzz; + try + { + fuzz = parenContents.Replace(fuzz, + (m) => PickAlternate(m.Groups[1].ToString())); + } + catch (RegexMatchTimeoutException) + { + break; + } + } + return fuzz; + } + + private static string PickAlternate(string fuzz) + { + if (string.IsNullOrEmpty(fuzz)) + return ""; + string[] alternates = fuzz.Split('|'); + if (alternates == null || alternates.Length == 0) + return ""; + int pick = random.Next(0, alternates.Length); + return alternates[pick]; + } + +} From 13f29b3ea06445b963c094759d9ba863b146fd96 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:33:47 -0600 Subject: [PATCH 2/3] Update FuzzTable.cs --- DiscordBot/Data/FuzzTable.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiscordBot/Data/FuzzTable.cs b/DiscordBot/Data/FuzzTable.cs index f565e5fd..92b19024 100644 --- a/DiscordBot/Data/FuzzTable.cs +++ b/DiscordBot/Data/FuzzTable.cs @@ -3,6 +3,8 @@ using System; using System.Text.RegularExpressions; +namespace DiscordBot.Data; + public class FuzzTable { private static Random random = new(); From 8ed3bfdfe27da7f753433d735f3d53cb591ed193 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:44:10 -0600 Subject: [PATCH 3/3] Update UserService.cs Use a fuzz string in the recent Miku topic detector as a test. --- DiscordBot/Services/UserService.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Services/UserService.cs b/DiscordBot/Services/UserService.cs index 6fc7bbba..8ebf570e 100644 --- a/DiscordBot/Services/UserService.cs +++ b/DiscordBot/Services/UserService.cs @@ -7,6 +7,7 @@ using DiscordBot.Domain; using DiscordBot.Settings; using DiscordBot.Skin; +using DiscordBot.Data; using ImageMagick; using Newtonsoft.Json; @@ -115,11 +116,14 @@ Init thanks Init Miku Gag feature has no external settings, hardcoded userid refers to Reenaki/Kiki. */ - _mikuMentioned = DateTime.Now; _mikuCooldownTime = new TimeSpan(0, 39, 0); // 39min //_mikuCooldownTime = new TimeSpan(0, 0, 39); // test 39sec + _mikuMentioned = DateTime.Now - _mikuCooldownTime; _mikuRegex = @"(?i)\b(miku|hatsune|初音ミク|初音|ミク)\b"; - _mikuReply = ":three: :nine: Oi, mite, mite, <@358915848515354626> -chan!"; + _mikuReply = + "(:three: :nine:|:microphone:|:notes:|:musical_note:|:musical_keyboard:|:mirror_ball:) " + + "(Oi, mite, mite,|Heya,|Hey, look,|Did someone mention Miku?) " + + "<@358915848515354626> (-chan|)!"; //_mikuReply = "Oi, mite, mite, <@427306565184389132> ! :three: :nine:"; // test /* @@ -541,7 +545,8 @@ public async Task MikuCheck(SocketMessage messageParam) return; _mikuMentioned = now; - await messageParam.Channel.SendMessageAsync(_mikuReply); + var reply = FuzzTable.Evaluate(_mikuReply); + await messageParam.Channel.SendMessageAsync(reply); } public async Task CodeCheck(SocketMessage messageParam)