Skip to content

Commit

Permalink
Common: 倍率を表す構造体を追加 (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
2RiniaR authored Dec 1, 2024
1 parent 6a3f9ad commit 21d908a
Show file tree
Hide file tree
Showing 25 changed files with 639 additions and 341 deletions.
10 changes: 10 additions & 0 deletions Common/Master/SettingMaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,15 @@ private int GetInt(string key)
/// </summary>
public int MaxRareReplyProbabilityPermillage => GetInt(nameof(MaxRareReplyProbabilityPermillage));

public Multiplier MaxRareReplyProbability => Multiplier.FromPermillage(MaxRareReplyProbabilityPermillage);

/// <summary>
/// 確率返信の抽選単位(千分率)
/// </summary>
public int RareReplyProbabilityStepPermillage => GetInt(nameof(RareReplyProbabilityStepPermillage));

public Multiplier RareReplyProbabilityStep => Multiplier.FromPermillage(RareReplyProbabilityStepPermillage);

/// <summary>
/// 単発ガチャ1回の価格
/// </summary>
Expand Down Expand Up @@ -120,15 +124,21 @@ private int GetInt(string key)
/// </summary>
public int SlotMaxConditionOffsetPermillage => GetInt(nameof(SlotMaxConditionOffsetPermillage));

public Multiplier SlotMaxConditionOffset => Multiplier.FromPermillage(SlotMaxConditionOffsetPermillage);

/// <summary>
/// スロットの調子の最小値(千分率)
/// </summary>
public int SlotMinConditionOffsetPermillage => GetInt(nameof(SlotMinConditionOffsetPermillage));

public Multiplier SlotMinConditionOffset => Multiplier.FromPermillage(SlotMinConditionOffsetPermillage);

/// <summary>
/// スロットの次に同じ出目が確定する確率の最大値(千分率)
/// </summary>
public int SlotRepeatPermillageUpperBound => GetInt(nameof(SlotRepeatPermillageUpperBound));

public Multiplier SlotRepeatUpperBound => Multiplier.FromPermillage(SlotRepeatPermillageUpperBound);
}

[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
Expand Down
4 changes: 4 additions & 0 deletions Common/Master/SlotItemMaster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ public class SlotItem : MasterRecord<string>
[field: MasterIntValue("return_rate_permillage")]
public int ReturnRatePermillage { get; }

public Multiplier ReturnRate => Multiplier.FromPermillage(ReturnRatePermillage);

/// <summary>
/// 次に同じ出目が確定する確率(千分率)
/// </summary>
[field: MasterIntValue("repeat_permillage")]
public int RepeatPermillage { get; }

public Multiplier RepeatProbability => Multiplier.FromPermillage(RepeatPermillage);
}
19 changes: 16 additions & 3 deletions Common/Models/AppService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace Approvers.King.Common;
/// </summary>
public class AppService : DbContext
{
public DbSet<AppState> AppStates { get; set; }
public DbSet<Slot> Slots { get; set; }
public DbSet<Gacha> Gachas { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<GachaProbability> GachaProbabilities { get; set; }
public DbSet<GachaItem> GachaItems { get; set; }

/// <summary>
/// セッションを作成する
Expand Down Expand Up @@ -41,7 +41,7 @@ public async Task<User> FindOrCreateUserAsync(ulong discordId)
Add(user);
return user;
}

public async Task<Slot> GetDefaultSlotAsync()
{
var slot = await Slots.FirstOrDefaultAsync();
Expand All @@ -54,4 +54,17 @@ public async Task<Slot> GetDefaultSlotAsync()
Add(slot);
return slot;
}

public async Task<Gacha> GetDefaultGachaAsync()
{
var gacha = await Gachas.Include(x => x.GachaItems).FirstOrDefaultAsync();
if (gacha != null)
{
return gacha;
}

gacha = new Gacha { Id = Guid.NewGuid() };
Add(gacha);
return gacha;
}
}
61 changes: 0 additions & 61 deletions Common/Models/AppState.cs

This file was deleted.

112 changes: 112 additions & 0 deletions Common/Models/Gacha.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Approvers.King.Common;

public class Gacha
{
[Key] public Guid Id { get; set; }

public int HitProbabilityPermillage { get; set; }

/// <summary>
/// 現在のメッセージに反応する確率
/// </summary>
[NotMapped]
public Multiplier HitProbability
{
get => Multiplier.FromPermillage(HitProbabilityPermillage);
set => HitProbabilityPermillage = value.Permillage;
}

/// <summary>
/// 各メッセージの確率
/// </summary>
public List<GachaItem> GachaItems { get; set; } = [];

/// <summary>
/// 単発ガチャを回す
/// </summary>
public GachaItem? RollOnce()
{
if (RandomManager.IsHit(HitProbability) == false)
{
return null;
}

return GetRandomResult();
}

/// <summary>
/// 確定ガチャを回す
/// </summary>
public GachaItem RollOnceCertain()
{
return GetRandomResult();
}

private GachaItem GetRandomResult()
{
var total = GachaItems.Sum(x => x.Probability.Permillage);
if (total <= 0)
{
return GachaItems.First();
}

var value = RandomManager.GetRandomInt(total);

foreach (var element in GachaItems)
{
if (value < element.Probability.Permillage) return element;
value -= element.Probability.Permillage;
}

return GachaItems.Last();
}

/// <summary>
/// メッセージに反応する確率を再抽選する
/// </summary>
public void ShuffleRareReplyRate()
{
// 確率は step の単位で max まで変動(ただし0にはならない)
var step = MasterManager.SettingMaster.RareReplyProbabilityStep;
var max = MasterManager.SettingMaster.MaxRareReplyProbability;
var rates = Enumerable.Range(0, max.Permillage / step.Permillage).Select(i => step * (i + 1));
HitProbability = RandomManager.PickRandom(rates);
}

/// <summary>
/// 各メッセージの確率を再抽選する
/// </summary>
public void ShuffleMessageRates()
{
var items = MasterManager.RandomMessageMaster
.GetAll(x => x.Type == RandomMessageType.GeneralReply)
.Select(randomMessage => GachaItems.FirstOrDefault(item => item.RandomMessageId == randomMessage.Id) ?? new GachaItem()
{
GachaId = Id,
RandomMessageId = randomMessage.Id,
Probability = Multiplier.Zero
})
.ToList();

// いい感じに確率がばらけるように、カイ二乗分布を適用
var borders = Enumerable.Range(0, items.Count - 1)
.Select(_ => (float)Math.Pow(RandomManager.GetRandomFloat(1f), 2))
.Select(Multiplier.FromRate)
.OrderBy(x => x)
.ToList();
borders.Add(Multiplier.One);
var randomIndices = RandomManager.Shuffle(Enumerable.Range(0, items.Count)).ToList();

items[randomIndices[0]].Probability = borders[0];
for (var i = 1; i < items.Count; i++)
{
items[randomIndices[i]].Probability = borders[i] - borders[i - 1];
}

GachaItems.Clear();
GachaItems.AddRange(items);
}
}
27 changes: 27 additions & 0 deletions Common/Models/GachaItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace Approvers.King.Common;

[PrimaryKey(nameof(GachaId), nameof(RandomMessageId))]
public class GachaItem
{
public Guid GachaId { get; set; }
public Gacha Gacha { get; set; } = null!;
public string RandomMessageId { get; set; } = null!;

public int ProbabilityPermillage { get; set; }

[NotMapped]
public Multiplier Probability
{
get => Multiplier.FromPermillage(ProbabilityPermillage);
set => ProbabilityPermillage = value.Permillage;
}

private RandomMessage? _randomMessage;

public RandomMessage? RandomMessage => _randomMessage == null || _randomMessage.Id != RandomMessageId
? _randomMessage = MasterManager.RandomMessageMaster.Find(RandomMessageId)
: _randomMessage;
}
Loading

0 comments on commit 21d908a

Please sign in to comment.