-2

Currently working on a project to create the card game "War" in Windows Forms. I am using dictionaries to keep track of the image file as well as the value for the card. I am running into an issue where cpuDeck.add(x, y); is adding the dictionary entery to the front of the dictionary as opposed to the back.

cpuPlayer = cpu's deck

humanPlayer = human's deck

cpuWinnings and humanWinnings are temporary dictionaries to store the cards in in order to pull the image for the GUI before they enter back into the main dictionaries

if (cpuPlayer.Values.ElementAt(0) >= humanPlayer.Values.ElementAt(0))
{
    Image x = cpuPlayer.Keys.ElementAt(0);
    int y = cpuPlayer.Values.ElementAt(0);
    Image a = humanPlayer.Keys.ElementAt(0);
    int b = humanPlayer.Values.ElementAt(0);
    cpuPlayer.Remove(x);
    humanPlayer.Remove(a);
    cpuPlayer.Add(x, y);
    cpuPlayer.Add(a, b);
    cpuWinnings.Add(x, y);
    imgcpuwinning.Image = cpuWinnings.Keys.ElementAt(0);
    cpuWinnings.Clear();
}
else if ((humanPlayer.Values.ElementAt(0) > cpuPlayer.Values.ElementAt(0)))
{
    Image x = cpuPlayer.Keys.ElementAt(0);
    int y = cpuPlayer.Values.ElementAt(0);
    Image a = humanPlayer.Keys.ElementAt(0);
    int b = humanPlayer.Values.ElementAt(0);
    cpuPlayer.Remove(x);
    humanPlayer.Remove(a);
    humanPlayer.Add(x, y);
    humanPlayer.Add(a, b);
    humanWinnings.Add(a, b);
    imghumanwinning.Image = humanWinnings.Keys.ElementAt(0);
    humanWinnings.Clear();
}
else
{

}
Scottb0898
  • 37
  • 1
  • 6
  • 2
    Have a look at [The order of elements in Dictionary](https://stackoverflow.com/a/4007787) and check the [2nd](https://stackoverflow.com/a/7127926) and [3rd](https://stackoverflow.com/a/4007799) answers. – 41686d6564 stands w. Palestine May 03 '19 at 00:43
  • 1
    Perhaps you need to be using the [OrderedDictionary](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.ordereddictionary?view=netframework-4.8) class – Brendan Green May 03 '19 at 00:45
  • I think you are trying to use a dictionary like a `List>`, keys should be something you can reference, not `Image`'s. – Ron Beyer May 03 '19 at 00:46
  • Dictionaries don't have the same semantics as a list. They don't have a defined order. – Enigmativity May 03 '19 at 00:46
  • Any chance you could provide a [mcve]? – Enigmativity May 03 '19 at 00:48
  • There also seems to be very little point using a dictionary as using an `Image` as a key doesn't make much sense. It sounds like `List<(Image, int)>` would be a better choice. A [mcve] would help us to understand if that would be right. – Enigmativity May 03 '19 at 00:50

2 Answers2

0

You shouldn't depend on the order of keys in a Dictionary. If you need ordering, you should use an OrderedDictionary or SortedDictionary or a List of KeyValuePair if you want to change elements manually.

From the documentation:

For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair structure representing a value and its key. The order in which the items are returned is undefined.

The order of elements in a dictionary is non-deterministic. So don't rely on enumerating in the same order as elements were added to the dictionary. That's not guaranteed.

I hope it helps

Pavel Kovalev
  • 7,521
  • 5
  • 45
  • 67
  • 1
    I really think the OP is asking a X-Y question. He thinks he needs an ordered dictionary to solve his problem, but he probably is using the wrong type of data structure in the first place. – Enigmativity May 03 '19 at 00:55
  • 1
    `SortedDictionary` would be an inappropriate type here, since it sorts based on the `key`, and the OP is using an `Image` as the key. I don't think it would even work because `Image` is not `IComparable`. – Ron Beyer May 03 '19 at 01:20
  • Yes, and the OP doesn't want the dictionary sorted. The OP wants the last element added to be added to the back and not the front. That's not a sorting issue. – Enigmativity May 03 '19 at 01:25
  • @Enigmativity I did my best giving him a few options, so he can pick one. For example, List with KeyValuePair. The reason of showing him Ordered/SortedDictionary that he can change his game mechanics based on those classes... I assume that he is in control of the app not vice versa – Pavel Kovalev May 03 '19 at 21:00
0

A Dictionary<Image, int> doesn't have a concept of having an order. The idea of using a SortedDictionary<Image, int> wouldn't make sense as you still don't control where an item is added - that would be based on the key.

What you really need is some sort of list where you do control the position that you add items.

It's likely that List<(int Value, Image Image)>, or even Queue<(int Value, Image Image)>, is what you want. The type (int Value, Image Image) is a tuple containing two elements. It's much like KeyValuePair<Image, int> that you're currently using.

I'm going to suggest some code for you to play with, but I'm afraid it's difficult to know exactly what you are trying to do with the minimal code that you presented.

I'm also a little confused as to what you're attempting with this code:

    cpuWinnings.Add(x, y);
    imgcpuwinning.Image = cpuWinnings.Keys.ElementAt(0);
    cpuWinnings.Clear();

You appear to want to add an element to the end of cpuWinnings, but then you use the first item of the list, and then you clear the list. What was the point of adding an item to the end if you're going to just clear it? Or, if you're expecting .Add(x, y) to put it to the front of the list then why not just do imgcpuwinning.Image = x; before clearing the list?

I'm going to assume that you have the desire to add it to the end of the list.

So here's the code. To start I want to define a way to say who the current player is and to reduce the number of variables you have.

Let's create a Player enum:

public enum Player
{
    Human, Cpu
}

Now if you're trying to select the first item from a list and then remove that item you probably want a Queue. And we want a queue for each of the Human and Cpu players.

var player = new Dictionary<Player, Queue<(int Value, Image Image)>>()
{
    { Player.Human, new Queue<(int Value, Image Image)>() },
    { Player.Cpu, new Queue<(int Value, Image Image)>() },
};

It seems to me for the winnings you just need a list.

var winnings = new Dictionary<Player, List<(int Value, Image Image)>>()
{
    { Player.Human, new List<(int Value, Image Image)>() },
    { Player.Cpu, new List<(int Value, Image Image)>() },
};

And for your PictureBox elements you just need this:

var holder = new Dictionary<Player, PictureBox>()
{
    { Player.Human, imghumanwinning },
    { Player.Cpu, imgcpuwinning },
};

Now to select and remove the first element from the queue you do this:

(int Value, Image Image) xy = player[Player.Cpu].Dequeue(); //remove first
(int Value, Image Image) ab = player[Player.Human].Dequeue(); //remove first

Note: I've kept the xy and ab variable names from your code, I've just joined them together. Ideally you'd name these something a little more meaningful.

Next we want to find out who the current player is:

var currentPlayer = xy.Value >= ab.Value
    ? Player.Cpu
    : Player.Human;

Now processing the values is easy:

player[currentPlayer].Enqueue(xy); //add to end of queue
player[currentPlayer].Enqueue(ab); //add to end of queue
winnings[currentPlayer].Add(xy);
holder[currentPlayer].Image = winnings[currentPlayer].First().Image;
winnings[currentPlayer].Clear();

There's no if any more.

Now, I might be wrong about needing a Queue, but it seems to fit you current code. It could be that you need to use a Queue for winnings too. Maybe just a List for both would suffice. You'd need to provide more detail for me to have a better response.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172