10

I am keeping track of values in a console. Two people "duel" against each other and I was using a dictionary to keep the names recorded along with damage done.

var duels = new Dictionary<string, string>();
duels.Add("User1", "50");
duels.Add("User2","34");

I'm trying to store both users in the same dictionary row, so it could be verified as User1 is dueling against User2. This way if another duel started, it would not interfere with User1 or User2.

duels.Add("KeyUser1","KeyUser2","50","34",.../*Other attributes of the duel*/);

I need two keys so I can check where the user's damage will go. The damage will always go to the other key--vice versa. What can I do to make this work?

Thank you.

Kyle
  • 3,004
  • 15
  • 52
  • 79
  • 7
    I would recommend using tuples for this. Here is a related article that might lead you in the right direction: http://stackoverflow.com/questions/1171812/multi-key-dictionary-in-c . Good luck! – Stephen Tetreault Feb 27 '12 at 03:52
  • Can a single user be engaged in more than one duel at a time? – Branko Dimitrijevic Feb 27 '12 at 04:55
  • Is the duel involving "User1" and "User2" different than the duel involving "User2" and "User1" ? – Amy B Feb 27 '12 at 05:08
  • @Branko No they cannot.@David B No not different at all. Duels against 2 people are interchangeable. – Kyle Feb 27 '12 at 06:53
  • Tuple may enforce you to initialize it at the very beginning but not to inflate it at latter time. – zionpi Jan 22 '15 at 03:05

4 Answers4

5

You could try making a custom data type for the key:

class DualKey<T> : IEquatable<DualKey<T>> where T : IEquatable<T>
{
    public T Key0 { get; set; }
    public T Key1 { get; set; }

    public DualKey(T key0, T key1)
    {
        Key0 = key0;
        Key1 = key1;
    }

    public override int GetHashCode()
    {
        return Key0.GetHashCode() ^ Key1.GetHashCode();
    }

    public bool Equals(DualKey<T> obj)
    {
        return (this.Key0.Equals(obj.Key0) && this.Key1.Equals(obj.Key1))
            || (this.Key0.Equals(obj.Key1) && this.Key0.Equals(obj.Key0));
    }
}

Then use a Dictionary<DualKey<string>, string>;

Daryl
  • 3,253
  • 4
  • 29
  • 39
  • 1
    I dont want to sound rude but as per the Stack Overflow norm this should be a comment on the original question and not submitted as an answer. Wouldn't want you to get down voted :) – Stephen Tetreault Feb 27 '12 at 03:54
  • 1
    I haven't tried an embedded dictionary. Wouldn't that mean having different key dictionaries though? – Kyle Feb 27 '12 at 03:56
5
public class Duel
{
  public string User1 {get; protected set;}
  public string User2 {get; protected set;}
  public Duel(string user1, string user2)
  {
    User1 = user1;
    User2 = user2;
  }

  public HashSet<string> GetUserSet()
  {
    HashSet<string> result = new HashSet<string>();
    result.Add(this.User1);
    result.Add(this.User2);
    return result;
  }

  //TODO ... more impl
}

Let's make some duels. CreateSetComparer allows the dictionary to use the values of the set for equality testing.

List<Duel> duelSource = GetDuels();
Dictionary<HashSet<string>, Duel> duels =
  new Dictionary<HashSet<string>, Duel>(HashSet<string>.CreateSetComparer());

foreach(Duel d in duelSource)
{
  duels.Add(d.GetUserSet(), d);
}

And finding a duel:

HashSet<string> key = new HashSet<string>();
key.Add("User1");
key.Add("User2");
Duel myDuel = duels[key];
Amy B
  • 108,202
  • 21
  • 135
  • 185
4

Something quick.

class UserScores {

    public string Key { get; set; }

    public int User1Score { get; set; }
    public int User2Score { get; set; }

    public UserScores(string username1, string username2)
    {
            Key = username1 + ":" + username2;
    }
}

void Main()
{
    var userScore = new UserScores("fooUser", "barUser");

    var scores = new Dictionary<string, UserScores>();

    scores.Add(userScore.Key, userScore);

    // Or use a list

    var list = new List<UserScores>();

    list.Add(userScore);

    list.Single (l => l.Key == userScore.Key);
}

Although a proper solution in my opinion would use a better thought out UserScores object that tracks that particular "duel" session.

Razor
  • 17,271
  • 25
  • 91
  • 138
  • 1
    What if `vin` and `yetish` are fighting while `viny` and `etish` are fighting? :) – Paul Bellora Feb 27 '12 at 03:59
  • I like the idea of combining them together. I think I could add something like a `username1+":"+username2` and split the `:` to get `user[0]` and `user[1]`. – Kyle Feb 27 '12 at 04:00
  • 1
    Also @Kyle don't forget to add a GetHashCode() and IEquatable.Equals() implementation. – Razor Feb 27 '12 at 04:22
2

Since a single person can be involved in at most one duel at a time, you can use a single dictionary to directly "index" both endpoints in all duels, something like this:

class Duel {

    public Duel(string user1, string user2) {
        Debug.Assert(user1 != user2);
        User1 = user1;
        User2 = user2;
    }

    public readonly string User1;
    public readonly string User2;
    public int User1Score;
    public int User2Score;

}

class Program {

    static void Main(string[] args) {

        var dict = new Dictionary<string, Duel>();

        // Add a new duel. A single duel has two keys in the dictionary, one for each "endpoint".
        var duel = new Duel("Jon", "Rob");
        dict.Add(duel.User1, duel);
        dict.Add(duel.User2, duel);

        // Find Jon's score, without knowing in advance whether Jon is User1 or User2:
        var jons_duel = dict["Jon"];
        if (jons_duel.User1 == "Jon") {
            // Use jons_duel.User1Score.
        }
        else {
            // Use jons_duel.User2Score.
        }

        // You can just as easily find Rob's score:
        var robs_duel = dict["Rob"];
        if (robs_duel.User1 == "Rob") {
            // Use robs_duel.User1Score.
        }
        else {
            // Use robs_duel.User2Score.
        }

        // You are unsure whether Nick is currently duelling:
        if (dict.ContainsKey("Nick")) {
            // Yup!
        }
        else {
            // Nope.
        }

        // If Jon tries to engage in another duel while still duelling Rob:
        var duel2 = new Duel("Jon", "Nick");
        dict.Add(duel2.User1, duel); // Exception! Jon cannot be engaged in more than 1 duel at a time.
        dict.Add(duel2.User2, duel); // NOTE: If exception happens here instead of above, don't forget remove User1 from the dictionary.

        // Removing the duel requires removing both endpoints from the dictionary:
        dict.Remove(jons_duel.User1);
        dict.Remove(jons_duel.User2);

        // Etc...

    }

}

This is just a basic idea, you might consider wrapping this functionality in your own class...

Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167