0

Let's suppose I have the following Dictionary:

private IDictionary<string, IPlayer> players;

where IPlayer is an interface defined as follows:

public interface IPlayer {
     bool HasTurn { get; set; }
     string Name { get; set; }
}

I'm trying to code a method that finds the active player, the one who has the turn, take its turn, and then give the turn to the next player in the dictionary.

So far I have this:

private void NextTurn() {
     if(!playing) return;
     IPlayer actual = players.Values.First(p => p.HasTurn);
     actual.HasTurn = false;
     // How can I get the next player in the dictionary??
}
Matias Cicero
  • 25,439
  • 13
  • 82
  • 154
  • 5
    `Dictionary` doesn't have any order specified, so there is no such thing as *next player* here. – MarcinJuraszek Jan 22 '15 at 19:28
  • 4
    There's no concept of "next" in a dictionary - it's logically unordered. If you want a specific order, you should use a different collection type. – Jon Skeet Jan 22 '15 at 19:28
  • You may be better off using a `Tuple` or another collection type. Remember, a `Dictionary` is designed as a `Key Value Pair`. Both items directly correlate to one another. – Greg Jan 22 '15 at 19:30
  • 4
    @MatiCicero: Just because you can iterate it, doesn't mean it's ordered. – Matt Burland Jan 22 '15 at 19:31
  • @MattBurland I don't want it to be ordered in any way, I just want to get the next element. If a `for each` cycle can do it with an `IEnumerable` (even though it's unordered), why can't I? – Matias Cicero Jan 22 '15 at 19:32
  • Then why not do something like `var playersWithTurns = players.Values.Where(p => p.HasTurn).ToList();` and then you can `foreach` it. The order of the list will be unpredictable (probably it'll be insertion order of the original dictionary, but it isn't guaranteed), but if you don't care, that's fine. Or you could just keep doing `First` (or better `FirstOrDefault`) as you were until there are no more players with turns. – Matt Burland Jan 22 '15 at 19:34
  • 1
    How about adding the property TurnNumber to your interface? – The One Jan 22 '15 at 19:36
  • 1
    I think you really need to clarify what you are actually trying to achieve here. I don't know what kind of (turn-based) game has no defined order of taking turns. You seem to need a list that is ordered so that you don't give a turn back to a player who has already taken a turn. Maybe you don't really need a dictionary at all, but would be better off with a `List`? Or if you really need the dictionary, it's quite possible to have both. – Matt Burland Jan 22 '15 at 19:38

3 Answers3

4

Dictionary does not have formally defined order - so you need separate structure that orders players.

Indeed you can enumerate elements and you will get an order (it will likely be the same order all the time due to implementation details) - so if you need just get list of all players in dictionary regular Dictionary.Values will give you the collection. While it is possible to define "next" this way most people reading your code will be confused - consider if other data structures reflect your intention better.

Trying to use OrderedDictionary may be an option, but No generic implementation of OrderedDictionary?

One cheap approach is to have "next player" as field of a player (possibly with name/other index as type).

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
2

Be careful, if you want to ensure the order of the dictionary items you need to make sure you are using a SortedDictionary. Then you would use the Keys collection and index of the current items to move on to the "next" key by locating the key by index + 1.

Jared Peless
  • 1,120
  • 9
  • 11
0

It would very much depend on how you define next; is it based on an identifier (the string key)? If so, then SortedDictionary may be the best bet. If its based on the order of insertion, then OrderedDictionary may be the best bet.

You can then use the Keys collection in the dictionary to determine position (you could also go through the key / value pair, but I think this illustrates what you're trying to do best).

foreach(var key in dictionary.Keys)
{
    var player = dictionary[key];
    //player does work
    player.HasTurn = false; 
}
Allan Elder
  • 4,052
  • 17
  • 19