Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an efficient way to store and reference hundreds of values?

In my game, I have many different types of units that are instantiated/destroyed with regularity. They have certain values, like MaxHP or Level or Defense, which need to be referenced at instantiation, and may vary based on certain factors. For example, MaxHP may be higher if Level increases, but not based on a strict formula, which varies by unit. So, for example:

  • Soldier Level 1 Max HP: 5
  • Soldier Level 2 Max HP: 6
  • Soldier Level 3 Max HP: 8

  • Mage Level 1 Max HP: 3

  • Mage Level 2 Max HP: 4
  • Mage Level 3 Max HP: 5

The class name would be easy to reference, and the level of the units would be stored elsewhere, and I'd need to know which trait I'm looking up to look it up in the first place. Therefore, what makes sense to me is to store these as key/value pairs. I can programmatically check something like (className + lvlString + traitName) as the key, so the key would end up being Mage2MaxHP and the value would be 4.

Usually my instincts in this regard are pretty bad since I never learned much about data structures. So, I'm wondering if there's a better way to achieve this and organize this amount of data. For example, it seems like this would be incredibly large for a dictionary. Perhaps it would be more manageable split into several dictionaries (one for MaxHP, one for Defense, etc.), but I still feel like I'm overlooking a data structure more suitable for this purpose. Any recommendations?

like image 912
Anthony Perez Avatar asked Dec 08 '22 15:12

Anthony Perez


2 Answers

The following would approach your issue using both inheritance and Dictionaries in order to avoid having to class-name-strings etc.

public abstract class Unit
{
    // This approach would use one Dictionary per Trait
    protected abstract Dictionary<int, int> MaxHpByLevel { get; }

    public int Level { get; set; } = 1;

    public int MaxHp => this.MaxHpByLevel[this.Level];
}

public class Soldier : Unit
{
    protected override Dictionary<int, int> MaxHpByLevel => new Dictionary<int, int>
    {
        [1] = 5,
        [2] = 6,
        [3] = 8
    };
}

public class Mage : Unit
{
    protected override Dictionary<int, int> MaxHpByLevel => new Dictionary<int, int>
    {
        [1] = 3,
        [2] = 4,
        [3] = 5
    };
}

You would use it like that:

var soldier = new Soldier { Level = 2 };
Console.WriteLine(soldier.MaxHp); // 6

Just like you, I also think one could solve this issue in different ways.

What I like about this particular approach is that it is based on OOP-Principles and that it reduces redundant structural elements (e.g. avoids enums for trait-types etc.). You can access the properties of a unit over - well - Properties of a unit.

The Dictionaries used here would be rather small. However, I agree with the folks from the comments/answers when it comes to the size-restrictions. No matter what approach you choose, you will likely not bring your dictionaries any close to its limits.

like image 94
nozzleman Avatar answered Dec 13 '22 03:12

nozzleman


"Hundreds" really isn't much in terms of a modern CPU, a Dictionary adds a lot of complexity and ties you to one access pattern. Often it's best to start simple: with a List<T> and figure out what your access patterns will be. You can use LINQ against it to query by class name, hp, level or any combination thereof. Once you have it working, if you find that you need to boost performance for some queries, then, at that time go ahead and refactor it maybe using a Dictionary as an index.

But never underestimate the power of a modern compiler and a modern CPU to iterate over a contiguous block of memory blindingly fast beating many other data structures than might offer a better theoretical performance for very large values of N.

like image 36
Ian Mercer Avatar answered Dec 13 '22 03:12

Ian Mercer