Skip to content

Commit

Permalink
Merge pull request #8 from approvers/feature/rinia/reply/002_shuffle
Browse files Browse the repository at this point in the history
Common: 毎日0時に各種確率が変わるように
  • Loading branch information
2RiniaR authored Jan 18, 2024
2 parents 2286328 + 0890ef5 commit b25ef26
Show file tree
Hide file tree
Showing 18 changed files with 301 additions and 126 deletions.
3 changes: 2 additions & 1 deletion Common/DiscordManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ public static class DiscordManager
public static async Task InitializeAsync()
{
Client.Log += OnLog;
await Client.LoginAsync(TokenType.Bot, SettingManager.Get("DISCORD_SECRET"));
await Client.LoginAsync(TokenType.Bot, SettingManager.DiscordSecret);
await Client.StartAsync();
await EventUtility.WaitAsync(h => Client.Ready += h, h => Client.Ready -= h);
}

private static Task OnLog(LogMessage content)
Expand Down
33 changes: 33 additions & 0 deletions Common/EventUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace Approvers.King.Common;

public static class EventUtility
{
public static Task WaitAsync(Action<Func<Task>> register, Action<Func<Task>> unregister,
CancellationToken ct = default)
{
var tcs = new TaskCompletionSource();
Func<Task>? h = null;
h = () =>
{
unregister(h!);
tcs.SetResult();
return Task.CompletedTask;
};
register(h);
ct.Register(() =>
{
unregister(h);
tcs.SetCanceled();
});

try
{
return tcs.Task;
}
catch
{
unregister(h);
throw;
}
}
}
76 changes: 76 additions & 0 deletions Common/GachaManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
namespace Approvers.King.Common;

public class GachaManager
{
private readonly List<ReplyMessage> _replyMessageTable = new();

public static GachaManager Instance { get; } = new();

/// <summary>
/// 現在のメッセージに反応する確率
/// </summary>
public float RareReplyRate { get; private set; }

/// <summary>
/// 各メッセージの確率
/// </summary>
public IReadOnlyList<ReplyMessage> ReplyMessageTable => _replyMessageTable;

public void Initialize()
{
_replyMessageTable.Clear();
_replyMessageTable.AddRange(MasterManager.ReplyMessages.Select(x => new ReplyMessage
{
Rate = 1f,
Message = x,
}));
}

public string? TryPickRareReplyMessage()
{
if (RandomUtility.IsHit(RareReplyRate) == false) return null;
return PickMessage();
}

public string PickMessage()
{
var totalRate = _replyMessageTable.Sum(x => x.Rate);
var value = RandomUtility.GetRandomFloat(totalRate);

foreach (var element in _replyMessageTable)
{
if (value < element.Rate) return element.Message;
value -= element.Rate;
}

return _replyMessageTable[^1].Message;
}

public void ShuffleRareReplyRate()
{
RareReplyRate = MasterManager.RareReplyRateTable.PickRandom();
}

public void ShuffleMessageRates()
{
var borders = Enumerable.Range(0, _replyMessageTable.Count - 1)
.Select(x => (float)Math.Pow(RandomUtility.GetRandomFloat(1f), 2))
.Select(x => (int)Math.Floor(x * 100f))
.OrderBy(x => x)
.ToList();
borders.Add(100);
var randomIndices = Enumerable.Range(0, _replyMessageTable.Count).Shuffle().ToList();

_replyMessageTable[randomIndices[0]].Rate = borders[0] * 0.01f;
for (var i = 1; i < _replyMessageTable.Count; i++)
{
_replyMessageTable[randomIndices[i]].Rate = (borders[i] - borders[i - 1]) * 0.01f;
}
}

public class ReplyMessage
{
public float Rate { get; set; }
public string Message { get; init; } = string.Empty;
}
}
48 changes: 14 additions & 34 deletions Common/MasterManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,39 @@

public static class MasterManager
{
public static float ReplyRate => 0.05f;
public static IReadOnlyList<float> RareReplyRateTable => new List<float>
{
0.01f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f, 0.07f, 0.08f, 0.09f, 0.10f,
};

public static float ReplyMaxDelay => 2f;
public static float TypingMaxDelay => 1f;

public static IReadOnlyList<(float rate, string message)> ReplyMessages => new List<(float rate, string message)>
public static IReadOnlyList<string> ReplyMessages => new List<string>
{
(1f, "あほしね"),
(1f, "ばか"),
(1f, "かす"),
(1f, "わかる"),
(1f, "草"),
(1f, "あほくさ"),
(1f, "noob"),
(1f, "それね、ちょっと分かる"),
"あほしね", "ばか", "かす", "わかる", "草", "あほくさ", "noob", "それね、ちょっと分かる",
};

public static string SilentCommandReplyMessage => "(いっそうの気配が{0}から消え去った)";

public static IReadOnlyList<string> SilentTriggerMessages => new List<string>
{
"だまれ",
"黙れ",
"だまって",
"黙って",
"だまろう",
"黙ろう",
"damare",
"しゃべるな",
"喋るな",
"しゃべんな",
"喋んな",
"帰れ",
"かえれ",
"帰って",
"かえって",
"帰ろう",
"かえろう",
"kaere",
"だまれ", "黙れ", "だまって", "黙って", "だまろう", "黙ろう", "damare",
"しゃべるな", "喋るな", "しゃべんな", "喋んな",
"帰れ", "かえれ", "帰って", "かえって", "帰ろう", "かえろう", "kaere",
};

public static TimeSpan SilentTimeSpan => TimeSpan.FromMinutes(5);

public static IReadOnlyList<string> GachaTriggerMessages => new List<string>
{
"10連",
"ガチャ",
"おみくじ",
"10連", "ガチャ", "おみくじ",
};

public static IReadOnlyList<string> RidiculeMessages => new List<string>
{
"雑魚",
"雑魚じゃん",
"雑魚すぎ",
"雑魚", "雑魚じゃん", "雑魚すぎ",
};

public static TimeSpan DailyResetTime => TimeSpan.FromHours(0);
}
22 changes: 9 additions & 13 deletions Common/PresenterBase.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Discord;
using Discord.WebSocket;
using System.Text;
using Discord;

namespace Approvers.King.Common;

Expand Down Expand Up @@ -32,21 +32,17 @@ public static Embed ErrorEmbed(string message)

public static class Format
{
private static readonly string[] SanitizeTarget = { "\\", "*", "_", "~", "`", ".", ":", "/", ">", "|", "#" };

public static string Sanitize(string text)
public static string Table(IEnumerable<(string key, string value)> records)
{
foreach (var target in SanitizeTarget)
var recordList = records.ToList();
var maxLength = recordList.Max(r => r.key.Length);
var sb = new StringBuilder();
foreach (var (key, value) in recordList)
{
text = text.Replace(target, "\\" + target);
sb.AppendLine($"| {value.PadLeft(maxLength)} | {Discord.Format.Sanitize(key)}");
}

return text;
}

public static string UserName(IUser user)
{
return Sanitize((user as SocketGuildUser)?.Nickname ?? user.Username);
return Discord.Format.Code(sb.ToString());
}
}
}
15 changes: 15 additions & 0 deletions Common/RandomUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ public static float GetRandomFloat(float min, float max)
return (float)(min + (max - min) * Random.NextDouble());
}

public static int GetRandomInt(int max)
{
return GetRandomInt(0, max);
}

public static int GetRandomInt(int min, int max)
{
return Random.Next(min, max);
}

public static bool IsHit(float probability)
{
return GetRandomFloat(1f) <= probability;
Expand All @@ -24,4 +34,9 @@ public static T PickRandom<T>(this IEnumerable<T> source)
var array = source.ToArray();
return array[Random.Next(array.Length)];
}

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list)
{
return list.OrderBy(_ => Guid.NewGuid());
}
}
5 changes: 5 additions & 0 deletions Common/Scheduler/SchedulerJobPresenterBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Approvers.King.Common;

public abstract class SchedulerJobPresenterBase : PresenterBase
{
}
15 changes: 15 additions & 0 deletions Common/Scheduler/SchedulerJobRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Approvers.King.Common;

public abstract class SchedulerJobRunner
{
public Func<DateTime, bool>? Predicate { get; init; }
public abstract void Run();
}

public class SchedulerJobRunner<T> : SchedulerJobRunner where T : SchedulerJobPresenterBase, new()
{
public override void Run()
{
new T().RunAsync().Run();
}
}
35 changes: 35 additions & 0 deletions Common/Scheduler/SchedulerManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Timers;
using Timer = System.Timers.Timer;

namespace Approvers.King.Common;

public static class SchedulerManager
{
private static readonly Timer Timer = new(TimeSpan.FromSeconds(1));
private static readonly List<SchedulerJobRunner> Runners = new();

public static void Initialize()
{
Timer.Elapsed += OnEverySecond;
Timer.Start();
}

private static void OnEverySecond(object? sender, ElapsedEventArgs e)
{
var now = TimeManager.GetNow();
foreach (var runner in Runners)
{
if (runner.Predicate != null && runner.Predicate(now)) runner.Run();
}
}

public static void RegisterDaily<T>(TimeSpan time) where T : SchedulerJobPresenterBase, new()
{
Runners.Add(new SchedulerJobRunner<T>
{
Predicate = dateTime => dateTime.Hour == time.Hours &&
dateTime.Minute == time.Minutes &&
dateTime.Second == time.Seconds,
});
}
}
6 changes: 5 additions & 1 deletion Common/SettingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ public class SettingManager
.AddUserSecrets<SettingManager>(true)
.Build();

public static string Get(string name)
public static string DiscordSecret => Get("DiscordSecret");
public static ulong DiscordTargetGuildId => ulong.Parse(Get("DiscordTargetGuildId"));
public static ulong DiscordMainChannelId => ulong.Parse(Get("DiscordMainChannelId"));

private static string Get(string name)
{
return Configuration[name] ??
throw new Exception($"Environment variable {name} is not set.");
Expand Down
8 changes: 8 additions & 0 deletions Common/TaskExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Approvers.King.Common;

public static class TaskExtensions
{
public static void Run(this Task source)
{
}
}
10 changes: 3 additions & 7 deletions Events/GachaCommandPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ public class GachaCommandPresenter : DiscordMessagePresenterBase

protected override async Task MainAsync()
{
var results = Enumerable.Range(0, PickCount).Select(_ => Pick()).ToList();
var results = Enumerable.Range(0, PickCount)
.Select(_ => GachaManager.Instance.TryPickRareReplyMessage())
.ToList();

var builder = new StringBuilder();
builder.AppendLine($"↓↓↓ いっそう{PickCount}連おみくじ ↓↓↓");
Expand All @@ -28,10 +30,4 @@ protected override async Task MainAsync()

await Message.ReplyAsync(builder.ToString());
}

private static string? Pick()
{
if (RandomUtility.IsHit(MasterManager.ReplyRate) == false) return null;
return MessageUtility.PickRandomMessage();
}
}
36 changes: 36 additions & 0 deletions Events/GachaRateUpdatePresenter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Approvers.King.Common;
using Discord;

namespace Approvers.King.Events;

public class GachaRateUpdatePresenter : SchedulerJobPresenterBase
{
private static readonly string IssoSmileStamp = "<:isso_smile:1081501060369236069>";

protected override async Task MainAsync()
{
// 排出確率を変える
GachaManager.Instance.ShuffleRareReplyRate();
GachaManager.Instance.ShuffleMessageRates();

// 名前を更新する
var guild = DiscordManager.Client.GetGuild(SettingManager.DiscordTargetGuildId);

await guild.CurrentUser.ModifyAsync(x =>
x.Nickname = $"{GachaManager.Instance.RareReplyRate:P0}の確率でわかってくれる創造主");

// 排出率を投稿する
var records = GachaManager.Instance.ReplyMessageTable
.OrderByDescending(x => x.Rate)
.Select(x => (x.Message, x.Rate.ToString("P0")));
var embed = new EmbedBuilder()
.WithTitle(
$"{IssoSmileStamp}{IssoSmileStamp}{IssoSmileStamp} 本日のいっそう {IssoSmileStamp}{IssoSmileStamp}{IssoSmileStamp}")
.WithColor(new Color(0xf1, 0xc4, 0x0f))
.WithDescription($"本日は {Discord.Format.Bold($"{GachaManager.Instance.RareReplyRate:P0}")} の確率で反応します")
.AddField("排出確率", Format.Table(records));

await guild.GetTextChannel(SettingManager.DiscordMainChannelId)
.SendMessageAsync(embed: embed.Build());
}
}
Loading

0 comments on commit b25ef26

Please sign in to comment.