-1

I've got a problem with my item factory class for a little game I am trying to code at the moment. What I am doing at the moment is the following:

  • I've got a List containing all my possible game items of type x (armor, weapon, ...) with base class type Item
  • Each item has a rarity from the rarity enum (0 = common, 1 = uncommen, and so on)
  • The actual rarity "spawn" percentage is saved in a dictionary containing the rarity and the percentage
  • Currently I have a generic method returning new instances of random items:
public IEnumerable<T> GetRandomItem<T>(int count = 1, Rarity maxRarity = Rarity.Common, List<int> ids = null)
  where T : Item
{
  InitializeActualRarities(maxRarity);
  return GetItems<T>().ToList().Where(i => CheckItemConditions(ref i, maxRarity, ids)).Clone().PickRandom(count);
}
  • The item(s) returned by the GetRandomItem Method is(are) always a copy of (a) randomly picked object(s) from the item list.

  • The InitializeActualRarities method generates percentages for all rarities below max rarity:

    private void InitializeActualRarities(Rarity maxRarity)
    {
      _actualRarityPercentages.Clear();

      var remaining = 100;
      Enum.GetValues(typeof(Rarity)).OfType<Rarity>().Where(r => _staticRarityPercentages[r] >= _staticRarityPercentages[maxRarity]).ToList().ForEach(r =>
      {
        remaining -= _staticRarityPercentages[r];
        _actualRarityPercentages.Add(r, _staticRarityPercentages[r]);
      });

      var key = _actualRarityPercentages.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
      _actualRarityPercentages[key] += remaining;
    }

At the moment I am obviously not using the actual rarity percentage in my GetRandomItem Method, and that is just what I want to change.

I want adjust the linq in a way to ensure only items to the given max rarity are returned with the rarity percentages from the _actualRarityPercentages dictionary.

Has anybody an idea or some advice on how to solve that kind of task in my coding manner?

Thank you in advance!

epanalepsis
  • 853
  • 1
  • 9
  • 26

2 Answers2

1

Something like this might work:

// Assuming this is the type
Dictionary<Rarity, int> _actualRarityPercentages;

public IEnumerable<T> GetRandomItem<T>(int count = 1, Rarity maxRarity = Rarity.Common, List<int> ids = null)
  where T : Item
{
  InitializeActualRarities(maxRarity);

  int maxRarityValue = _actualRarityPercentages[maxRarity];

  return GetItems<T>().ToList()
        .Where(item => _actualRarityPercentages[item.Rarity] <= maxRarityValue)
        .Clone()
        .PickRandom(count)
}

I've assumed that _actualRarityPercentages is a straightforward dictionary from Rarity to int. Using LINQ Where you should be able to filter the items that are more rare than maxRarity.

Hope that helps

Mikiel
  • 451
  • 3
  • 9
  • That would work to ensure teh right rarity to be returned. This is actually already the case because I'm doing this check in the CheckItemCondition Call. What I need is just the weighted selection instead of just the selection. – epanalepsis Jul 18 '19 at 15:28
-1

Try following :

public IEnumerable<T> GetRandomItem<T>(int count = 1, Rarity maxRarity = Rarity.Common, List<int> ids = null)
  where T : Item
{
  InitializeActualRarities(maxRarity);
  Random rand = new Rand();
  return GetItems<T>().ToList().Where(i => CheckItemConditions(ref i, maxRarity, ids)).Clone().Select((x,i) => new {item = x, rand = rand.Next()}).OrderBy(x => x.rand).Select(x => x.item).Take(count);
}
jdweng
  • 33,250
  • 2
  • 15
  • 20