1

I'm coding a bot for a game, in which several players have different actions and use them to interact with each other.

One of the actions I'm coding chooses 2 players (A and B), and makes every other player that was targeting A, target B instead, and vice versa.

However, with my code, only players targeting B have their target swapped. If a player is targeting A initially, my code changes it to B and then changes it to A back.

var target1 = Players.FirstOrDefault(x => x.Id == doorman.Choice);
var target2 = Players.FirstOrDefault(x => x.Id == doorman.Choice2);

if (target1 != null && target2 != null)
{
    var going1 = Players.Where(x => x.Choice == target1.Id && x.Id != doorman.Id);
    var going2 = Players.Where(x => x.Choice == target2.Id && x.Id != doorman.Id);

    foreach (var visitor in going1)
        visitor.Choice = target2.Id;

    foreach (var visitor in going2)
        visitor.Choice = target1.Id;
}

I think the problem is that the list going2 gets updated even after being declared, and has all the players in going1 added to it.

This means all players that are targeting target1 are swapped to target2 and then back to target1.

How can I make my going1 and going2 lists not update by themselves after being declared?

GSerg
  • 76,472
  • 17
  • 159
  • 346
  • 3
    You might want to force the evaluation of your `Where()` calls with a `.ToList()` statement. – Progman Sep 14 '19 at 12:42
  • You might want to look up the term "deferred execution" and possibly have a look at https://stackoverflow.com/q/7324033/11683 and https://stackoverflow.com/q/47379362/11683. – GSerg Sep 14 '19 at 12:48
  • lists `going1` and `going2` and the list `Players` are referencing to the same source, so any change in any of these will reflect in all of them (as you did in both foreach loops). you have declared `going1` and `going2` as new lists but they only have references to the source! – Rashid Ali Sep 14 '19 at 12:59
  • If you do not want original changed, then you need to clone the originals. – jdweng Sep 14 '19 at 13:04

1 Answers1

2

You should be using .ToList() after Where

var going1 = Players.Where(x => x.Choice == target1.Id && x.Id != doorman.Id).ToList();
var going2 = Players.Where(x => x.Choice == target2.Id && x.Id != doorman.Id).ToList();

As Linq .Where will return Enumerable list it will be evaluated again when you try to access going1 & going2 objects inside foreach. But if you use .ToList() then it will immediately evaluate value and assign it to going1 & going2 objects.

Karan
  • 12,059
  • 3
  • 24
  • 40