Creating an int inside an if/else and using it later - c#

I'm playing with stuff here and am having trouble with something.
I have an input; it can be either a number or a letter. I have to check whether it's a number or a letter. So I used an if for that. If the input is a number, my code should create an int. If it's a letter, it should create a different int. But I can't use the integer later on for some reason. Any way to solve that?
Console.WriteLine("Length (ms)");
string I = Console.ReadLine();
int I2 = Int32.Parse(I);
Console.WriteLine("Height: r for random");
string L = Console.ReadLine();
//So it asks for an input,for which I here want to check what it is
if (L != "r")
{
int He = Int32.Parse(L);
}
else
{
Random Hi = new Random();
int He = Hi.Next(1, 50);
}
//----------------------I want to use the ints in here
while(true)
{
Random R = new Random();
Random R2 = new Random();
int H = R2.Next(1,He);
int rH = H * 100;
Console.WriteLine("Height is {0}",H);
Console.Beep(rH,I2);

You need to adjust the scope of int He to take it outside of the conditional blocks.
int He;
if (L != "r")
{
He = Int32.Parse(L);
}
else
{
Random Hi = new Random();
He = Hi.Next(1, 50);
}
You could also use the conditional operator in this example to make the code look like which might be preferable as a matter of style.
int He = L != "r" ? Int32.Parse(L) : (new Random()).Next(1, 50);
One thing that is notable, about both the above, versions is that Int32.Parse could raise a number of exceptions based on the format of the string L which you probably want to handle either using try - catch statements or by using the TryParse method

Related

C# substract 2 strings without getting negatives

i need some help with my code.
i've got to make a math game with subtracting without getting negatives but my code doesn't seem to work.
int c = a - b;
if (c < 0)
{
Random ro = new Random();
a = ro.Next(10) + 1;
b = ro.Next(10) + 1;
lb_getal1.Text = a.ToString();
lb_getal2.Text = b.ToString();
}
if (txt_antwoord.Text == c.ToString())
{
MessageBox.Show("You provided the right answer!");
score += 1;
Random r = new Random();
a = r.Next(10) + 1;
b = r.Next(10) + 1;
lb_getal1.Text = a.ToString();
lb_getal2.Text = b.ToString();
}
else
{
MessageBox.Show("You were wrong!");
}
if (score == 5)
{
MessageBox.Show("You answered 5 answers correctly! Well done!");
this.Close();
RM_menu form = new RM_menu();
form.Show();
}
There are several problems in your code. The first thing to improve is: use only one instance of Random.
The Random class provides pseudo random numbers from a list. If you create an instance with the default constructor new Random(), the instance is initialized with a seed taken from the current time. Since there is not much time between your two calls, both instances probably use the same seed and you will get the same values for a and b again.
I suggest to create only one instance and store it in a member variable of your class.
Second problem: if your first try results in a negative c, you only try again once, but that does not make sure that this time it will be positive. A better approach is to compare a and b and switch if b is larger.
So the your code could look like this:
public class YourGame : Form // I guess it's a Form
{
private Random randomGenerator = new Random();
private int a;
private int b;
private int score;
public void CreateQuestion()
{
a = randomGenerator.Next(10) + 1;
b = randomGenerator .Next(10) + 1;
if (b > a)
{
// switch values
int tmp = b;
b = a;
a = tmp;
}
lb_getal1.Text = a.ToString();
lb_getal2.Text = b.ToString();
}
private void OnAnswer()
{
int c = a - b; // will never be negative as we checked a and b above
if (txt_antwoord.Text == c.ToString())
{
MessageBox.Show("You provided the right answer!");
score += 1;
CreateQuestion();
}
else
MessageBox.Show("You were wrong!");
if (score == 5)
{
MessageBox.Show("You answered 5 answers correctly! Well done!");
this.Close();
RM_menu form = new RM_menu();
form.Show();
}
}
}
I am not trying to solve this problem, but trying to give some inputs on how to make sure that the value would not be less than zero when using Random.
int a, b, c;
Random ro;
ro = new Random();
b = ro.Next(10);
a = ro.Next(b, 10);
c = a - b;
As you can see, first we set a random value to b using ro.Next(10) and then we specify a minimum value by using ro.Next(b, 10)
Doing so, it is guaranteed that the value would not be less than zero when doing a-b.
you can use Math.Abs
int c = Math.Abs (a-b);

cycle never reaching final value

This is my random unique numbers generator I try to create for my cards software. It generates numbers and write into array OK. I have problem with the loop here. when integer i reaches 29, it stops growing and code cycles infinitely and never reaches 30, which would stop the loop.
Without the if statement it works, but it won't fill the range needed.
fixed the code, now works OK, the initial value in array was the problem. now I ged needed 0-29 values
public partial class Form1 : Form
{
int[] rndCards = new int[30];
public Form1()
{
InitializeComponent();
richTextBox1.Text = #"random numbers";
}
private void button1_Click(object sender, EventArgs e)
{
int i = 0;
rndCards = new int[30];
richTextBox1.Clear();
Random rnd = new Random();
while (i < 30)
{
int cardTest = rnd.Next(0, 30);
while (rndCards.Contains(cardTest))
{
cardTest++;
if (cardTest == 31)
{
cardTest = 1;
}
}
rndCards[i] = cardTest;
i++;
}
i = 0;
while (i < 30)
{
rndCards[i] = rndCards[i] -1;
richTextBox1.Text += rndCards[i] + ", ";
i++;
}
}
}
You problem lies in the simple fact that the array already contains the number 0 when you create it (because each item of an array is initialized to the default value for its member's type) That's why you should start your i from 1 and not zero.
int i = 1;
Alternative Simpler Approach:
You can do this as a simple random number generation:
Random rnd = new Random();
rndCards = Enumerable.Range(0, 30).OrderBy(x => rnd.Next()).ToArray();
foreach(var card in rndCards)
{
// do something
}
rnd.Next(0,30) would return a random number from 0-29.
From the documentation for Random.Next(Int32, Int32):
The Next(Int32, Int32) overload returns random integers that range from minValue to maxValue – 1. However, if maxValue equals minValue, the method returns minValue.
Use int cardText = rnd.Next(0, 31);, and this should solve your issue.
The upper bound is exclusive (C# Random.Next - never returns the upper bound?).
int cardTest = rnd.Next(0, 31);

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);

only return random number when it is unique

My brain is melting today and i cannot think how to do this simple bit of code. numberList is a string of numbers seperated by commas like '2, 34, 10' etc.. when i request a random number i need to check if the string has the number, if it does i want to keep requesting a random number until the random number is definitely not in the string. i cant think what kind of loop i would do to get this to work:
Random r = new Random();
public int RandomPos(int max) {
int i;
do {
i = r.Next(max) + 1;
}
while (!numberList.Contains(i.ToString()));
return i;
}
I'll just explain in text instead of code because I'm too lazy to write the code right now:
Use String.Split to break your list into an array, then (if you need to) parse it into integers.
Use Enumerable.Range(0, max).ToArray() to create a list of all the numbers you could select.
Subtract the first list from the second.
Randomly select an element from the final list.
This has the benefit that you don't need to keep picking things randomly and retrying in a potentially-infinite-but-not-really-in-practice loop.
edit: here's some code
string[] invalid = numberList.Split(", ");
var list = Enumerable.Range(0, max).Where(x => !invalid.Contains(x.ToString())).ToArray();
return list[r.Next(list.Count)];
Remove the !
do
{
i = r.Next(max) + 1;
}
while (numberList.Contains(i.ToString()));
Try it with this:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
if (!invalidNumbers.Split(',').Contains(randomInt.ToString()))
{
return randomInt;
}
else
{
return Randomize();
}
}
Providing a simple answer, you don't need Split(). This assumes no spaces between numbers, modify accordingly:
String modifiedNumberList = "," + numberList + ",";
do {
i = r.Next(max) + 1;
}
while (modifiedNumberList.Contains("," + i.ToString() + ","));
edit: I believe BrokenGlass is also right, you shouldn't have the "!", removed from my solution.
Maybe this is what you want? I used a regular while instead since I think they are easier to read, and the only thing I think you get wrong was the !.
public int RandomPos(int max) {
int i = r.Next(max);
var intList = numberList.Split(',').ToDictionary<string,int>((n) => int.Parse(n));
while(intList.Contains(i))
{
i = r.Next(max);
}
return i;
}
Assuming I need to split the numberList first to if they are in a string. That would make the third row look like:
A modification of #Dave's reply:
static string invalidNumbers = "0,1,2,3,4,5";
static Random random = new Random();
static int Randomize()
{
var randomInt = random.Next(0, 10);
var splitString = invalidNumbers.Split(',');
while (splitString.Contains(randomInt.ToString()))
{
randomInt = random.Next(0, 10);
}
return randomInt;
}
A couple ways to improve this:
1) Use a List<int> or something instead of a string to make your life easier
2) if max is small (say <1000 or something) generate the list of all possible values, order them randomly, and return numbers in sequence from that list.
As the number of "used" numbers approaches "max" you could end up in a very long loop before you get an unused number. For values of max over a couple hundred, this could actually be of consequence. This may or may not be a problem in your situation.
This code will cover all cases:
"1,2,3,4,5"...
"1, 2, 3,4,5"...
private static int GetRandomNumber(string existingNumbers, int max)
{
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
while (true)
{
Random rnd = new Random();
int value = rnd.Next(max);
if (!existingNumbersList.Contains(value.ToString()))
{
return value;
}
}
}
You can even take out this part:
string[] existingNumbersArray = existingNumbers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
List<string> existingNumbersList = new List<string>();
foreach (string number in existingNumbersArray)
{
existingNumbersList.Add(number.Trim());
}
so it will not be called each time you call GetRandomNumber function.
My addition to all the other answers..
const string invalidNumbers = "0,1,2,3,4,5";
Random random = new Random();
int value = 0;
List<int> tmpList = new List<int>();
foreach (var x in invalidNumbers.Split(','))
{
tmpList.Add(Int32.Parse(x));
}
do
{
value = random.Next(0, 10);
}
while (tmpList.Contains(value));
return value
Edit: missunderstood the question for the first post, anyway, here is a recursive solution.
It seems better to keep the numbers in a List, but if it is required to follow the format you asked, here it is:
const int MAX_ATTEMPTS = 10;
Random r = new Random();
string nlist = "2, 34, 10";
public int RandomPos(int max_val)
{
List<string> used = nlist.Replace(" ","").Split(',').ToList();
return _RandomPos(MAX_ATTEMPTS, max_val, used);
}
private int _RandomPos(int tl, int max, List<string> used)
{
if (tl <= 0)
throw new Exception("Could not generate random number. Too many tries.");
else
{
int rnum = r.Next(max);
if (!used.Contains(rnum.ToString()))
{
nlist += ", " + rnum.ToString();
return rnum;
}
else
return _RandomPos(tl - 1, max, used);
}
}
I realize there are a lot of entries, but I don't see any with some decent error checking. That being said, this will offer a few things:
Won't waste any effort when there's nothing to disqualify
Will only select from a range of possible choices
Will flag -1 if a number can't be chosen within the max range and not in the disqualifying list
So here goes:
public int RandomPos(int max)
{
// compile the list of numbers we need to disqualify
List<int> disqualified = numberList.Split(new[]{',',' '},StringSplitOptions.RemoveEmptyEntries).Select(n => int.Parse(n)).ToList();
// Nothing to check against, save the CPU cycles
if (disqualified.Count == 0)
return (new Random(DateTime.Now.Millisecond)).Next(max) + 1;
// make a list of everything that's possible for a choice
List<int> valid = Enumerable.Range(0, max).Where(r => !disqualified.Contains(r)).ToList();
// return either a valid result, or -1 if there are no valid results
return (valid.Count == 0 ? -1 : valid[(new Random(DateTime.Now.Millisecond)).Next() % valid.Count]);
}
.Split will do the work, the following code will work as well, just for fun (replace the line while (!numberList.Contains(i.ToString())); in your code instead of checking i.ToString() check ","+i.ToString()+"," PLUS the beginning and ending. You need to adjust it if you have a space after ","):
while (!numberList.StartsWith(i.ToString()+",")&&
!numberList.Contains(","+i.ToString()+",")&&
!numberList.EndsWith(","+i.ToString()));
// if numberList is large then use HashSet<int> rather than a plain int[] array
int[] nums = numberList.Split(new[] { ',', ' ' },
StringSplitOptions.RemoveEmptyEntries)
.Select(int.Parse)
.ToArray();
int i;
while (nums.Contains(i = r.Next(max) + 1));
return i;
(You should also add a check to ensure that you don't end up in an infinite loop if/when numberList contains all the possible values that might be produced by the rng.)

generating a batch of random passwords

Generating a random password is easy. but generating a batch is more difficult.
public static string getRandomPassword(int letters, int getallen) {
//int letters = 8;
//int getallen = 5;
char[] letterdeel = new char[letters];
int minGetal = (int)Math.Pow(10, getallen - 1);
int maxGetal = (int)Math.Pow(10, getallen);
string password;
Random r = new Random();
int test = (int)(DateTime.Now.Ticks);
for (int i = 0; i < letters; i++) {
r = new Random((int)(DateTime.Now.Ticks) + i);
bool capital = r.Next(2) == 0 ? true : false;
if (capital) {
letterdeel[i] = (char)r.Next(65, 91);
} else {
letterdeel[i] = (char)r.Next(97, 123);
}
}
password = new string(letterdeel);
password += r.Next(minGetal, maxGetal);
return password;
}
this is my method, the passwords should be in a certain letter-number format.
this works fine, however if i have a for loop pulling 100 passwords from this method, in my array i have 5-8 the same passwords, then again 5-8 the same pass.
i know WHY this is, because of the random function and the clock it depends on, but how do i fix this?
Move Random r to outside the method if you are repeatedly calling it. You are going to be hitting it several times in the same relative timeframe, so you are going to be generating the same seeds. You also want to get rid of the line below. It is unnecessary, and (again), with the nature of DateTime.Now, you would just continue to generate the same sequence of "random" numbers.
r = new Random((int)(DateTime.Now.Ticks) + i);
Define your random number generator as a static outside of the function.
How can I get true randomness in this class without Thread.Sleep(300)?
Use a set rather than whatever collection you store into and don't loop 100 times but until the set has 100 items in it.

Categories

Resources