Random Integer, no repeat, within specific range - c#

Detailed scenario:
There are 300 possible numbers that fit into the discription.
That is, the number must between 1123 and 5543 inclusive
The number is unique and not repeated
The number only has the integers 1,2,3,4 and 5.
What I am trying to achieve is a program that can display all those numbers at once in ascending order.
My current code:
var chars = "12345";
var stringChars = new char[4];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
Console.WriteLine(finalString)
This code works fine, but I have 2 additional requirements.
Loop 300 times
Display all results in ascending order
EDIT:
Sorry for all confusion. What this code produces is a 4 digit number like I want. But I want to it to do so 300 times. I guess I can use a Loop, but this is my first time using C# (I've only used vb.net in the past). What I mean by random and in ascending order is: Produce a random number, and when all numbers are generated, order them in ascending order before displaying them all.
However, if ordering them will be too complicated, then I'm fine without that.

It's not entirely clear what you're asking, but here is some code that will print the 611 (not 300) numbers matching the description you gave in ascending order.
If I've understood your question correctly, you will want to sample 300 distinct elements from this larger set, sort them, and them print them out. You might look at using a Fisher-Yates shuffle to do this. Shuffle the list, take the first 300, and sort them.
public static void Main (string[] args) {
var digits = new [] { 1, 1, 2, 3 };
for (var num = DigitsToInt(digits); num <= 5543; num = DigitsToInt(digits)) {
Console.WriteLine(num);
for (int i = 3; i >= 0; i--) {
digits[i]++;
if (digits[i] < 6) {
break;
} else {
digits[i] = 1;
}
}
}
}
private static int DigitsToInt(int[] digits) {
return 1000 * digits[0] + 100 * digits[1] + 10 * digits[2] + digits[3];
}

Related

How to scan every value in an array and compare it to every value in another array?

I'm new to the programming world and I would appreciate some help to finish an exercise.
Exercise goal: User guesses 10 numbers. The numbers are then stored in an array. Array is called
"userGussedNumbers" in my program(it's not included down below). Then the program will
generate 4 random numbers and store in an array "generatedWinningNumber". Now the program
will compare the arrays and displays matches.
Problem i have: How do I compare both of these arrays and print out the winning numbers? There will be 4
winning numbers. You can see my solution down below but it stops when it gets the first
match. I want it to keep scanning for more matches and display all matches if any matches
found ofc.
private static void Main()
{
Random randomNumber = new Random();
int[] generatedWinningNumber = new int[4];
int temp;
// Console.WriteLine("\nThese are the winning number...");
for (int i = 0; i<generatedWinningNumber.Length; i++)
{
temp = randomNumber.Next(1, 26);
generatedWinningNumber[i] = temp;
if (userGussedNumbers.Intersect(generatedWinningNumber).Any())
{
Console.WriteLine("\n Number {0} matched", userGussedNumbers[i]);
}
else
{
Console.WriteLine("No match!");
}
}
}
If I understand your question correctly, you are saying that if one value is guessed correctly then all of them say they were guessed correctly.
I believe this is due to the .Intersect(...).Any(). I am not an expert on this function, but I believe it is returning true if any value in the arrays match. Perhaps just use .Contains() from System.Linq
using System.Linq;
Random randomNumber = new Random();
//int[] userGuessedNumbers = new int[10] { 9, 2, 15, 4, 11, 6, 7, 8, 2, 10 };
int[] generatedWinningNumber = new int[4];
for (int i = 0; i < generatedWinningNumber.Length; i++)
{
//Removed unnecessary temp
generatedWinningNumber[i] = randomNumber.Next(1, 26);
//An easier way to format most strings in C# is by using $"string here {variablesHere}"
if (userGuessedNumbers.Contains(generatedWinningNumber[i]))
Console.WriteLine($"\nNumber {generatedWinningNumber[i]} matched!");
else
Console.WriteLine($"\nNo match to {generatedWinningNumber[i]}!");
}
The Intersect method will give you a sequence with all the current winning numbers, so you can also try something like this.
Random randomNumber = new Random();
int[] generatedWinningNumber = new int[4];
for (int i = 0; i<generatedWinningNumber.Length; i++)
{
generatedWinningNumber[i] = randomNumber.Next(1, 26);
}
var winningNumbers = userGussedNumbers.Intersect(generatedWinningNumber);
if (winningNumbers.Any())
{
foreach(int number in winningNumbers) {
Console.WriteLine("\nNumber {0} matched", number);
}
}
else
{
Console.WriteLine("No match!");
}

Scheduler algorithm that fill remaning hours to work

I need to generate all possible values to a scheduler who works like this:
Some hours of the week can be already chosen.
The week of work is defined by the following pattern "???????" question marks can be replaced.
Given a maximum of hours, I need to replace the question marks with digits so that the sum of the scheduled hours match the hours need to work in a week returning a string array with all possible schedules, ordered lexicographically.
Example:
pattern = "08??840",
required_week_hours= 24
In this example, there are only 4 hours left to work.
calling this:
function List<String> GenerateScheduler(int workHours, int dayHours, string pattern){}
public static void Main(){
GenerateScheduler(24, 4, "08??840");
}
This would return the following list of strings:
0804840
0813840
.......
.......
0840840
I'm not very familiar with algorithms, which one I could use to solve this problem?
This sounds like a problem where you have to generate all permutations of a list of a certain amount of numbers that sum up to a certain number. First, you need to sum up the hours you already know. Then you need to count up the number of ? aka the number of shifts/days you do not know about. Using these parameters, this is what the solution will look like,
public List<string> GenerateScheduler(int workHours, int dayHours, string pattern){
int remainingSum = workHours;
int unknownCount = 0;
// first iterate through the pattern to know how many ? characters there are
// as well as the number of hours remaining
for (int i = 0; i < pattern.Length; i++) {
if (pattern[i] == '?') {
unknownCount++;
}
else {
remainingSum -= pattern[i] - '0';
}
}
List<List<int>> permutations = new List<List<int>>();
// get all the lists of work shifts that sum to the remaining number of hours
// the number of work shifts in each list is the number of ? characters in pattern
GeneratePermutations(permutations, workHours, unknownCount);
// after getting all the permutations, we need to iterate through the pattern
// for each permutation to construct a list of schedules to return
List<string> schedules = new List<string>();
foreach (List<int> permutation in permutation) {
StringBuilder newSchedule = new StringBuilder();
int permCount = 0;
for (int i = 0; i < pattern.Length(); i++) {
if (pattern[i] == '?') {
newSchedule.Append(permutation[permCount]);
permCount++;
}
else {
newSchedule.Append(pattern[i]);
}
}
schedules.Add(newSchedule.ToString());
}
return schedules;
}
public void GeneratePermutations(List<List<int>> permutations, int workHours, int unknownCount) {
for (int i = 0; i <= workHours; i++) {
List<int> permutation = new List<int>();
permutation.Add(i);
GeneratePermuationsHelper(permutations, permutation, workHours - i, unknownCount - 1);
}
}
public void GeneratePermutationsHelper(List<List<int>> permutations, List<int> permutation, int remainingHours, int remainingShifts){
if (remainingShifts == 0 && remainingHours == 0) {
permutations.Add(permutation);
return;
}
if (remainingHours <= 0 || remainingShifts <= 0) {
return;
}
for (int i = 0; i <= remainingHours; i++) {
List<int> newPermutation = new List<int>(permutation);
newPermutation.Add(i);
GeneratePermutationsHelper(permutations, newPermutation, remainingHours - i, remainingShifts - 1);
}
}
This can be a lot to digest so I will briefly go over how the permutation recursive helper function works. The parameters go as follows:
a list containing all the permutations
the current permutation being examined
the remaining number of hours needed to reach the total work hour count
the number of remaining shifts (basically number of '?' - permutation.Count)
First, we check to see if the current permutation meets the criteria that the total of its work hours equals the amount of hours remaining needed to complete the pattern and the number of shifts in the permutation equals the number of question marks in the pattern. If it does, then we add this permutation to the list of permutations. If it doesn't, we check to see if the total amount of work hours surpasses the amount of hours remaining or if the number of shifts has reached the number of question marks in the pattern. If so, then the permutation is not added. However, if we can still add more shifts, we will run a loop from i = 0 to remainingHours and make a copy of the permutation while adding i to this copied list in each iteration of the loop. Then, we will adjust the remaining hours and remaining shifts accordingly before calling the helper function recursively with the copied permutation.
Lastly, we can use these permutations to create a list of new schedules, replacing the ? characters in the pattern with the numbers from each permutation.
As per OP, you already know the remaining hours, which I assume is given by the parameter dayHours. So, if you were to break down the problem further, you would need to replace '?' characters with numbers so that, sum of new character(number) is equal to remaining hours(dayHours).
You can do the following.
public IEnumerable<string> GenerateScheduler(int totalHours,int remainingHours,string replacementString)
{
var numberOfPlaces = replacementString.Count(x => x == '?');
var minValue = remainingHours;
var maxValue = remainingHours * Math.Pow(10,numberOfPlaces-1);
var combinations = Enumerable.Range(remainingHours,(int)maxValue)
.Where(x=> SumOfDigit(x) == remainingHours).Select(x=>x.ToString().PadLeft(numberOfPlaces,'0').ToCharArray());
foreach(var item in combinations)
{
var i = 0;
yield return Regex.Replace(replacementString, "[?]", (m) => {return item[i++].ToString(); });
}
}
double SumOfDigit(int value)
{
int sum = 0;
while (value != 0)
{
int remainder;
value = Math.DivRem(value, 10, out remainder);
sum += remainder;
}
return sum;
}

C# Checking if there is same random value in the array or not

I want to check if there is same value in the array or not as I mentioned in the title. And if there is, I want to pass that value and check another random value to add to listbox.
In my form, there is 2 textBox, 1 listbox and 1 button. When button is clicked, listbox has to show random numbers up to sum of textbox1 and textbox2. For instance;
5 entered from textbox1 and 10 entered from textbox2. Sum is of course 15 and listbox has to show 15 random numbers but those numbers have to be different from each other.
I wrote something like that and used Contains method to check if there is same value or not. But the program froze and didn't give any error.
int a, b;
Random rnd = new Random();
int[] array;
private void button1_Click(object sender, EventArgs e)
{
a = Convert.ToInt32(textBox1.Text);
b = Convert.ToInt32(textBox2.Text);
int c = a + b;
array = new int[c];
for (int i = 0; i < array.Length; i++)
{
int number = rnd.Next(c);
foreach(int numbers in array)
{
if (array.Contains(numbers))
{
i--;
}
else
{
array[i] = number;
listBox1.Items.Add(array[i]);
}
}
}
I also did it without foreach(Only Contains part I mean). Also didn't work. I wrote in "else";
array[i] += number;
it also didn't work.
I would be very appreciated if you help me. Thanks in advance.
instead of a for loop, use a while loop:
int = 0;
while(i<c)
{
int random rnd.Next(c);
if(!array.Contains(random))
array[i++] = random;
}
you may also create a list of numbers from 1-15 and then shuffle them (as your random function will create only random numbers from 1-15 just random):
array = Enumberable.Range(0,c).OrderBy(x => rnd.Next()).ToArray();
The above code is much faster, because imagine that we have generated 14 random numbers and only one number (5 for instance) left, it has to go through loop several times so that finally random number that is generated equals to 5, but in the above code there is no need to check that, we just have all numbers and then we shuffle it.
You can try to use do...while instead of for loop
Random.Next get the value from 0 to c - 1, so rnd.Next(c + 1); need to add 1 otherwise, the loop will not be stopped.
var array = new int[c];
int number;
for (int i = 0; i < array.Length; i++)
{
do
{
number = rnd.Next(c + 1);
} while (array.Contains(number));
array[i] = number;
listBox1.Items.Add(array[i]);
}
You basically need to shuffle your data. Create a collection with all values:
var temp = Enumerable.Range(0, c);
Now order it by random
temp = temp.OrderBy(_ => rnd.Next());
Now you can add temp to your listBox
Or, as single line:
listBox1.Items.AddRange(Enumerable.Range(0, c).OrderBy(_ => rnd.Next()));

Random a unique number to five objects

I have been searching for an answers to my problem but I can't find any solutions.
I writing a program where the user enter name, last name, and social number for five students. When that's done a random number will get handed to each of the five students the user has typed in. But the problem is that two students can not have the same random number. I know with 1-10000 the chances is low, but this is my task.
This is my code where I have tried to fix the problem but I can't get it to work.
while (antal != ggr)
{
string name = Interaction.InputBox("Write name: ");
string lastname = Interaction.InputBox("Write last name: ");
string socialnr = Interaction.InputBox("Write social number: ");
while (a != false)
{
foreach (int item in uniqNum)
{
if (item == _rnd)
{
a = true;
}
else
{
_rnd = rnd.Next(1, 10000);
uniqNum.Add(_rnd);
a = false;
}
}
}
ggr++;
_Studens.Add(new student(name, lastname, socialnr, _rnd));
}
Generate a list containing all the random numbers you wish to pick from. Then, choose an index randomly from that list, add the resultant number to a separate list, and remove the indexed element from the list of all numbers.
This will work for smaller ranges of numbers. If you wanted a unique random number in larger ranges, this method is probably not appropriate. In that case, consider generating GUIDs and converting them to their 128-bit numeric representation.
var allNumbers = Enumerable.Range(1, 10000).ToList();
var randomNumbers = new List<int>();
var random = new Random();
const int studentCount = 5;
for (int i = 0; i < studentCount; i++)
{
int randomIndex = random.Next(0, allNumbers.Count);
randomNumbers.Add(allNumbers[randomIndex]);
allNumbers.RemoveAt(randomIndex);
}
What about if you generate the number first, then use the Contains() method to check if the number already exists? If it does, generate the number again. Something like this:
int number = 0;
List<int> numberArray = new List<int>();
while (true)
{
Random r = new Random();
number = r.Next(1, 1000);
if (!numberArray.Contains(number))
{
break;
}
}
Random r = new Random();
Enumerable.Range(1,10000).OrderBy(n => r.Next()).Take(5);

How to: Assign a unique number to every entry in a list?

What I want is to make tiles. These tiles (about 30 of them) should have a fixed position in the game, but each time I load the game they should have random numbers that should affect their graphical appearance.
I know how to use the Random method to give a single tile a number to change its appearance, but I'm clueless on how I would use the Random method if I were to make a list storing the position of multiple tiles. How can you assign each entry in a list a unique random number?
I need this for my game where you're in a flat 2D map, generated with random types of rooms (treasure rooms, arena rooms etc.) that you are to explore.
Take a look at the Fisher-Yates shuffle. It's super easy to use and should work well for you, if I read your question right.
Make an array of 30 consecutive numbers, mirroring your array of tiles. Then pick an array-shuffling solution you like from, say, here for instance:
http://forums.asp.net/t/1778021.aspx/1
Then tile[23]'s number will be numberArray[23].
if you have something like this:
public class Tile
{
public int Number {get;set;}
...
}
you can do it like this:
var numbers = Enumerable
.Range(1, tilesList.Count) // generates list of sequential numbers
.OrderBy(x => Guid.NewGuid()) // shuffles the list
.ToList();
for (int i = 0; i < tiles.Count; i++)
{
tile[i].Number = numbers[i];
}
I know, that Guid is not a Random alternative, but it should fit this scenario.
Update: As long as answer was downvoted, I've wrote simple test, to check if Guids are not usable for shuffling an array:
var larger = 0;
var smaller = 0;
var start = DateTime.Now;
var guid = Guid.NewGuid();
for (int i = 0; i < 10000000; i++)
{
var nextGuid = Guid.NewGuid();
if (nextGuid.CompareTo(guid) < 0)
{
larger++;
}
else
{
smaller++;
}
guid = nextGuid;
}
Console.WriteLine("larger: {0}", larger);
Console.WriteLine("smaller: {0}", smaller);
Console.WriteLine("took seconds: {0}", DateTime.Now - start);
Console.ReadKey();
What it does, it counts how many times next guid is smaller than current and how many times is larger. In perfect case, there should be equal number of larger and smaller next guids, which would indicate, that those two events (current guid and next guid) are independent. Also measured time, just to make sure, that it is not too slow.
And got following result (with 10 million guids):
larger: 5000168
smaller: 4999832
took seconds: 00:00:01.1980686
Another test is direct compare of Fisher-Yates and Guid shuffling:
static void Main(string[] args)
{
var numbers = Enumerable.Range(1, 7).ToArray();
var originalNumbers = numbers.OrderBy(x => Guid.NewGuid()).ToList();
var foundAfterListUsingGuid = new List<int>();
var foundAfterListUsingShuffle = new List<int>();
for (int i = 0; i < 100; i++)
{
var foundAfter = 0;
while (!originalNumbers.SequenceEqual(numbers.OrderBy(x => Guid.NewGuid())))
{
foundAfter++;
}
foundAfterListUsingGuid.Add(foundAfter);
foundAfter = 0;
var shuffledNumbers = Enumerable.Range(1, 7).ToArray();
while (!originalNumbers.SequenceEqual(shuffledNumbers))
{
foundAfter++;
Shuffle(shuffledNumbers);
}
foundAfterListUsingShuffle.Add(foundAfter);
}
Console.WriteLine("Average matching order (Guid): {0}", foundAfterListUsingGuid.Average());
Console.WriteLine("Average matching order (Shuffle): {0}", foundAfterListUsingShuffle.Average());
Console.ReadKey();
}
static Random _random = new Random();
public static void Shuffle<T>(T[] array)
{
var random = _random;
for (int i = array.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
T tmp = array[j];
array[j] = array[i - 1];
array[i - 1] = tmp;
}
}
By "direct compare" I mean, that I'm producing shuffled sequence and try to shuffle again to get same sequence, and assume, that the more tries I need to produce same sequence, the better random is (which is not necessary mathematically correct assumption, I think it is oversimplification).
So results for small set with 1000 iterations to reduce error, was:
Average matching order (Guid): 5015.097
Average matching order (Shuffle): 4969.424
So, Guid performed event better, if my metric is correct :)
with 10000 iterations they came closer:
Average matching order (Guid): 5079.9283
Average matching order (Shuffle): 4940.749
So in my opinion, for current usage (shuffle room number in game), guids are suitable solution.

Categories

Resources