XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEDToolBox.Core.Engineering;
using XFEEDToolBox.Core.Models;
namespace XFEEDToolBox.Core.Outfitting;

/// <summary>One material ledger per ship and one shared reputation state per engineer, in the configured slot order.</summary>
public static class ShipRefitPlanner
{
    public static ShipRefitResult Calculate(ShipRefitDocument document, EngineeringCatalog catalog, IReadOnlyList<EngineerAccess> engineers, IReadOnlyList<InventoryItem> stock, CancellationToken token = default)
    {
        var totals = new Dictionary<string,(string Name,int Min,int Max)>(); var rows = new List<RefitModuleResult>(); var notes = new List<string>(); var complete = true; var exact = true;
        var rules = EngineeringRules.Captured;
        foreach (var group in document.Slots.Where(s => s.Module is not null && s.Target is not null).GroupBy(s => s.Target!.EngineerId))
        {
            token.ThrowIfCancellationRequested();
            var access = engineers.FirstOrDefault(e => e.Id == group.Key) ?? throw new InvalidOperationException("未读取到所选工程师的当前权限。");
            if (!access.Unlocked || access.Rank is <1 or >5) throw new InvalidOperationException(access.Name + " 尚未解锁或缺少有效权限等级。");
            var lo = access.Rank == 5 ? 100 : access.ReputationMin ?? rules.Absolute(access.Rank, access.RankProgress ?? 0);
            var hi = access.Rank == 5 ? 100 : access.ReputationMax ?? (access.RankProgress is { } p ? rules.Absolute(access.Rank,p) : rules.ReputationThresholds[access.Rank+1] - 1e-7);
            var samples = new List<double> { lo };
            if (hi - lo > 1e-6) { exact = false; for (int n=(int)Math.Floor(lo*100)+1;n/100.0<hi;n++) samples.Add(n/100.0); samples.Add(hi); }
            var groupCounts = new List<Dictionary<string,(string Name,int Count)>>(); var sequence = group.ToArray();
            foreach (var start in samples)
            {
                token.ThrowIfCancellationRequested();
                var rep = start; var counts = new Dictionary<string,(string Name,int Count)>();
                foreach (var slot in sequence)
                {
                    var t = slot.Target!; var type = EngineeringCatalog.ModuleType(slot.Module!.Item);
                    var effect=EngineeringExperimental.Find(catalog,type,t.Experimental);
                    var current = access with { Rank=rules.Rank(rep),ReputationMin=rep,ReputationMax=rep,RankProgress=rules.WithinRank(rep) };
                    EngineeringPlan result;
                    try { result=EngineeringPlanner.Calculate(catalog,slot.Module,t.Blueprint,t.Grade,t.Quality,effect,current,[],t.Remote,t.FastAdvance,t.Experimental,token); }
                    catch (Exception e) when(e is ArgumentException or InvalidOperationException) { throw new InvalidOperationException(slot.Slot+":"+e.Message,e); }
                    rep=result.FinalReputation??rep; complete &= result.Complete;
                    foreach(var m in result.Materials) { var before=counts.GetValueOrDefault(m.Key); counts[m.Key]=(m.Name,before.Count+m.Required); }
                    if(start==lo) rows.Add(new(slot.Slot,slot.Module.Name,result.Rolls.Count,result.FinalRank,result.Complete?"可完成":"需要额外提升权限"));
                }
                groupCounts.Add(counts);
            }
            foreach(var key in groupCounts.SelectMany(g=>g.Keys).Distinct())
            {
                var values=groupCounts.Select(c=>c.GetValueOrDefault(key)).ToArray(); var before=totals.GetValueOrDefault(key);
                totals[key]=(values.First(v=>v.Name is not null).Name,before.Min+values.Min(v=>v.Count),before.Max+values.Max(v=>v.Count));
            }
            notes.Add($"{access.Name}:按当前列表顺序处理 {sequence.Length} 个模块,同组共享声望;起始声望 {(hi-lo<1e-6?lo.ToString("F2"):$"{lo:F2}–{hi:F2}")} 点。");
        }
        var needs=totals.Select(p=>new MaterialNeed(p.Key,p.Value.Name,p.Value.Max,stock.Where(m=>m.Key==p.Key).Sum(m=>m.Count),p.Value.Min)).OrderByDescending(m=>m.Missing).ThenBy(m=>m.Name).ToArray();
        var ordered=rows.OrderBy(r=>Array.FindIndex(document.Slots.ToArray(),s=>s.Slot==r.Slot)).ToArray();
        var purchasing=document.Slots.Count(s=>s.Module is not null && s.Origin=="计划购入");
        if(purchasing>0)notes.Add($"包含 {purchasing} 个计划购入模块;材料统计不包含模块购买/转运的信用点成本。");
        if(document.Slots.Any(s=>s.Category=="standard" && s.Module is null)) notes.Add("模拟配置缺少核心模块,不能据此认定飞船可出航。");
        notes.Add("按槽型、尺寸和已知舰船限制筛选;总供电、质量、推进器质量区间及特殊模块数量限制尚未作完整性能校核。");
        if(!complete)notes.Add("部分目标需要额外提升权限,当前材料总表只包含已经计算出的步骤。");
        return new(needs,ordered,notes,complete,exact);
    }
}