How to get random value from Dictionary<string, bool> - c#

I am trying to get a random game name from my Dictionary Dictionary<string, bool>.
Any method I try doesn't seem to work for some reason.
I could do this in simple list form and I had this actually but what I am trying to do is in the first scene I want players to choose games they want to play(1 game or multiple games or all games). I have these game names as buttons on the scene in unity and What I'm trying to do is once they click those buttons and hit play only those games should run.
This is the screenshot of my main scene
Tried with ElementAT
Dictionary<string, bool> nameOfTheGame = new Dictionary<string, bool>();
nameOfTheGame.Add("Never Have I Ever", false);
nameOfTheGame.Add("Randomiser", false);
nameOfTheGame.Add("Dare", false);
nameOfTheGame.Add("Vote & Win", false);
nameOfTheGame.Add("Who Is Most Likely To ?", false);
nameOfTheGame.Add("Where's the water ?", false);
nameOfTheGame.Add("Would You Rather Choose ?", false);
nameOfTheGame.Add("Flip Or Strip", false);
nameOfTheGame.Add("Two Truths And One Lie", false);
string gameName = //(here)

You can use the below code using ElementAt
For the sake of testing purposes, I have changed a few values to true in your dictionary.
Dictionary<string, bool> nameOfTheGame = new Dictionary<string, bool>();
nameOfTheGame.Add("Never Have I Ever", true);
nameOfTheGame.Add("Randomiser", false);
nameOfTheGame.Add("Dare", true);
nameOfTheGame.Add("Vote & Win", false);
nameOfTheGame.Add("Who Is Most Likely To ?", true);
nameOfTheGame.Add("Where's the water ?", false);
nameOfTheGame.Add("Would You Rather Choose ?", true);
nameOfTheGame.Add("Flip Or Strip", false);
nameOfTheGame.Add("Two Truths And One Lie", true);
Random rand = new Random();
int index1 = rand.Next(0, nameOfTheGame.Count);
var item = nameOfTheGame.ElementAt(index1).Value;
int index2 = rand.Next(0, nameOfTheGame.Count);
var item2 = nameOfTheGame.ElementAt(rand.Next(0, nameOfTheGame.Count)).Value;

You can do it like this using System.Random class:
System.Random rand = new System.Random();
int index = rand.Next(map.Count-1);
string name = map.ElementAt(index).Key;
First line initializes random number generator. Second line gets number from 0 to your dictionary length, minus one. Your dictionary has 9 entries, so generated number will be from 0 to 8. Then, by that generated bumber (index) you can get element from your Dictionary. Once you have an element, Key contains the name of the game.

Related

Why does the Random class somtimes return nothing?

As you can see in my code down below, I have A and B. For example if I place the result at B then it sometimes return as result=0, nothing prints out in the console. But A works as it is expected to do. I don't really understand it, I did put a breakpoint, and stepped into the code but it didn't tell me much, just that the result return 0, this should infact print out the movie at Index 0? Sorry for being stupid, just want some clarification.
private static void PickRandomMovie(List<Movie> movie)
{
var rng = new Random();
//A:
var result = rng.Next(0, movie.Count);
for (int i = 0; i < movie.Count; i++)
{
//B:
//var result = rng.Next(0, movie.Count);
if (movie[i].Index.Equals(result))
{
Console.WriteLine(movie[i].Title);
break;
}
}
}
private static List<Movie> AddMovie()
{
return new List<Movie>
{
new Movie(new Movie(0, "Shark Attack", "Horror, Thriller")),
new Movie(new Movie(1, "Tom Clancy's", "Action")),
new Movie(new Movie(2, "American Pie", "Comedy")),
new Movie(new Movie(3, "Ted", "Comedy")),
new Movie(new Movie(4, "Ted 2", "Comedy")),
new Movie(new Movie(5, "American Pie 2", "Comedy")),
new Movie(new Movie(6, "Tom Clancy's 2", "Action")),
new Movie(new Movie(7, "Guardians of the Galaxy", "Comedy, Action")),
};
}
A chooses a random number and then loops all items in your array looking for the one where Index matches your pre-selected random number
B loops the array of items picking a new random number on every iteration of the loop and only writes the result if it happens to match.
There is a fairly high chance that the B case will never hit a match
While Jamiec explains the error well enough, I would suggest a few changes to your method:
Remove the explicit index from the movie objects, objects might have an id, but should not know or care about how they are stored or what index they have.
Don't loop thru the list, just do the indexing explicitly.
You should probably separate the search of the random item, from the print to the console part. That will help make your functions reusable.
There is no reason not to make such a function generic.
public static T PickRandomValue<T>(List<T> values, Random rng )
=> values[rng.Next(values.Count)];
...
var rng = new Random();
Console.WriteLine(PickRandomValue(movies, rng).Title);

Putting a int variable value which has been calculated by random into an arrayList

I'm new to C#. Is there any way that I can put the roll1 variable value into the rolls arrayList? Do I need to put this section within a method separate to the main?
Random diceRoll1 = new Random();
int throw1 = diceRoll1.Next(1, 18);
Random diceRoll2 = new Random();
int throw2 = diceRoll2.Next(1, 12);
Random diceRoll3 = new Random();
int throw3 = diceRoll3.Next(1, 6);
ArrayList rolls = new ArrayList();
int roll1 = Console.WriteLine(throw1 + throw2 + throw3);
Console.ReadLine();
The first thing to note is that you don't need to make a new Random each time you want a random number. Random is seeded from the current time, so it's very likely that the code would run quickly enough that you get three of the same random number. As for adding the values to a list, there are a few different options for this. If you're always going to put items with three grouped values into the list, you could use a Tuple<int, int, int>. Here's an example of that:
Random rnd = new Random();
int throw1 = rnd.Next(1, 18);
int throw2 = rnd.Next(1, 12);
int throw3 = rnd.Next(1, 6);
List<Tuple<int, int, int>> rolls = new List<Tuple<int, int, int>>();
rolls.Add(new Tuple<int, int, int>(throw1, throw2, throw3));
Or, you could have a nested list of integers, replacing the last two lines with:
List<List<int>> rolls = new List<List<int>>();
rolls.Add(new List<int> { throw1, throw2, throw3 });
Finally, you could also use an array:
List<int[]> rolls = new List<int[]>();
rolls.Add(new int[] { throw1, throw2, throw3 });
Another option is to make a custom class which holds your dice roll values (let's call it MultiDiceRoll) and have a list of that (i.e. List<MultiDiceRoll>).
Edit:
If you want to use ArrayList (I would not advise it, for reasons I'll go into), you can do the following:
ArrayList rolls = new ArrayList();
rolls.Add(new int[] { throw1, throw2, throw3 }); // Or whatever other permutation you want
The reason I'd advise not doing this is because the items inside an ArrayList are objects. That is to say, ArrayList doesn't use generics the way a List<T> does. This means that every time you access an item in the list and you want to use it in some way, you have to cast it to the type you want (e.g. (int[])rolls[0]). If you change the type of the list items, you then have a lot of type references you need to clean up and change as well.
You could initialize a list of type of int and add each element into that list. After adding all elements, you can loop through that list and print it.
https://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx

How can I always have a different random phrase selected when using a random? [duplicate]

This question already has answers here:
Randomize a List<T>
(28 answers)
Closed 5 years ago.
I have this code:
public async Task ShowTimedCard()
{
phrase = phrases[(int)AS.rand.Next(phrases.Count)];
It gets a random number and then selects a phrase from phrases which is a List of phrase rows. The List has items added and removed from it by a background process.
Each phrase has an Id field. I cannot remove phrases that I have used from the List for other reasons.
Sometimes ShowTimedCard picks the same phrase twice in a row so I decided to store the lastPhrase information in a static variable like this:
AS.phrase.id = phrase.id
How can I make it so if there are more than 1 items in the phrases List then it will not pick the same phrase twice in a row? I was thinking of some kind of while loop or until loop but not sure how to implement that. I guess it needs to compare the phrase.Id with the AS.phrase.id
Show where you create rand
You should create it just once and reuse it
I bet you are creating new and not enough tick to get a new seed
OK I may have missed the question
Just shuffle the List using Yates shuffle
This is byte but you get the idea
for (byte i = (byte)(count - 1); i >= 1; i--)
{
byte k = (byte)rand.Next(i + 1);
if (k != i)
{ // exchange the values
curVal = deck[i];
deck[i] = deck[k];
deck[k] = curVal;
}
}
Or store the used id in a hashset
Random rand = new Random();
HashSet<int> hs = new HashSet<int>();
int next;
while (hs.Contains(next = rand.Next(12))) { }
hs.Add(next)
Moving target
while (next = rand.Next(12) == lastNext) { }
lastNext = next;
It sounds like what you really want to do is sort the list randomly and then you can just take consecutive items. This will ensure that you don't see any item before all the others have been displayed, but they won't be displayed in the order they were added:
// Shuffle our list of phrases, so they're in a random order
var rnd = new Random();
phrases = phrases.OrderBy(p => rnd.NextDouble()).ToList();
You can then re-shuffle the list anytime you want, like if you add new items or when you've reached the end of the list.
Here's a quick demo using integers:
// Create a list of consecutive integers and display it
var numbers = Enumerable.Range(1, 30).ToList();
Console.WriteLine("Original list:");
Console.WriteLine(string.Join(", ", numbers));
// Shuffle the list and display it again
var rnd = new Random();
numbers = numbers.OrderBy(n => rnd.NextDouble()).ToList();
Console.WriteLine("\nShuffled list:");
Console.WriteLine(string.Join(", ", numbers));
Output

Randomizing images in picture boxes without repeating

I am pretty new in the programming scene and I want to be able to use a button to show random photos in multiple picture boxes. The thing is that I don't want one photo to show in multiple boxes. So every pictureBox should contain different images. I have searched Google for the past few hours but I haven't been able to get any useful information. What I have now, when pressing the button, every pictureBox goes blank. Though here is my code in the button1_Click :
{
List<string> name = new List<string>();
name.Add("0.jpg");
name.Add("1.jpg");
name.Add("2.jpg");
name.Add("3.png");
List<PictureBox> box = new List<PictureBox>();
box.Add(pictureBox1);
box.Add(pictureBox2);
box.Add(pictureBox3);
box.Add(pictureBox4);
a = 4;
ResourceManager rm = MatchGame.Properties.Resources.ResourceManager;
for (int i = 0; i < box.Count; i++)
{
int randomPic = new Random().Next(0, name.Count);
string randomName = name[randomPic];
name.Remove(randomName);
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;`
}
}
An easy way would be to simply shuffle in random order your name list
List<string> name = new List<string>();
name.Add("0.jpg");
name.Add("1.jpg");
name.Add("2.jpg");
name.Add("3.png");
List<PictureBox> box = new List<PictureBox>();
box.Add(pictureBox1);
box.Add(pictureBox2);
box.Add(pictureBox3);
box.Add(pictureBox4);
// 2 lines code for shuffle every kind of IEnumerable
Random r = new Random();
name = name.OrderBy(x => r.Next()).ToList();
ResourceManager rm = MatchGame.Properties.Resources.ResourceManager;
for (int i = 0; i < box.Count; i++)
{
// no need to remove elements from name list
string randomName = name[i];
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;`
}
this will assure that every picture picked once and only once (as long, of course, number of pictureboxes is the same of images stored in resource).
Be sure that every rm.GetObject returns a different image.
As a side note, never create a new Random() within a loop: instantiate a single Random and keep calling .Next on it (see this question). The above code would be wrong in this way:
name = name.OrderBy(x => new Random.Next()).ToList();
What you could do is store the picture references in a Dictionary.
Associating the picture names with the PictureBox indexes - then all you need to do is check the dictionary values and see if the picturename is in the dictionary. If it is in the dictionary - then just let the while loop do another loop - to pick another image. To Recycle that all you would need to do is clear the dictionary and the process could start over again.
Dictionary<int, string> MyActivePictures = new Dictionary<int, string>();
Use a concurrentDictionary if you are multithreading.
// Where MyActivePictures < PictureBoxControl , picturename > is the Dictionary
Dictionary<int, string> MyActivePictures = new Dictionary<int, string>();
// i is your PictureBoxes index as you loop through them
int i = 0;
if(box.Count < name.Length){
do
{
int randomPic = new Random().Next(0, name.Count);
string randomName = name[randomPic];
if(!MyActivePictures.Values.Contains[randomName])
{
name.Remove(randomName);
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;
MyActivePictures[i]=randomName;
i++;
}
if (i > name.Length) // exits the loop in case there are more
{
i = box.Count + 1;
}
}while (i < box.Count);
}
I should add that if it is not possible for the above code to get a unique picture - for example picture boxes > number of images. Then this code will hang in an endless loop. You will need to factor in for that scenario in the while loop - if(the iterator I of pictureboxes value > total images - exit the loop. so if(i > totalimages) exit loop.
I added the additional code to handle this: however
You could just simply include that test in the while condition as well - it is easier ( (i names.Length))

Remove random entry until collection is empty

I'm pretty sure this is something basic but for some reason I just can't seem to get it work. First I'm not sure which Collection Type I should be using. I'm using C# for my Unity game and I'd like to store info like this:
# Name Number Value
1 Jim 15
2 Bob 21
3 Tim 31
4 Ron 26
Numbers 1-4 would be indexes so if I removed entry #3 with Tim, the table would look like:
# Name Number Value
1 Jim 15
2 Bob 21
3 Ron 26
I assume I should be using Dictionaries and that's what I tried. What I want to do with my code is to pick a random element, print it and then remove it. Rinse and repeat until the list is empty.
This is what I've been using for my code:
Dictionary<String, int> myDictionary = new Dictionary<String, int> ();
void Start()
{
myDictionary.Add ("Jim", 15);
myDictionary.Add ("Bob", 21);
myDictionary.Add ("Tim", 31);
myDictionary.Add ("Ron", 26);
}
void Update()
{
int totalEntries = myDictionary.Count;
int randNumber = Random.Range(1,totalEntries);
print(myDictionary[randNumber]);
myDictionary.Remove(randNumber);
}
It's not working. I've seen some suggestions about using RemoveAt or using HashTable but I haven't been able to get those working either. RemoveAt for some reason isn't recognized as a command and HashTable just kind of had the same issue. I am using "using System.Collections.Generic;" btw so that's not the problem. I'd like to mention that I'm pretty new to C# so what would help me the most would be actual working code that I can then edit to fit my game.
A Dictionary would not be ideal in this case.
I'd use a List of Tuples (or a List of a custom class).
List<Tuple<int, String, int>> myItems = new List<Tuple<int, String, int>>();
void Start()
{
myItems.Add(Tuple.Create(1, "Jim", 15));
myItems.Add(Tuple.Create(2, "Bob", 21));
myItems.Add(Tuple.Create(3, "Tim", 31));
myItems.Add(Tuple.Create(4, "Ron", 26));
}
Now there are a couple of ways to identify the object you wish to remove. First your initial approach (by index in the list):
void Update()
{
var rnd = new Random();
var randNumber = rnd.Next(0, myItem.Count);
myItems.Remove(myItems.ElementAt(randNumber));
}
Then by the actual value of the object:
void Update2()
{
var minValue = myItems.Min(i => i.Item1); // Gets the minimum value in first column (so to speak);
var maxValue = myItems.Max(i => i.Item1); // Gets the maximum value.
var rnd = new Random();
var randNumber = rnd.Next(minValue, maxValue + 1); // maximum value in Random.Next is exclusive.
var myObject = myItems.SingleOrDefault(o => o.Item1 == randNumber);
if (myObject != null)
myItems.Remove(myObject);
}
Which method you prefer is up to you and the requirements to solve the task. You might prefer by index but on the other hand you might prefer removing by value.
The drawback by the second method is that you might not remove an object at all when the random value is already removed.
Try this:
using System.Linq;
var r = new Random();
var i = r.Next(0, dic.Count);
var e = dic.ElementAt(i)
dic.Remove(e);
create an array with the same length, and out in each cell a number 1 to N. and shuffle the array. then delete each row by index
I ended up finding this link: http://wiki.unity3d.com/index.php/Choosing_the_right_collection_type
And have been able to solve my issue with ArrayLists. This is the part of the link that really helped me:
ArrayList myArrayList = new ArrayList(); // declaration
myArrayList.Add(anItem); // add an item to the end of the array
myArrayList[i] = newValue; // change the value stored at position i
TheType thisItem = (TheType) myArray[i]; // retrieve an item from position i
myArray.RemoveAt(i); // remove an item from position i
var howBig = myArray.Count; // get the number of items in the ArrayList
Thanks everyone for all the sugestions!

Categories

Resources