0

I am trying to create a custom dictionary with some methods. I created a struct containing the information for lanes in my game. One information tells me if there is an enemy in the lane(Occupied) and the other if we completed that lane so no more enemies will come there(Completed).

I am able to get the initial information out, but cannot update them with my methods. I construct it by adding all 7 lanes, where none of them are either occupied or completed. Then throughout my game, I would like to mark them either as completed or occupied or free, but even after a lot of time searching around, I couldn't figure out the proper way to call for an update of these items inside my laneInfo property.

public struct laneInfo
{
    public bool Occupied;
    public bool Completed;
}

public class laneInfoClass : Dictionary<int, laneInfo>
{
    public laneInfo laneinfo;

    public laneInfoClass()
    {
        for(int i = 0; i <= 6; i++)
        {
            this.Add(i, false, false);
        }
    }
    public void Add(int key, bool occupied, bool completed)
    {
        laneinfo.Occupied = occupied;
        laneinfo.Completed = completed;
        this.Add(key, laneinfo);
    }
    public void Complete()
    {
        laneinfo.Completed = true;
    }
    public void Occupy()
    {
        laneinfo.Occupied = true;
    }
    public void Free()
    {
        laneinfo.Occupied = false;
    }
}

Thanks!

Wehaga
  • 27
  • 4
  • First of all, please stick to common code conventions. It's just easier to read for us. Then, in your `Add` method, what do you think is happening there? You are altering an existing instance and adding it to your "dictionary". Which means, you are altering "_all_ " of them - because there actually _is only one_. – Fildor Oct 19 '21 at 09:57
  • Then you have those `Complete`, `Occupy`, ... methods. But they don't specify, which lane they shall mutate. – Fildor Oct 19 '21 at 10:00
  • 2
    BTW: I think you'd be better off _and_ less confused, if `LaneInfoClass` _had_ a dictionary instead of _being_ a Dictionary. – Fildor Oct 19 '21 at 10:01
  • 1
    By common code conventions, Fildor means that structs and classes should be named with PascalCase. Also, classes should not use the word Class as a suffix, unless it's valid for some other reason, such as if it's modelling a Class that a Student is enrolled for. I can't see the point in your struct; put your two bool fields into the `class` as properties, and throw the struct away. As you're indexing your Dictionary by int, consider whether it would just be better to have an array of LaneInfo (the class, not the struct, you threw the struct away) in some other class like LaneManager – Caius Jard Oct 19 '21 at 10:02
  • 1
    @Fildor I'd go one step further and say Wehaga would be better off if `laneInfoClass` didn't exist in the first place and instead just used `Dictionary`. Though I think they are getting mixed up with how dictionaries actually work. – DavidG Oct 19 '21 at 10:06
  • @DavidG You may be right. I was under the impression, OP wanted to have some sort of "Manager" class ... – Fildor Oct 19 '21 at 10:08
  • 1
    Hah, and now you've got me saying to throw the struct away, David saying to throw the class away.. :D But all in I think people would agree you would ideally have two things: a (class) that tracks stuff per-lane, and another class that knows how many lanes you have/tracks multiple instances of the first class – Caius Jard Oct 19 '21 at 10:08
  • Thanks all, I'll make sure to stick to those conventions more(I do find myself looking up what I'm referring to a lot of times) – Wehaga Oct 19 '21 at 10:27

2 Answers2

3

Its fairly rare that your class would inherit from a dictionary/list/collection (why?), more often than not what you are actually modelling is a class which has an instance member which is that same dictionary/list/collection.

In addition, you need some way to notify your class which particular lane you're trying to update, you use an integer key so work with that:

public struct LaneInfo
{
    public bool Occupied {get;set;}
    public bool Completed {get;set;}
}

public class LaneInfoContainer
{
    private Dictionary<int, LaneInfo> laneInfoDict = new Dictionary<int, LaneInfo>();

    public LaneInfoContainer()
    {
        for(int i = 0; i <= 6; i++)
        {
            this.Add(i, false, false);
        }
    }
    public void Add(int key, bool occupied, bool completed)
    {
        var laneInfo = new LaneInfo();
        laneinfo.Occupied = occupied;
        laneinfo.Completed = completed;
        this.laneInfoDict.Add(key, laneinfo);
    }
    public void Complete(int key)
    {
        laneInfoDict[key].Completed = true;
    }
    public void Occupy(int key)
    {
        laneInfoDict[key].Occupied = true;
    }
    public void Free(int key)
    {
        laneInfoDict[key].Occupied = false;
    }
}

I suspect you might also need some way to read the info about your lanes too, add methods such as

public bool IsComplete(int key)
{
    return laneInfoDict[key].Complete;
}
Fildor
  • 14,510
  • 4
  • 35
  • 67
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • 2
    Don't do *all* their homework for them... – Caius Jard Oct 19 '21 at 10:09
  • 2
    @CaiusJard nah, I dounbt this is _all_ the homework. There's defo more to it than just this. – Jamiec Oct 19 '21 at 10:09
  • 1
    It may be worthwhile to point out to OP, _why_ we refrain from inheriting from Collection types ... I am sure, there has been a community question about this ... found this : https://stackoverflow.com/a/21694054/982149 - it's about List but I guess one could generalize to collections. – Fildor Oct 19 '21 at 10:11
  • 2
    @Fildor thanks, you just did! (Ill add the link to the answer) – Jamiec Oct 19 '21 at 10:13
  • Thanks a lot all of you, I actually got the main idea from another stack answer and tried to modify that to fit my needs, without fully understanding. And don't worry, I still have plenty to do :) Not homework, but hobby project :) – Wehaga Oct 19 '21 at 10:25
  • so I'm getting now an error for: error CS1612: Cannot modify the return value of 'Dictionary.this[int]' because it is not a variable Any ideas? Thanks again @Jamiec – Wehaga Oct 19 '21 at 16:14
  • 1
    @Wehagaprobs worth a new question – Jamiec Oct 20 '21 at 07:23
0

The answer to your question is that you should not use a Dictionary. Iterating a List<T>.Contains is faster than Dictionary<TKey, TValye> lookup for 7 items, especially if you are accessing them by index integer 0-6.

Part from that, Dictionary<TKey, TValue> is already generic and so there is no need to inherit from it. Sometimes you would wrap it, for various reasons (one might be locking). But if it is just for a few methods you can simply add extension methods to the Dictionary<int, LaneInfo>.

public static class LaneExtensionMethods
{
    public static bool IsComplete(this Dictionary<int, LaneInfo> dictionary, int key)
    {
        return dictionary[key].Complete;
    }
}

// Use
var d = new Dictionary<int, LaneInfo>();
var isComplete = d.IsComplete(1);

I often replace the int with a type to avoid bugs and confusion in code. This would in your case also allow for specialized extension methods. Casting has zero CPU cost (its just cosmetics in code).

public enum LaneId : Int32 { }

public static class LaneExtensionMethods
{
    public static bool IsComplete(this Dictionary<LaneId, LaneInfo> dictionary, LaneId key)
    {
        return dictionary[key].Complete;
    }
}

// Use
var d = new Dictionary<LaneId, LaneInfo>();
var laneId = (LaneId)1; // We cast from integer to LaneId, but use LaneId type everywhere in our app
var isComplete = d.IsComplete(laneId);
Tedd Hansen
  • 12,074
  • 14
  • 61
  • 97