Classic deck of cards/poker game issue. I have classes for each card (CardClubs, CardDiamond, etc). I have an enum for Rank (Deuce = 2, etc). In my CardSet class, I have the constructor:
public SuperCard[] cardArray;
public Random myRandom = new Random();
#region Constructor
public CardSet()
{
cardArray = new SuperCard[52];
for (int i = 0; i < 13; i++)
{
cardArray[i] = new CardClubs((Rank)i + 1);
cardArray[i + 13] = new CardDiamond((Rank)i+1);
cardArray[i + 26] = new CardHeart((Rank)i + 1); ;
cardArray[i + 39] = new CardSpades((Rank)i + 1); ;
}
}
#endregion
And I have the method GetCards, which passes in the number of cards to get. I created the public random up top. GetCards is called in the Program.cs, as such:
int howManyCards = 5; // can be whatever. used this instead of # for debug purposes
SuperCard[] computerHand = myDeck.GetCards(howManyCards); // create two hands, user/comp
SuperCard[] myHand = myDeck.GetCards(howManyCards);
I am not understanding how to use random to generate the random card. here is my current GetCard method (which isn't working) also from the CardSet class. For now, its okay if it generates the same card, just want to understand the basics of random selection.
public SuperCard[] GetCards(int number)
{
SuperCard[] hand = new SuperCard[number];
for (int i = 0; i < number; i++)
{
hand[i] = cardArray[myRandom]((Rank)i + 1);
}
return hand;
}
Use the Random class (http://msdn.microsoft.com/en-us/library/system.random.aspx)
var r = new Random();
r.Next(min,max);
Related
Please check the code below. I am trying to set value to a random property of a int list. Problem is that even after i set 5 to a random list this value getting inserted to that property. What am I doing wrong here?
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
var randTransaction = TransactionList.OrderBy(x => Guid.NewGuid()).FirstOrDefault();
//here i am trying to set 5 value to a random TrnasactionList but this not being set
randTransaction = 5;
Try like below. new Random().Next(0, 59); will return value between 0 and 59. Or you can better set it like new Random().Next(0, TransactionList.Count); for it to be dynamic with list.
new Random().Next(minValue, maxValue); The maxValue for the upper-bound in the Next() method is exclusive—the range includes minValue, maxValue-1, and all numbers in between.
var TransactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
TransactionList.Add(0);
}
// var index = new Random().Next(0, 59);
// Below will work for dynamic length of list.
var index = new Random().Next(0, TransactionList.Count);
TransactionList[index] = 5;
If you don't mind the original list getting sorted you could do this:
class Program
{
static void Main(string[] args)
{
var transactionList = new List<int>();
for (int i = 0; i < 59; i++)
{
//I initialized the list with i instead of 0 to better see sorting in place
transactionList.Add(i);
}
transactionList.Sort(new RandomComparer());
//changed it to 99 to spot it more easily
transactionList[0] = 99;
foreach (var i in transactionList)
Console.WriteLine(i);
}
}
public class RandomComparer : IComparer<int>
{
private Random _random = new Random();
public int Compare(int x, int y)
{
return _random.Next(-1, 2);
}
}
See it in action:
https://dotnetfiddle.net/NKuPdx
randTransaction is "int" data type, which is primitive data type.
if you want to set randTransaction that reflect to it's object, just set the object it self
I am stuck trying to figure out how to use the values of one array of numbers to initialize a second array of objects. This might not be the most effective way to do something like this in a real program, but I am just trying to understand how to create a relationship between two different arrays.
The first array is just a randomly generated array holding values 0,1 or 2. The second array is an array of Occupant objects. Each occupant has an occupant id that will be either 0, 1 or 2. I am trying to generate the second array of occupants by copying the values of first array and then initializing the second based on the occupant id.
Nothing I have tried will compile, and I can't think of anything else on my own except writing a million if statements. Surely there must be a simple solution I am missing. Any help you can offer will be greatly appreciated.
FYI: Occupant is the base class, three classes derive from it, each with a unique id number.
static public class Board
{
static public Occupant[,] board = BoardGen();
static private Occupant[,] BoardGen()
{
Random myRandom = new Random();
int[,] setup = new int[10, 10];
for (int i = 0; i < setup.GetLength(0); i++)
{
for (int j = 0; j < setup.GetLength(1); j++)
setup[i, j] = myRandom.Next(0, 3);
}
Occupant[,] populate = new Occupant[10,10];
// How to link setup to populate using the number to choose an occupant based on it's id number?
return populate;
}
}
}
I would suggest to fill-in the second table along with the first, or even better, completely forget about the first table:
static private Occupant[,] BoardGen()
{
Random myRandom = new Random();
// Not needed
// int[,] setup = new int[10, 10];
Occupant[,] populate = new Occupant[10, 10];
for (int i = 0; i < populate .GetLength(0); i++)
{
for (int j = 0; j < populate .GetLength(1); j++)
{
int randomSetup = myRandom.Next(0, 3);
switch (randomSetup)
{
case 0:
populate[i, j] = new Occupant_0(); // Derived Class with id=0
break;
case 1:
populate[i, j] = new Occupant_1(); // Derived Class with id=1
break;
case 2:
populate[i, j] = new Occupant_2(); // Derived Class with id=2
break;
default:
break;
}
}
}
return populate;
}
abstract class Master
{
public abstract int Id { get; }
}
class A : Master
{
public override int Id => 1;
}
class B : Master
{
public override int Id => 2;
}
class C : Master
{
public override int Id => 3;
}
Type[] types = new Type[] { typeof(A), typeof(B), typeof(C) };
int[] yourIds = new int[100];
Master[] generated = new Master[yourIds.Length];
for (int i = 0; i < yourIds.Length; i++)
{
generated[i] = (Master)Activator.CreateInstance(types[yourIds[i] - 1]);
}
I cannot understand your question completely, but this logic should fit your situation.
The point is that you can create an instance in runtime with the System.Activator and a System.Type.
I have an Gameobject that contains several prefabs, As in the picture below
public SimpleSpriteSequence birds;
Randomizer setBirds;
setBirds = new Randomizer(birds.sprites);
int index = setBirds.getRandom();
birds.setCurrentSpriteIndex(index);
In the image below we see the population of the array
Invoke("Interface", 1f);
Now with the help of the random I get a random bird from the array. But the problem is that the bird can be repeated. All I want is that at least 6 times in a row when the Invoke("Interface", 1f); function does not repeat the bird.So in principle I have to do so 6 times the bird does not repeat itself. To be a random of these birds but 6 times to be different birds. No I know if I explained it properly, but I hope you understand the idea.
Here is code but it is written in console application since i do not have your code and it is writen with custom class of Birds but you will adapt it to your code. If you need help with it i will help you.
class Birds
{
public int birdID;
public string birdName;
//public Sprite birdSprite;
}
class Program
{
static Random rnd = new Random();
static Birds[] birds = new Birds[10];
static int nBirdsSpawned = 0;
static List<int> spawnedBirds = new List<int>();
static void Main(string[] args)
{
//Database of my birds ;)
birds[0] = new Birds();
birds[1] = new Birds();
birds[2] = new Birds();
birds[3] = new Birds();
birds[4] = new Birds();
birds[5] = new Birds();
birds[6] = new Birds();
birds[7] = new Birds();
birds[8] = new Birds();
birds[9] = new Birds();
birds[0].birdID = 0;
birds[0].birdName = "Bird 1";
birds[1].birdID = 1;
birds[1].birdName = "Bird 2";
birds[2].birdID = 2;
birds[2].birdName = "Bird 3";
birds[3].birdID = 3;
birds[3].birdName = "Bird 4";
birds[4].birdID = 4;
birds[4].birdName = "Bird 5";
birds[5].birdID = 5;
birds[5].birdName = "Bird 6";
birds[6].birdID = 6;
birds[6].birdName = "Bird 7";
birds[7].birdID = 7;
birds[7].birdName = "Bird 8";
birds[8].birdID = 8;
birds[8].birdName = "Bird 9";
birds[9].birdID = 9;
birds[9].birdName = "Bird 10";
int i = 0;
while (i < 100)
{
RandomSpawn();
i++;
}
Console.Write("Finished");
Console.ReadKey();
}
static void CheckForBirdSpawn(int birdID)
{
if (nBirdsSpawned <= 6)
{
if (!spawnedBirds.Contains(birdID))
{
spawnedBirds.Add(birdID);
SpawnBird(birdID);
}
else
{
Console.WriteLine("Bird " + birds[birdID].birdName + " is already spawned!");
}
}
else
{
SpawnBird(birdID);
}
}
static void SpawnBird(int birdID)
{
Console.WriteLine(birds[birdID].birdName);
nBirdsSpawned++;
}
static void RandomSpawn()
{
int r = rnd.Next(0, 10);
CheckForBirdSpawn(r);
}
}
Until first 6 birds are spawned it check if bird is already spawned and if it is it doesn't allow it's spawning. After 6 birds are spawned it allows every bird to be spawned.
Here is output in console app:
I know this is a mainly code reply but how about you try something a little like this?
Populate a list of the bird indexes.
Pick a random index within that list.
Decrease all already spawned birds' Values.
If any reach zero, re-add the birds index into the availableBird list.
Spawn the bird, while adding it's index as Key and the amount of spawning delay needed until it can be spawned again as the Value.
Remove the birds index from the list.
Do the spawn whenever necessary, this will spawn every frame since it is found in a Coroutine which has an infinite while loop.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class burd : MonoBehaviour {
public bool spawning;
private System.Random rnd = new System.Random();
private Dictionary<int, int> spawnedBurdies = new Dictionary<int, int>();
private List<int> availableBurdies = new List<int>();
// Use this for initialization
void Start () {
for (int index = 0; index < 10; index++)
{
availableBurdies.Add(index);
}
StartCoroutine(SpawnBurdies());
}
private IEnumerator SpawnBurdies()
{
while (true)
{
if (spawning)
{
int burdIndex = rnd.Next(availableBurdies.Count);
spawnBurd(availableBurdies[burdIndex]);
availableBurdies.RemoveAt(burdIndex);
}
yield return new WaitForFixedUpdate();
}
}
private void spawnBurd(int burdIndex)
{
Debug.Log("Spawned burd #" + burdIndex);
List<int> burdieKeys = new List<int>();
foreach (var burdie in spawnedBurdies) { burdieKeys.Add(burdie.Key); }
foreach (var burdieKey in burdieKeys)
{
spawnedBurdies[burdieKey]--;
if(spawnedBurdies[burdieKey] <= 0)
{
spawnedBurdies.Remove(burdieKey);
availableBurdies.Add(burdieKey);
}
}
spawnedBurdies.Add(burdIndex, 6);
}
}
This solution would save you from attempting to spawn birds that can't be spawned; but if there are less birds than the minimum spawns to wait for, an Argument out of range error would be thrown.
I'm making a basic Deal or No Deal game, in doing so I have to pick 10 finalists from an array, at random, without repeats.
I have my structure and arrays set out like this
public struct People
{
public string firstname;
public string lastname;
public int age;
}
class Program
{
public static People[] People1 = new People[40];
public static People[] Finalists1 = new People[10];
public static People[] Finalist1 = new People[1];
And my finalists method set out like this
Random rand = new Random();
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, People1.Length);
Finalists1[i].lastname = People1[num].lastname;
Finalists1[i].firstname = People1[num].firstname;
Finalists1[i].age = People1[num].age;
}
How can I eliminate duplicate entries, while maintaining 10 people in the array?
Since initial array doesn't contain duplicates, you can sort it in random order and pick up 10 top items:
Finalists1 = People1
.OrderByDescending(item => 1) // if people have some points, bonuses etc.
.ThenBy(item => Guid.NewGuid()) // shuffle among peers
.Take(10) // Take top 10
.ToArray(); // materialize as an array
If people are selected to the final are not completely random (e.g. contestant can earn points, bonuses etc.) change .OrderByDescending(item => 1), e.g.
.OrderByDescending(item => item.Bonuses)
If you don't want to use Linq, you can just draw Peoples from urn without returning:
private static Random random = new Random();
...
List<People> urn = new List<People>(People1);
for (int i = 0; i < Finalists1.Length; ++i) {
int index = random.Next(0, urn.Count);
Finalists1[i] = urn[index];
urn.RemoveAt(index);
}
You can hold a list or hash set of numbers you have already drawn. Then just roll the dice again to get another random number.
Random rand = new Random();
HashSet<int> drawnNumbers = new HashSet<int>();
for (int i = 0; i < Finalists1.Length; i++)
{
do
{
num = rand.Next(0, People1.Length);
}
while (drawnNumbers.Contains(num));
Finalists1[i] = People1[num];
}
You can change the type of Finalists1 to a HashSet, that does not allow duplicates.
Then change your loop to
while(Finalists1.Length < 10)
{
// random pick from array People1 (you don't need to create a new one)
num = rand.Next(0, People1.Length);
var toAdd = People1[num];
// add to hash-set. Object won't be added, if already existing in the set
Finalists1.Add(toAdd);
}
You probably need to override the Equals method of class People, if you really need to create a new object to add to the hash-set.
You can group people array and select distinct that way.
If you use List you can remove person from the list
`var peopleArray = new People[40];
var peopleCollection = peopleArray.GroupBy(p => new { p.age, p.firstname, p.lastname }).Select(grp => grp.FirstOrDefault()).ToList();
var finalists = new People[10];
var rand = new Random();
for (var i = 0; i < finalists.Length; i++)
{
var index = rand.Next(0, peopleCollection.Count);
var person = peopleCollection[index];
finalists[i].lastname = person.lastname;
finalists[i].firstname = person.firstname;
finalists[i].age = person.age;
peopleCollection.Remove(person);
}
shuffle and take the first 10, for example
People1.Shuffle();
Finalists1= People1.Take(10).ToArray();
you can find shuffle code from StackOverflow or search for "Fisher-Yates shuffle C#" Below methods are taken from This SO Post. Read the answers for more information on why GUID is not used etc..
public static class ThreadSafeRandom
{
[ThreadStatic] private static Random Local;
public static Random ThisThreadsRandom
{
get { return Local ?? (Local = new Random(unchecked(Environment.TickCount * 31 + Thread.CurrentThread.ManagedThreadId))); }
}
}
static class MyExtensions
{
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = ThreadSafeRandom.ThisThreadsRandom.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
Swap each selected element in People1 to with the end of the array, and decrement an end-of-array index so that you're only selecting from what's left on the next iteration.
People tempPerson = new People;
int lastElem = People1.length - 1;
for (int i = 0; i < Finalists1.Length; i++)
{
num = rand.Next(0, lastElem + 1);
Finalists1[i] = People1[num];
//swap last entry in People1 with People1[num]
tempPerson = People1[num];
People1[num] = People1[lastElem];
People1[lastElem] = tempPerson;
lastElem--;
}
Sorry if there's a syntax error, I'm mostly using Java and C# these days.
BTW You don't have to set the fields individually since each array stores objects of type Person.
For some reason, when I try to generate this code all at once, the code produces the same number or letter over and over again (30 times) - see below. When I go through line by line in debug mode, however, the code works great...
private string Generate_ActiveX_name()
{
StringBuilder charBuilder = new StringBuilder("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
StringBuilder numBuilder = new StringBuilder("0123456789");
//
// Holds Active X Key (final)
//
StringBuilder activeX_builder = new StringBuilder();
// Determine charactar or number
while (activeX_builder.Length < 30)
{
Random activeX_gen = new Random();
switch (activeX_gen.Next(0, 2))
{
case 0:
Random charSelection = new Random();
int CharSelected = charSelection.Next(0, 53);
activeX_builder.Append(charBuilder[CharSelected]);
break;
case 1:
Random numSelection = new Random();
int NumSelected = numSelection.Next(0, 10);
activeX_builder.Append(numBuilder[NumSelected]);
break;
}
}
string activeX_key = activeX_builder.ToString().Substring(0, 8) + "-";
activeX_key += activeX_builder.ToString().Substring(8, 4) + "-";
activeX_key += activeX_builder.ToString().Substring(12, 4) + "-";
activeX_key += activeX_builder.ToString().Substring(16, 11);
return activeX_key;
}
Why does this code fail when I run it through all at once?
Thanks,
Evan
You need to move the Random constructor out of your loop. Change this:
while (activeX_builder.Length < 30)
{
Random activeX_gen = new Random();
To:
Random activeX_gen = new Random();
while (activeX_builder.Length < 30)
{
The issue is that, when an instance of Random is created, it uses the current system clock as a "seed" value for the random number generation. Since your routine runs very quickly, the same seed is chosen every time, so you get the same "random" value. When you're debugging, you're slowing it down (by stepping) enough that a different seed is chosen in each loop, and you get truly random values.
If you move it out of the loop, then a single Random instance will be created, which will lead to a random distribution (and more efficiency!).
Seems like you are trying to generate GUID.
You can do this with one line
var guid = Guid.NewGuid();
However, here is the fix to your code:
private static string Generate_ActiveX_name()
{
StringBuilder charBuilder = new StringBuilder("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
StringBuilder numBuilder = new StringBuilder("0123456789");
StringBuilder activeX_builder = new StringBuilder();
Random activeX_gen = new Random();
while (activeX_builder.Length < 30)
{
switch (activeX_gen.Next(0, 2))
{
case 0:
int CharSelected = activeX_gen.Next(0, 53);
activeX_builder.Append(charBuilder[CharSelected]);
break;
case 1:
int NumSelected = activeX_gen.Next(0, 10);
activeX_builder.Append(numBuilder[NumSelected]);
break;
}
}
string activeX_key = activeX_builder.ToString().Substring(0, 8) + "-";
activeX_key += activeX_builder.ToString().Substring(8, 4) + "-";
activeX_key += activeX_builder.ToString().Substring(12, 4) + "-";
activeX_key += activeX_builder.ToString().Substring(16, 11);
return activeX_key;
}
Two problems:
You don't need more than one instance of Random class: charSelection and numSelection are redundant.
Instantiate Random class one time, not inside of the while loop.
[Edit]
8-4-4-11 format:
var guidText = Guid.NewGuid().ToString();
var customGuid = guidText.Substring(0, 18) + guidText.Substring(23, 12);