private void CreateGearModel() { foreach (var grp in GearChoices.GroupBy(g => g.EquipSlotCategory)) { // if gear is unique, equip it once only. grp.Where(e => e.IsUnique) .ForEach( e => Model.AddConstraint(Expression.Sum(grp.Key.PossibleSlots.Select(s => gear[s, e])) <= 1, $"ensure gear uniqueness for {e}")); // SIMPLIFICATION: we ignore blocked slots foreach (var s in grp.Key.PossibleSlots) { // choose at most one gear per slot Model.AddConstraint(Expression.Sum(grp.Select(e => gear[s, e])) <= 1, $"choose at most one item for slot {s}"); foreach (var e in grp) { var gv = gear[s, e]; // ASSUMPTION: all gear choices have fixed parameters e.AllParameters.Where(p => RelevantStats.Contains(p.BaseParam)) .ForEach( p => AddExprToDict(StatExprs, p.BaseParam, p.Values.Sum(v => ((ParameterValueFixed)v).Amount) * gv)); // ASSUMPTION: all meldable items have at least one materia slot // ASSUMPTION: customisable relics are unmeldable if (e.FreeMateriaSlots > 0) { CreateMateriaModel(s, e); } else if (RelicCaps != null && RelicCaps.ContainsKey(e)) { CreateRelicModel(s, e); } } } } }
private void CreateGearModel() { foreach (var grp in GearChoices.GroupBy(g => g.EquipSlotCategory)) { // if gear is unique, equip it once only. if (grp.Key.PossibleSlots.Count() > 1) { grp.Where(e => e.IsUnique) .ForEach( e => Model.AddConstraint(Expression.Sum(grp.Key.PossibleSlots.Select(s => gear[s, e])) <= 1, $"ensure gear uniqueness for {e}")); } // SIMPLIFICATION: we ignore blocked slots foreach (var s in grp.Key.PossibleSlots) { // choose at most one gear per slot Model.AddConstraint(Expression.Sum(grp.Select(e => gear[s, e])) <= 1, $"choose at most one item for slot {s}"); foreach (var e in grp) { var gv = gear[s, e]; // ASSUMPTION: all gear choices have fixed parameters var stats = e.AllParameters.Where(p => RelevantStats.Contains(p.BaseParam)) .ToDictionary(p => p.BaseParam, p => p.Values.OfType <ParameterValueFixed>().Select(val => val.Amount).Sum()); if (SolverConfig.EquipmentOverrides?.ContainsKey(e) ?? false) { var statsOverride = SolverConfig.EquipmentOverrides[e]; if (statsOverride == null) { continue; } foreach (var kv in statsOverride) { stats[kv.Key] = kv.Value; } } // sanity check stats foreach (var kv in stats) { if (e.GetMaximumParamValue(kv.Key) < kv.Value) { Console.Error.WriteLine($"{kv.Key} => {kv.Value} for {e} is out of range"); } } stats.ForEach(p => StatExprs.AddExprToDict(p.Key, p.Value * gv)); // ASSUMPTION: all meldable items have at least one materia slot // ASSUMPTION: customisable relics are unmeldable if (e.FreeMateriaSlots > 0) { CreateMateriaModel(s, e); } else { CreateRelicModel(s, e); } } } } }