Assigning a random property enumeration value

Hi, I have been asked the problem I am struggling with. I need to assign a random value enum

to a property. I have the code.

public enum PegColour
{
    Red, Green, Blue, Yellow, Black, White
}

      

And another class that looks like

public class PegContainer
{
   /// <summary>
   /// Dfines the colour of the first peg
   /// </summary>
    public Peg Colour1 { get; set; }

    /// <summary>
    /// Dfines the colour of the secod peg
    /// </summary>
    public Peg Colour2 { get; set; }

    /// <summary>
    /// Dfines the colour of the third peg
    /// </summary>
    public Peg Colour3 { get; set; }

    /// <summary>
    /// Dfines the colour of the forth peg
    /// </summary>
    public Peg Colour4 { get; set; }

    public void GeneratePegs()
    {

    }
}

      

my GeneratePegs()

method should, every time it is called randomly assigns one of the colors to enum

one of the properties ( Colour1

, Colour2

etc.) to complicate matters I need a randomizer to ignore Black

and White

.

+3


source to share


4 answers


Enumerations are just integers, and so integers can be cast into an enum. I would do this:

Random rnd = new Random();

public enum PegColour
{
    Red, Green, Blue, Yellow, Black, White
}

private PegColour GetRandomColoredPeg()
{
    PegColour color = (PegColour)rnd.Next(0, Enum.GetNames(typeof(PegColour)).Length - 2);
    return color;
}

      

Black and white will never be selected because they are randomly selected from the first four colors. As long as you add bindings before the black and white pegs, this code should work every time, even if you add or remove bindings from the enumeration. So if you want to add new colors, you just change PegColour

to something like this:

public enum PegColour
{
    Red, Green, Blue, Yellow, Purple, Orange, Pink, Black, White
}

      



You don't need to change anything!

So your method GeneratePegs()

should look something like this:

public void GeneratePegs()
{
    Colour1 = GetRandomColoredPeg();
    Colour2 = GetRandomColoredPeg();
    Colour3 = GetRandomColoredPeg();
    Colour4 = GetRandomColoredPeg();
}

      

+5


source


A simple solution would be to create an array that contains all the valid values:

PegColour[] eligibleValues = new[] { PegColour.Red, PegColour.Blue, PegColour.Green, PegColour.Yellow };

      

Then you can use an instance Random

to randomly select an index on that array:

var myRandomColour = eligibleValues[myRandom.Next(eligibleValues.Length)];

      

The advantage of this is that you don't need to assign any specific numeric values ​​to constants enum

for random selection to work. This way, you can still define and use numeric values ​​for another purpose, if needed.


Now it can be a little awkward if it is PegColour

often expanded with new elements. In this case, you can get the complete list of the currently defined constants after initialization from the method Enum.GetValues

(note that this code snippet assumes the System.Linq

namespace
was imported to allow access to extension methods from ): System.Linq.Enumerable



PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().ToArray();

      

Obviously, this does not yet satisfy the requirement to exclude certain colors. So you can either hard-code this constraint directly in the array creation expression:

PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().Where(pc => (pc != PegColour.Black) && (pc != PegColour.White)).ToArray();

      

... or keep colors to exclude in some set to make things more extensible:

PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().Where(pc => !myExcludedColours.Contains(pc)).ToArray();

      

Note that you can always place this code so that it eligibleValues

only initializes once, not every time you fetch a value at random. This avoids unnecessary possible costly callsGetValues

, and also without having to regenerate the array.

+4


source


I suggest you create a list:

var pegs = new List<Peg> { Peg.Red, Peg.Green, Peg.Blue, Peg.Yellow };

      

Then, using the accepted answer to that request , randomly order it. Finally, assign values ​​to the bindings:

Colour1 = pages[0];
Colour2 = pages[1];
Colour3 = pages[2];
Colour4 = pages[3];

      

+2


source


I made a very generic extension method for an object Random

that generates a random value of the type Enum

. This works for all sorts of messed up enums, including the dreaded numbering schemes. This is achieved by using Enum.GetValues

to get all possible values ​​of the Enum. Then random simply picks a random possible value.

public static TEnum GetRandomEnum<TEnum>(this Random rand, IEnumerable<TEnum> excludedValues)
{
    var type = typeof(TEnum);
    if (!type.IsEnum)
        throw new ArgumentException("Not an enum type");


    var values = Enum.GetValues(type).Cast<TEnum>();

    if (excludedValues != null && excludedValues.Any())
        values = values.Except(excludedValues); 
    //if you call this a lot, you could consider saving this collection in memory
    //   and separate the logic to avoid having to re-generate the collection


    //create a random index for each possible Enum value 
    //will never be out of bounds because it NextDouble returns a value
    //between 0 (inclusive) and 1 (exclusive)  or [0, 1)
    int randomIndex = (int) (rand.NextDouble() * values.Count());
    return values.ElementAt(randomIndex);
}   

      

This extension method is named as follows:

var randomColor = rand.GetRandomEnum<ColorType>(new List<Colors> 
{ 
    Colors.White, 
    Colors.Black
});

      

demo .

0


source







All Articles