GiantDwarf010
GiantDwarf010

Reputation: 13

C# randomly pick elements from one array to move to another

I'm still learning C# so bear with me as I attempt to explain. Basiclly what I'm trying to do is deal a deck of cards. So arrayA (arrayGameBlessings in my example) has 52 elements and I want to move 10 cards to arrayB (arrayBlessings) while also removing them from arrayA. Here's what I got so far

for (int i = 0; i <= arrayGameBlessings.Length; i++)
{
    int bless = rnd.Next(arrayBlessings.Length);
    arrayGameBlessings[i] = arrayBlessings[bless];
    arrayBlessings = arrayBlessings.Where(w => w != arrayBlessings[bless]).ToArray();
}

But this doesn't do anything as far as I can tell... What would be the best way to achieve something like this? Preferably a super simple one, two line method that's easy to understand and modify. Thanks!

Upvotes: 1

Views: 819

Answers (3)

David Heffernan
David Heffernan

Reputation: 613053

Card dealing is typically done like this:

  1. Perform a shuffle.
  2. Pick the first N cards from the shuffled array.

A shuffle is done like so. Put integers 0 to 51 into an array. Then shuffle them with, for instance, Fisher-Yates shuffle. Perhaps like this:

int[] shuffle()
{
    int[] cards = Enumerable.Range(0, 52).ToArray();
    for (int i = cards.Length; i > 1; i--)
    {
        int j = random.Next(i);
        int temp = cards[j];
        cards[j] = cards[i-1];
        cards[i-1] = temp;
    }
    return cards;
}

int[] deal(int N)
{
    int[] result = new int[N];
    Array.Copy(shuffle(), 0, result, N);
    return result;
}

If you wanted to be more adventurous you could adapt the shuffle to pick just N cards.

You don't need to remove any elements from the shuffled deck. You just need to remember how many you took so far. And even then, you only need to do that if you are going to take any more at a later time without a new shuffle.

Upvotes: 1

Theraot
Theraot

Reputation: 40220

Your approach is not wrong per se, the only detail is that the for should use < instead of <=, that is:

void Main()
{
    var arrayBlessings = new int[]{1, 2, 3, 4, 5, 6};
    var arrayGameBlessings = new int[5];
    var rnd = new Random();
    for (int i = 0; i < arrayGameBlessings.Length; i++)
    {
        int bless = rnd.Next(arrayBlessings.Length);
        arrayGameBlessings[i] = arrayBlessings[bless];
        arrayBlessings = arrayBlessings.Where(w => w != arrayBlessings[bless]).ToArray();
    }
    Console.WriteLine(arrayBlessings);
    Console.WriteLine(arrayGameBlessings);
}

Note: code tested on LinqPad.


With that said, your approach is very inneficient. Each call to ToArray will create a new array, which is too much. Instead you may want to try List<T>:

void Main()
{
    const int amount_to_deal = 5;
    var arrayBlessings = new List<int>{1, 2, 3, 4, 5, 6};
    var arrayGameBlessings = new List<int>();
    var rnd = new Random();
    for (int i = 0; i < amount_to_deal; i++)
    {
        int bless = rnd.Next(arrayBlessings.Count);
        arrayGameBlessings.Add(arrayBlessings[bless]);
        arrayBlessings.RemoveAt(bless);
    }
    Console.WriteLine(arrayBlessings);
    Console.WriteLine(arrayGameBlessings);
}

As mentioned by David Heffernan, an array would be enough to shuffle, for example the following code will shuffle the array:

void Main()
{
    var array = new int[]{1, 2, 3, 4, 5, 6};
    var rnd = new Random();
    for (int i = 0; i < array.Length - 1; i++)
    {
        int j = i + rnd.Next(array.Length - i);
        var tmp = array[j];
        array[j] = array[i];
        array[i] = tmp;
    }
    Console.WriteLine(array);
}

Upvotes: 2

Anri
Anri

Reputation: 6265

//I assume you have a Card class, but this can be anything, integers, for example 
void MoveRandomCards(List<Card> source, List<Card> dest, int cards)
{
  var rnd = new Random();
  for(int i = 0;i<cards && source.Count>0;i++)
  {
    // random card position to remove from source
    var idxSrc = rnd.Next(source.Count);
    // random position in destination to insert new card
    var idxDst = rnd.Next(dest.Count);
    dest.Add(idxDst, source[idxSrc]);
    source.RemoveAt(idxSrc);
  }
}

Upvotes: 0

Related Questions