Creating a random order for my quiz questions - c#

I have created a quiz application and was using a switch statement to work my way through the questions. i.e. going from 1 to 2 to 3 to 4 and so on.
However, once the user has completed the quiz once and wanted to start again, they would have to go through all the same questions all over again. (the design is that if they get one wrong, the application exits).
Therefore, I wanted to see if there was a way to either randomize the number for the QuestionCount (but only have this number generated once) or another way I could do it.
I can see there are suggestions in using a list but these seem to concentrate on large numbers contained in the list whereas mine currently will only be 20 questions long.
I have copied the code I am using currently.
private void Verify(int Question)
{
switch (Question)
{
case 1:
if (checkBox1.Checked && !checkBox2.Checked && !checkBox3.Checked && !checkBox4.Checked)
{
MessageBox.Show("Correct - Well Done");
//This was a test to see if I could assign a random number which works but the number could then appear again meaning the user gets the same question
Random random = new Random();
QuestionCount = random.Next(0, 21);
QuestionSelection(QuestionCount);
//SelectLabel(QuestionCount);
ClearcheckBox();
}
else
{
MessageBox.Show("No - It was Sunguard");
Application.Exit();
}
break;
case 2:
if (checkBox3.Checked && !checkBox2.Checked && !checkBox1.Checked && !checkBox4.Checked)
{
//this method was the original where it just adds 1 to QuestionCount and works it way through the switch statement for the questions.
MessageBox.Show("Correct - Well Done");
QuestionCount++;
QuestionSelection(QuestionCount);
//SelectLabel(QuestionCount);
ClearcheckBox();
}
else
{
MessageBox.Show("No - It's to look at a students details");
Application.Exit();
}
}
}

To make sure that each question is only asked once I would use two Lists: AnsweredQuestions and UnansweredQuestions.
At the beginning AnsweredQuestions is empty, UnansweredQuestions contains all questions to be asked.
Now you can you the randomizer like you already have it in your code above. As the max vlaue for the random.Next() you take the current item Count of the UnansweredQuestions list.
After the question was answered correctly, you can remove it from the UnansweredQuestions list and put it into the AnsweredQuestions list.
This way your randomizer only uses those questions that really are unanswered.

Why don't you put all questions in a List, and shuffle it:
public List<T> RandomPermutation<T>(List<T> array)
{
Random random = new Random();
List<T> retArray = new List<T>(array);
int maxIndex = array.Count - 1;
for (int i = 0; i <= maxIndex; i++)
{
int swapIndex = random.Next(i, maxIndex);
if (swapIndex != i)
{
T temp = retArray[i];
retArray[i] = retArray[swapIndex];
retArray[swapIndex] = temp;
}
}
return retArray;
}

If you only have a small number of possible values you can encode the choices as bit flags in a Uint64. I've added an example below that does it.
I use a BitArray for convenience. It would be better to use bit-wise & and | operators.
The result is packed into one UInt64, but it could as easily have been two separate Uint32 for flags and value.
private static UInt64 Next(UInt64 current, int questions)
{
// Convert the current value to an array of bytes.
// Remove the least significant 4 bytes.
// and then create a flag array.
var bytes = BitConverter.GetBytes(current);
bytes[0] = bytes[1] = bytes[2] = bytes[3] = 0;
var flags = new BitArray(bytes);
// If all questions has been answered then exit with 0.
var all = Enumerable.Range(32, questions).All(flags.Get);
if (all)
return 0UL;
// Make a random next value, if the value has been used then repeat.
var random = new Random(DateTime.Now.Millisecond);
var next = random.Next(questions);
while (flags.Get(next + 32))
next = random.Next(questions);
// set the flag value for the guess.
flags.Set(next + 32, true);
// convert the flags back to Uint64 and add the next value.
flags.CopyTo(bytes, 0);
return BitConverter.ToUInt64(bytes, 0) + Convert.ToUInt64(next);
}
Test with:
var first = Next(0UL, 20);
while (first != 0UL)
{
var v = first & 0xFFFFFFFF;
Console.Out.WriteLine(v);
first = Next(first, 20);
}

Related

How to check and change the values in an array in C#?

I'm working on a very simple tic tac toe project where I check if a user input is in an array (looking for an integer from 1 to 9) and, if not, I want to change an index to that user input. Below is code, don't know what I'm doing wrong. CallSquare() returns an int.
int [] numbersPlayed = {0,0,0,0,0,0,0,0,0};
int callResult;
int totalPlayed = 0;
while (totalPlayed != 10)
{
callResult = CallSquare();
foreach (int i in numbersPlayed)
{
if (numbersPlayed.Contains(callResult))
{
Console.WriteLine("\n\nError, number already in array");
break;
}
else
{
numbersPlayed.SetValue(callResult, i);
}
}
totalPlayed++;
}
Basically, what it does after input is giving me the Error message above, even though I type an integer between 1 and 9, and then, only changes the value in the index number I have entered on the first input (for example, if I enter 1 on the first input, it will only change the first index on following inputs). Help please?
Edit: what I'm trying to do is to keep a record of the numbers that have been played. I figured an array like that was the way to go, but if you have a better solution, I'm listening.
I think, you'd be better off using a List:
List<int> numbersPlayed = new List<int>();
int callResult;
int totalPlayed = 0;
while (totalPlayed < 10)
{
callResult = CallSquare();
if( numbersPlayed.Contains(callResult) )
{
Console.WriteLine("\n\nError, number already in array");
}
else
{
numbersPlayed.Add(callResult);
}
totalPlayed++;
}

Best way to choose two random ints to assign values to

I am creating a Dungeons and Dragons Character Creator. There is a randomize feature that is going to create a complete character sheet. There is a part that I have gotten to and I am not quite sure the best way to proceed.
The way I have the racial modifiers set up is with if statements. Here is an example.
if (raceInt == 0 || raceInt == 2 || raceInt == 10)
{
raceStrMod = 2;
}
if (raceInt == 3 || raceInt == 4 || raceInt == 5 || raceInt == 11 || raceInt == 12)
{
raceDexMod = 2;
}
However there are races that have modifiers that let you select two stats to add a modifier to, such as Strength or Dexterity. What would be the best way to select two random ints for just those races?
For example, the half-elf race which would get +2 to Dex and then +1 to two other random stats. So I need to find a way to randomly select two of the remaining ints to make the value = 1.
My race mod ints are initialized as
int raceStrMod = 0;
int raceDexMod = 0;
int raceConMod = 0;
int raceIntMod = 0;
int raceWisMod = 0;
int raceChaMod = 0;
Then the if statements assign a value dependent on which race was randomly selected.
Thank you all for the input! This is how I ended up coding it
if (raceInt == 9)
{
int randomX = rnd.Next(1, 5);
int randomY = rnd.Next(1, 5);
int attempts = 0;
while (randomX == randomY && attempts < 10)
{
randomY = rnd.Next(1, 5);
attempts++;
}
//if they are still not unique after 10 attempts
if (randomX == randomY)
{
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
}
int[] randomNumbers = { randomX, randomY };
foreach (int i in randomNumbers)
{
switch (i)
{
case 1:
raceStrMod = 1;
break;
case 2:
raceDexMod = 1;
break;
case 3:
raceConMod = 1;
break;
case 4:
raceIntMod = 1;
break;
case 5:
raceWisMod = 1;
break;
}
}
}
Has your class introduced you to enum types yet? If not, is there any restriction on your final project with respect to using language features that weren't taught in the class?
Your question is arguably too broad, as there are many different ways to address this sort of thing even in real-world code, and the classroom context introduces potential roadblocks that while might constrain the question, being unknown they make it impossible to know what answer is actually going to work for you.
That said…
Ignoring the classroom aspect and focusing only on the problem itself, I would use enum types and dictionaries for this sort of thing. For example:
enum Attribute
{
Strength,
Dexterity,
Constitution,
Charisma,
Intelligence,
Wisdom,
Count, // must always be last
}
Dictionary<Attribute, int> modifiers = new Dictionary<Attribute, int>();
Then you can pick a random attribute like (assuming you have a random variable referencing a Random object…don't make the classic newbie mistake of creating a new Random object every time you want to pick a new random number):
Attribute attributeToModify = (Attribute)random.Next((int)Attribute.Count);
And you can store that selection like:
modifiers[attributeToModify] = 1;
This can be used to store however many modifiers you like. You can encapsulate that in an object representing the character itself, or you could put it into a separate AttributeModifiers class. One advantage of doing the latter would be that if you have modifiers that come from different sources, you can track that in the character object as a list of AttributeModifier instances, each in turn keeping track of what the actual source of those modifiers are.
This just barely scratches the surface. As I noted, the question itself is fairly broad. But I strongly recommend using the available language features to ensure that your variables represent things in a type-specific way, rather than just using int values for things that aren't really integers, and to use collection classes that more correctly represent the semantics of what your code is intended to do.
Note that this also means you probably should have an enum type for the races. E.g.:
enum Race
{
Dwarf,
Elf,
HalfElf,
Halfling,
HalfOrc,
Human,
// etc.
}
And your chain of if statements is probably better represented as a switch:
Attribute racialMod;
switch (race)
{
case Human:
case Halfling:
// etc.
racialMod = Attribute.Strength;
break;
case Elf:
case HalfElf:
// etc.
racialMod = Attribute.Dexterity;
break;
}
modifiers[racialMod] = 2;
Something like that. The point is to make sure the code reads more like what the original specification would say (if you actually had written one). This will make the code easier to understand, and it will be less likely for you to put bugs in the code (e.g. you accidentally type the wrong magic, unnamed integer).
I am creating a Dungeons and Dragons Character Creator.
That's a fun beginner project; I did the same when I was learning to program.
I need to find a way to randomly select two of the remaining...
You need to find two distinct values, call then x and y. The solution you've arrived at is:
Generate x
Try to generate y ten times
If no attempt succeeded to find a distinct y, hard-code a choice.
That works, and you almost never have to use the hard-coded choice. But I thought you might be interested to know that there is an easier way to generate two distinct numbers. Let's suppose we want two distinct numbers from 0, 1, 2, 3 or 4. (Obviously if you want a different range, say, 1 through 5, you can solve that problem by generating two distinct numbers 0->4 and then adding one to each.)
The improved algorithm is:
Choose x between 0 and 4 as usual.
Choose n between 1 and 4.
y = (x + n) % 5;
Think about it this way. Suppose we make a list like this:
0, 1, 2, 3, 4, 0, 1, 2, 3
We randomly choose x from the first five entries on the list, and then we choose y by stepping forwards between 1 and 4 steps. Since the list does not repeat in one to four steps, we know that we'll get two unique elements. The math does the equivalent of that.
You could similarly have used % in your program:
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
could be written
randomY = randomX % 5 + 1
If you're unfamiliar with %, it is the remainder operator. It is the complement of the / operator. The rule is:
int x = whatever;
int y = whatever;
int r = x % y;
is the same as:
int r = x - (x / y) * y;
That is, it is the remainder when x is divided by y. Keep in mind that the remainder can be negative!
(Disclaimer: I don't love this option, but couldn't think of another way other than reflection which is even nastier)
You could define a class that masks the fact that all of the mods are stored as an array and therefore can be indexed using a random number.
Something like the following:
public class StatMods
{
public int RaceStrMod { get { return this.mods[0]; } set { this.mods[0] = value; } }
public int RaceDexMod { get { return this.mods[1]; } set { this.mods[1] = value; } }
public int RaceConMod { get { return this.mods[2]; } set { this.mods[2] = value; } }
public int RaceIntMod { get { return this.mods[3]; } set { this.mods[3] = value; } }
public int RaceWisMod { get { return this.mods[4]; } set { this.mods[4] = value; } }
public int RaceChaMod { get { return this.mods[5]; } set { this.mods[5] = value; } }
private readonly int[] mods;
private static readonly Random rand = new Random();
public StatMods()
{
this.mods = new int[6];
}
public void ApplyRandomMod(int modification)
{
this.mods[rand.Next(0, 6)] += modification;
}
}

Creating 1000 arrays and sorting them using the bubble and selection sort (C#) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am new to programming. C# is my first programming language.
I have an assignment where I have to create and test out a bubble sort algorithm and a selection sort algorithm using arrays. I think I understand those now.
The next part of the assignment I am having some trouble on.
I have to write a program that will ask the user for a number (n) and create 1000 arrays of n size.
So if the user enters 5 for the number, my program has to create and sort 1000 arrays that are of length 5.
I have to use the bubble sort and the selection sort methods I created.
After I do that, I have to initiate a variable called running_time to 0. I have to create a for loop that iterates 1000 times and in the body of the loop i have to create an array of n random integers.
Then I have to get the time and set this to the start time. My professor said to notice that the sort is started after each array is built, so I should time the sort process only.
Then I have to get the time and set it to end time. I have to subtract the start time from end time and add the result to the total time.
Once the program has run, note
1. the number of items sorted
2. the average running time for each array (total time/1000)
Then I have to repeat the process using 500, 2500, and 5000 as the size of the array.
This is my code for creating one array with n number of spaces and filled with random integers.
//Asks the user for number
Console.WriteLine("Enter a number: ");
n = Convert.ToInt32(Console.ReadLine());
//Creates an array of the length of the user entered number
int[] randArray = new int[n];
//Brings in the random class so we can use it.
Random r = new Random();
Console.WriteLine("This is the array: ");
//For loop that will put in a random number for each spot in the array.
for (int i = 0; i < randArray.Length; i++) {
randArray[i] = r.Next(n);
Console.Write(randArray[i] + " ");
}
Console.WriteLine();
THIS IS MY CODE FOR THE BUBBLE SORT ALGORITHM:
//Now performing bubble sort algorithm:
for (int j = 0; j <= randArray.Length - 2; j++) {
for (int x = 0; x <= randArray.Length - 2; x++) {
if (randArray[x] > randArray[x + 1]) {
temp = randArray[x + 1];
randArray[x + 1] = randArray[x];
randArray[x] = temp;
}
}
}
//For each loop that will print out the sorted array
foreach (int array in randArray) {
Console.Write(array + " ");
}
Console.WriteLine();
THIS IS MY CODE FOR THE SELECTION SORT ALGORITHM:
//Now performing selection sort algorithm
for (int a = 0; a < randArray1.Length - 1; a++) {
minkey = a;
for (int b = a + 1; b < randArray1.Length; b++) {
if (randArray1[b] < randArray1[minkey]) {
minkey = b;
}
}
tempSS = randArray1[minkey];
randArray1[minkey] = randArray1[a];
randArray1[a] = tempSS;
}
//For loop that will print the array after it is sorted.
Console.WriteLine("This is the array after the selection sort algorithm.");
for (int c = 0; c < randArray1.Length; c++) {
Console.Write(randArray1[c] + " ");
}
Console.WriteLine();
This is very overwhelming as I am new to this and I am still learning this language.
Can someone guide me on the beginning on how to create 1000 different arrays filled with random numbers and then the rest. I would appreciate it greatly. Thank you.
So you have a several questions that has overwhelmed you.
Let's look at each one
Take user input
Console.WriteLine("Enter a length");
while (!int.TryParse(Console.ReadLine(), out var length))
Console.WriteLine("omg! you had one job");
Calling a method with an out argument
Starting with C# 7.0, you can declare the out variable in the argument
list of the method call, rather than in a separate variable
declaration. This produces more compact, readable code, and also
prevents you from inadvertently assigning a value to the variable
before the method call. The following example is like the previous
example, except that it defines the number variable in the call to the
Int32.TryParse method.
Fill Array
private static Random _rand = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
...
public static string RandomString(int length)
{
var result = Enumerable.Range(0, length)
.Select(s => chars[_rand.Next(length)])
.ToArray();
return new string(result);
}
Create array of random chars
var arr = Enumerable.Range(0, size)
.Select(i => RandomString(length)).ToArray();
How to time something
var sw = Stopwatch.StartNew();
// something to time
var milliseconds = sw.ElapsedMilliseconds
Now map it all together, I'll leave these details up to you
Additional Resources
Enumerable.Range(Int32, Int32) Method
Generates a sequence of integral numbers within a specified range.
Enumerable.Select Method
Projects each element of a sequence into a new form.
Stopwatch Class
Provides a set of methods and properties that you can use to
accurately measure elapsed time.
Random Class
Represents a pseudo-random number generator, which is a device that
produces a sequence of numbers that meet certain statistical
requirements for randomness.

Shuffling a string so that no two adjacent letters are the same

I've been trying to solve this interview problem which asks to shuffle a string so that no two adjacent letters are identical
For example,
ABCC -> ACBC
The approach I'm thinking of is to
1) Iterate over the input string and store the (letter, frequency)
pairs in some collection
2) Now build a result string by pulling the highest frequency (that is > 0) letter that we didn't just pull
3) Update (decrement) the frequency whenever we pull a letter
4) return the result string if all letters have zero frequency
5) return error if we're left with only one letter with frequency greater than 1
With this approach we can save the more precious (less frequent) letters for last. But for this to work, we need a collection that lets us efficiently query a key and at the same time efficiently sort it by values. Something like this would work except we need to keep the collection sorted after every letter retrieval.
I'm assuming Unicode characters.
Any ideas on what collection to use? Or an alternative approach?
You can sort the letters by frequency, split the sorted list in half, and construct the output by taking letters from the two halves in turn. This takes a single sort.
Example:
Initial string: ACABBACAB
Sort: AAAABBBCC
Split: AAAA+BBBCC
Combine: ABABABCAC
If the number of letters of highest frequency exceeds half the length of the string, the problem has no solution.
Why not use two Data Structures: One for sorting (Like a Heap) and one for key retrieval, like a Dictionary?
The accepted answer may produce a correct result, but is likely not the 'correct' answer to this interview brain teaser, nor the most efficient algorithm.
The simple answer is to take the premise of a basic sorting algorithm and alter the looping predicate to check for adjacency rather than magnitude. This ensures that the 'sorting' operation is the only step required, and (like all good sorting algorithms) does the least amount of work possible.
Below is a c# example akin to insertion sort for simplicity (though many sorting algorithm could be similarly adjusted):
string NonAdjacencySort(string stringInput)
{
var input = stringInput.ToCharArray();
for(var i = 0; i < input.Length; i++)
{
var j = i;
while(j > 0 && j < input.Length - 1 &&
(input[j+1] == input[j] || input[j-1] == input[j]))
{
var tmp = input[j];
input[j] = input[j-1];
input[j-1] = tmp;
j--;
}
if(input[1] == input[0])
{
var tmp = input[0];
input[0] = input[input.Length-1];
input[input.Length-1] = tmp;
}
}
return new string(input);
}
The major change to standard insertion sort is that the function has to both look ahead and behind, and therefore needs to wrap around to the last index.
A final point is that this type of algorithm fails gracefully, providing a result with the fewest consecutive characters (grouped at the front).
Since I somehow got convinced to expand an off-hand comment into a full algorithm, I'll write it out as an answer, which must be more readable than a series of uneditable comments.
The algorithm is pretty simple, actually. It's based on the observation that if we sort the string and then divide it into two equal-length halves, plus the middle character if the string has odd length, then corresponding positions in the two halves must differ from each other, unless there is no solution. That's easy to see: if the two characters are the same, then so are all the characters between them, which totals ⌈n/2⌉&plus;1 characters. But a solution is only possible if there are no more than ⌈n/2⌉ instances of any single character.
So we can proceed as follows:
Sort the string.
If the string's length is odd, output the middle character.
Divide the string (minus its middle character if the length is odd) into two equal-length halves, and interleave the two halves.
At each point in the interleaving, since the pair of characters differ from each other (see above), at least one of them must differ from the last character output. So we first output that character and then the corresponding one from the other half.
The sample code below is in C++, since I don't have a C# environment handy to test with. It's also simplified in two ways, both of which would be easy enough to fix at the cost of obscuring the algorithm:
If at some point in the interleaving, the algorithm encounters a pair of identical characters, it should stop and report failure. But in the sample implementation below, which has an overly simple interface, there's no way to report failure. If there is no solution, the function below returns an incorrect solution.
The OP suggests that the algorithm should work with Unicode characters, but the complexity of correctly handling multibyte encodings didn't seem to add anything useful to explain the algorithm. So I just used single-byte characters. (In C# and certain implementations of C++, there is no character type wide enough to hold a Unicode code point, so astral plane characters must be represented with a surrogate pair.)
#include <algorithm>
#include <iostream>
#include <string>
// If possible, rearranges 'in' so that there are no two consecutive
// instances of the same character.
std::string rearrange(std::string in) {
// Sort the input. The function is call-by-value,
// so the argument itself isn't changed.
std::string out;
size_t len = in.size();
if (in.size()) {
out.reserve(len);
std::sort(in.begin(), in.end());
size_t mid = len / 2;
size_t tail = len - mid;
char prev = in[mid];
// For odd-length strings, start with the middle character.
if (len & 1) out.push_back(prev);
for (size_t head = 0; head < mid; ++head, ++tail)
// See explanatory text
if (in[tail] != prev) {
out.push_back(in[tail]);
out.push_back(prev = in[head]);
}
else {
out.push_back(in[head]);
out.push_back(prev = in[tail]);
}
}
}
return out;
}
you can do that by using a priority queue.
Please find the below explanation.
https://iq.opengenus.org/rearrange-string-no-same-adjacent-characters/
Here is a probabilistic approach. The algorithm is:
10) Select a random char from the input string.
20) Try to insert the selected char in a random position in the output string.
30) If it can't be inserted because of proximity with the same char, go to 10.
40) Remove the selected char from the input string and go to 10.
50) Continue until there are no more chars in the input string, or the failed attempts are too many.
public static string ShuffleNoSameAdjacent(string input, Random random = null)
{
if (input == null) return null;
if (random == null) random = new Random();
string output = "";
int maxAttempts = input.Length * input.Length * 2;
int attempts = 0;
while (input.Length > 0)
{
while (attempts < maxAttempts)
{
int inputPos = random.Next(0, input.Length);
var outputPos = random.Next(0, output.Length + 1);
var c = input[inputPos];
if (outputPos > 0 && output[outputPos - 1] == c)
{
attempts++; continue;
}
if (outputPos < output.Length && output[outputPos] == c)
{
attempts++; continue;
}
input = input.Remove(inputPos, 1);
output = output.Insert(outputPos, c.ToString());
break;
}
if (attempts >= maxAttempts) throw new InvalidOperationException(
$"Shuffle failed to complete after {attempts} attempts.");
}
return output;
}
Not suitable for strings longer than 1,000 chars!
Update: And here is a more complicated deterministic approach. The algorithm is:
Group the elements and sort the groups by length.
Create three empty piles of elements.
Insert each group to a separate pile, inserting always the largest group to the smallest pile, so that the piles differ in length as little as possible.
Check that there is no pile with more than half the total elements, in which case satisfying the condition of not having same adjacent elements is impossible.
Shuffle the piles.
Start yielding elements from the piles, selecting a different pile each time.
When the piles that are eligible for selection are more than one, select randomly, weighting by the size of each pile. Piles containing near half of the remaining elements should be much preferred. For example if the remaining elements are 100 and the two eligible piles have 49 and 40 elements respectively, then the first pile should be 10 times more preferable than the second (because 50 - 49 = 1 and 50 - 40 = 10).
public static IEnumerable<T> ShuffleNoSameAdjacent<T>(IEnumerable<T> source,
Random random = null, IEqualityComparer<T> comparer = null)
{
if (source == null) yield break;
if (random == null) random = new Random();
if (comparer == null) comparer = EqualityComparer<T>.Default;
var grouped = source
.GroupBy(i => i, comparer)
.OrderByDescending(g => g.Count());
var piles = Enumerable.Range(0, 3).Select(i => new Pile<T>()).ToArray();
foreach (var group in grouped)
{
GetSmallestPile().AddRange(group);
}
int totalCount = piles.Select(e => e.Count).Sum();
if (piles.Any(pile => pile.Count > (totalCount + 1) / 2))
{
throw new InvalidOperationException("Shuffle is impossible.");
}
piles.ForEach(pile => Shuffle(pile));
Pile<T> previouslySelectedPile = null;
while (totalCount > 0)
{
var selectedPile = GetRandomPile_WeightedByLength();
yield return selectedPile[selectedPile.Count - 1];
selectedPile.RemoveAt(selectedPile.Count - 1);
totalCount--;
previouslySelectedPile = selectedPile;
}
List<T> GetSmallestPile()
{
List<T> smallestPile = null;
int smallestCount = Int32.MaxValue;
foreach (var pile in piles)
{
if (pile.Count < smallestCount)
{
smallestPile = pile;
smallestCount = pile.Count;
}
}
return smallestPile;
}
void Shuffle(List<T> pile)
{
for (int i = 0; i < pile.Count; i++)
{
int j = random.Next(i, pile.Count);
if (i == j) continue;
var temp = pile[i];
pile[i] = pile[j];
pile[j] = temp;
}
}
Pile<T> GetRandomPile_WeightedByLength()
{
var eligiblePiles = piles
.Where(pile => pile.Count > 0 && pile != previouslySelectedPile)
.ToArray();
Debug.Assert(eligiblePiles.Length > 0, "No eligible pile.");
eligiblePiles.ForEach(pile =>
{
pile.Proximity = ((totalCount + 1) / 2) - pile.Count;
pile.Score = 1;
});
Debug.Assert(eligiblePiles.All(pile => pile.Proximity >= 0),
"A pile has negative proximity.");
foreach (var pile in eligiblePiles)
{
foreach (var otherPile in eligiblePiles)
{
if (otherPile == pile) continue;
pile.Score *= otherPile.Proximity;
}
}
var sumScore = eligiblePiles.Select(p => p.Score).Sum();
while (sumScore > Int32.MaxValue)
{
eligiblePiles.ForEach(pile => pile.Score /= 100);
sumScore = eligiblePiles.Select(p => p.Score).Sum();
}
if (sumScore == 0)
{
return eligiblePiles[random.Next(0, eligiblePiles.Length)];
}
var randomScore = random.Next(0, (int)sumScore);
int accumulatedScore = 0;
foreach (var pile in eligiblePiles)
{
accumulatedScore += (int)pile.Score;
if (randomScore < accumulatedScore) return pile;
}
Debug.Fail("Could not select a pile randomly by weight.");
return null;
}
}
private class Pile<T> : List<T>
{
public int Proximity { get; set; }
public long Score { get; set; }
}
This implementation can suffle millions of elements. I am not completely convinced that the quality of the suffling is as perfect as the previous probabilistic implementation, but should be close.
func shuffle(str:String)-> String{
var shuffleArray = [Character](str)
//Sorting
shuffleArray.sort()
var shuffle1 = [Character]()
var shuffle2 = [Character]()
var adjacentStr = ""
//Split
for i in 0..<shuffleArray.count{
if i > shuffleArray.count/2 {
shuffle2.append(shuffleArray[i])
}else{
shuffle1.append(shuffleArray[i])
}
}
let count = shuffle1.count > shuffle2.count ? shuffle1.count:shuffle2.count
//Merge with adjacent element
for i in 0..<count {
if i < shuffle1.count{
adjacentStr.append(shuffle1[i])
}
if i < shuffle2.count{
adjacentStr.append(shuffle2[i])
}
}
return adjacentStr
}
let s = shuffle(str: "AABC")
print(s)

How to use the C# random method most effectively? [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 9 years ago.
I have been able to use the random method to accomplish most of my tasks in trying to populate labels and RadioButtonList Items randomly to create a 5 question quiz.
The code generates a good blend of questions given the large pool it draws from.
However, the inner code for randomly populating the RadioButtonList Items is acting funny.
When I throw in breakpoints at my while loop and run it step by step the answers are populated in different order on every next question.
But when I simply open up the browser and run it from the Sharepoint website I have it deployed to,
the answers follow the same order sequence on every next question/all questions.
Note: It does however throw unique orders on page refresh; in other words when I start the quiz again.
I cant seem to figure out the hitch for the life of me.
Could use a few sets of eyes.
Here is the code thus far: Please advise
public void LoadQuestions()
{
try
{
SPWeb thisWeb = SPContext.Current.Web;
SPList oSPList = thisWeb.Lists["QuestionsAndAnswers"];
SPListItemCollection oSPListItemCollection = oSPList.Items;
Random rand = new Random();
List<int> tempStore = new List<int>();
List<int> tempStore2 = new List<int>();
int tempValue = 0;
//int tempValue2 = 0;
int icount = 1;
int iMax = oSPListItemCollection.Count;
//int icount2 = 0;
//int iMax2 = oSPListItemCollection.Count;
SPListItem thisItem;
Label thisQuestion;
Label thisCorrectAnswer;
RadioButtonList thisAnswers;
while (icount < 6)
{
tempValue = rand.Next(1, iMax);
if (tempStore.Exists(value => value == tempValue))
continue;
else
{
tempStore.Add(tempValue);
thisQuestion = (Label)UpdatePanelMaster.FindControl("Question" + icount.ToString());
thisItem = oSPListItemCollection[tempValue];
thisQuestion.Text = icount + ". " + thisItem["Question"].ToString();
thisCorrectAnswer = (Label)UpdatePanelMaster.FindControl("CorrectAnswer" + icount.ToString());
thisCorrectAnswer.Text = thisItem["CorrectAnswer"].ToString();
thisAnswers = (RadioButtonList)UpdatePanelMaster.FindControl("RadioButtonList" + icount.ToString());
//Entering code to handle random answer arrangements
//This code works ok when run in a step by step debug fashion but no when deployed and run from the website directly.
Missing/Changes required?
int tempValue2;
int Icounter = 0;
string[] AnswerArr = new string[] { thisItem["CorrectAnswer"].ToString(), thisItem["IncorrectAnswer1"].ToString(), thisItem["IncorrectAnswer2"].ToString(), thisItem["IncorrectAnswer3"].ToString() };
Random rand2 = new Random();
while (Icounter < 4)
{
tempValue2 = rand2.Next(0, 13);//max number of items in the array
decimal toCeilingVar = tempValue2 / 4;
int fraction = Convert.ToInt32(System.Math.Ceiling(toCeilingVar));
string tempArrValue = AnswerArr[fraction];
if (thisAnswers.Items.FindByValue(tempArrValue) == null)
{
//add new value because the current value is not in the list
thisAnswers.Items.Add(tempArrValue);
Icounter++;
tempArrValue = string.Empty;
}
tempValue2 = 0;
toCeilingVar = 0;
fraction = 0;
//End Random Answer handling
}
tempValue = 0;
icount++;
}
}
}
//End random question handling
catch (Exception ex)
{
throw ex;
}
}
The problem is (inside the loop):
Random rand2 = new Random();
The Random class is, if no explicit seed is provided, seeded using the time. If you create multiple instances in a tight loop, they will often be close enough (in time) together that they have the same seed. This means they will all generate the same sequence of pseudo-random numbers. Two options:
lose the inner Random instance (rand2) completely - just use the single outer instance (rand); using more Random instances does not increase the randomness
use the outer instance to seed the inner instance
I'd only use the latter if there was a good reason, for example parallelism
Probably what is happening here is that when run in production, the line Random rand2 = new Random() is called several times in a very short interval of time, so each instance will have the same initial seed value. The default constructor for Random uses a time-based seed with fairly low resolution in my experience.
To solve this, I would just use the single rand variable to generate all random numbers, or initialize rand2 outside the outermost loop.

Categories

Resources