I have a WPF application which has random chances of random events occurring. I have a switch statement like so which switches a random number:
(property)
static Random RandomObject { get; set; } = new Random();
...
RandomObject = new Random();
switch (RandomObject.Next())
{
case 1 when RandomObject.Next(1, 3) == 2:
// a
case 1 when RandomObject.Next(1, 13) == 2:
// b
break;
}
For some reason, in debug mode, the whole switch is being skipped completely. Could someone tell me what I'm doing wrong or how I could possibly make it so it does work?
EDIT: Okay can someone tell me how to fix this instead because I remember coming up with something similar that does what I want to do and it did work but the problem is my hard drive crashed so I lost all of my data
Would this be possible?
switch(RandomObject)
{
case 1 when RandomObject.Next(1,3) == 2:
//do stuff
break;
}
I will run tests to try to show you what's going wrong. Let's take this code, which is similar to your own:
int acount = 0, bcount = 0;
var r = new Random();
for(var i = 0; i < 1_000_000_000; ++i) // 1 billion iterations
{
switch (r.Next())
{
case 1 when r.Next(1, 3) == 2:
++acount;
break;
case 1 when r.Next(1, 13) == 2:
++bcount;
break;
}
}
Console.WriteLine($"a case hit {acount} times");
Console.WriteLine($"b case hit {bcount} times");
The output is:
a case hit 0 times
b case hit 0 times
Now, let's try shrinking up your range on your switch statement:
// ...
switch (r.Next(1, 20))
{
// ...
Your results are now:
a case hit 26313397 times
b case hit 2191910 times
So what we are trying to tell you in the comments is Random.Next() returns a value in the range of [0, 2147483647], which is near unlikely to ever return the value of 1, which is what your switch cases require to continue. By changing your range with much more reasonable values, your chances increase dramatically and is more than likely what you want.
Related
Edit # Dublicate: I know that an unsafe use of Thread is not recomented. My question is about the why, and not about if random is thread-safe. Thanks to the answers, helped me understandig it better!
I wrote a "gimmick" program that is supposed to display random chars with random colors (For- and Background) in a Console-Window using Math.Random() and Multithreading. For more randomness I didn't made the program "thread safe". (Additional Information: I originally wanted the program to display an Space-Invader in the center, I achieved that with Thread-Safety, and I know, multithreading is supposed to be thread safe but this is not what this question is about)
The output looks like this:
The function of the program is like that: I have an Array in which all the Positions (X/Y) with colors and Char are stored. I have some Functions that change this array and I have some functions to display the array. I also got a function to return random chars and one to return random colors.
Now the point that I don't get: Sometimes everything works as described, but sometimes the program starts to display only !-Chars (exclamation mark) but keeps the random colors and positions:
Another time the program only shows the colors black and white but the chars keep being random:
And sometimes it happens, that the program only displays !-Chars and only black and white:
What I could say is the following:
My "Get a Random Char" function looks like that:
public static char GetChar()
{
return (char)randomChar.Next(33, 150);
}
!-Char is Ascii-Char 33. That means if the Program get stucked the Random-Char-Function only returns the lowest Random-Char (== 33 == !)
I got something similar for the colors. I give an random-number between 0 and 16 to a function to get back a Console-Color:
private ConsoleColor SetColor(char ColorIndex)
{
switch (ColorIndex)
{
case (char)1:
return ConsoleColor.Black;
case (char)2:
return ConsoleColor.Blue;
case (char)3:
return ConsoleColor.Cyan;
case (char)4:
return ConsoleColor.DarkBlue;
case (char)5:
return ConsoleColor.DarkCyan;
case (char)6:
return ConsoleColor.DarkGray;
case (char)7:
return ConsoleColor.DarkGreen;
case (char)8:
return ConsoleColor.DarkMagenta;
case (char)9:
return ConsoleColor.DarkRed;
case (char)10:
return ConsoleColor.DarkYellow;
case (char)11:
return ConsoleColor.Gray;
case (char)12:
return ConsoleColor.Green;
case (char)13:
return ConsoleColor.Magenta;
case (char)14:
return ConsoleColor.Red;
case (char)15:
return ConsoleColor.White;
case (char)16:
return ConsoleColor.Yellow;
default:
return ConsoleColor.Black;
}
}
//The call looks like that:
_Data[x, y, 1] = (char)random.Next(0, 16);
I know that random.Next(0, 16) will give a 15 as maximum number back, and 15 is the color white in the example. If I change 15 to red, the Program will display red instead of white, when the program gets stucked:
This means: When the program got stucked the Random-Char-Function always returns the lowest possible number (33) and the Random-Color-Function always returns the highest possible number (15).
The question: Why is this behaviour? Why is it just sometimes and not every time? And why it is every time after a different time of running? Why is one random function always returning max-number and the other one always the min-number?
My guess is, that his is because of the CPU predicting, but as I said, it's just a guess and I wonder how this works, and why it goes to different approaches (min/max).
Here are some of my Code, if needed I could post more Code:
//Program-Start after initialising some stuff:
public AnotherOne()
{
new Thread(DrawData).Start();
new Thread(DrawDataLR).Start();
new Thread(DrawDataRL).Start();
new Thread(DrawDataTD).Start();
new Thread(DrawDataDT).Start();
new Thread(ChangeData).Start();
ChangeData();
}
//Draw Data example for Left-Right:
private void DrawDataLR()
{
while (!_done)
{
DrawDataLeftRight();
Thread.Sleep(2);
}
}
private void DrawDataLeftRight()
{
for (int x = 0; x < _Width - 1; x++)
{
for (int y = 0; y < _Height - 1; y++)
{
Console.SetCursorPosition(x, y);
Console.BackgroundColor = SetColor(_Data[x, y, 1]);
Console.ForegroundColor = SetColor(_Data[x, y, 2]);
Console.WriteLine(_Data[x, y, 0]);
}
}
}
//Draw Data Function:
private void DrawData()
{
Random next = new Random();
int x = 1;
while (!_done)
{
x = next.Next(1, 5);
switch (x)
{
case 1:
DrawDataLeftRight();
break;
case 2:
DrawDataTopDown();
break;
case 3:
DrawDataRightLeft();
break;
case 4:
DrawDataDownTop();
break;
}
}
}
//Change Data Function with "stripes" as Example:
private void ChangeData()
{
int x = 100;
while (!_done)
{
FillRandomFeld();
Thread.Sleep(x);
ClearChar();
Thread.Sleep(x);
SetColor();
Thread.Sleep(x);
Stripes();
Thread.Sleep(x);
SetChar();
Thread.Sleep(x);
OtherStripes();
Thread.Sleep(x);
x = randomX.Next(0, 100);
}
}
private void Stripes()
{
char colr = (char)random.Next(0, 16);
for (int x = 0; x < _Width - 1; x += 4)
{
for (int y = 0; y < _Height - 1; y++)
{
if (_Data[x, y, 3] != (char)1)
{
_Data[x, y, 1] = colr;
_Data[x, y, 2] = colr;
}
}
}
}
Random.Next() ends up calling this code (from the reference source):
private int InternalSample() {
int retVal;
int locINext = inext;
int locINextp = inextp;
if (++locINext >=56) locINext=1;
if (++locINextp>= 56) locINextp = 1;
retVal = SeedArray[locINext]-SeedArray[locINextp];
if (retVal == MBIG) retVal--;
if (retVal<0) retVal+=MBIG;
SeedArray[locINext]=retVal;
inext = locINext;
inextp = locINextp;
return retVal;
}
Looking at this code, it is obvious that multithreaded access could do some very bad things. For example, if inext and inextp end up containing the same value, then SeedArray[locINext]-SeedArray[locINextp]; will always result in 0, and Random.Next() will always return 0.
I'm sure you can start to imagine lots of other ways that multithreaded access to this code could mess things up.
Conceptually, PRNGs internally have a large number of states, where each state corresponds to a possible output of the PRNG (although multiple states can have the same output), and they walk through each one of those states in a deterministic order. If you corrupt the internal state of the PRNG, it may start walking through a much smaller set of those states before looping back to the first one, so you get a small repeating set of "random" output numbers.
In another place in your code, you are creating a new Random instance each time the method is called. As mentioned in the linked answer, this will result in many Random instances which return the same set of random numbers.
Eric Lippert has an ongoing series of blog posts about improving the Random class: part 1 part 2 (and more to come).
Your multithreaded use of the Random object is corrupting its internal state.
You can reproduce the issue fairly easily using the following program. If you run it, after a while (or sometimes, immediately) it will start producing zeroes instead of random numbers. You may have to run it several times to see the effect. Also, it goes wrong more often for a RELEASE build rather than a DEBUG build (which is not unusual for multithreading problems!).
(Note: This was tested using .Net 4.7.2 on a 16 core processor. Results may vary for other systems.)
using System;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
static void Main()
{
Console.WriteLine();
Random rng = new Random(12345);
Parallel.Invoke(
() => printRandomNumbers(rng),
() => printRandomNumbers(rng),
() => printRandomNumbers(rng));
Console.ReadLine();
}
static void printRandomNumbers(Random rng)
{
while (rng.Next() != 0)
{}
while (true)
{
Console.WriteLine(rng.Next());
}
}
}
}
So i'm working on a revision tool that'll ask defined questions randomly using console command C#. I can create the random number but cannot seem to use the Switch function properly. Can anyone help?
// The random Object
Random Number = new Random();
while (true)
{
int Question = Number.Next(1);
Console.WriteLine("{0}", Question);
string Answer = Console.ReadLine();
if (Answer.ToLower() == "finished")
{
break;
}
if(Answer.Length == 0)
{
Console.WriteLine("Write Please");
continue;
}
switch (Question)
{
case 0:
{
Console.WriteLine("What is the nucleus of an atom made of");
if (Answer == "neutrons and protons")
{
Console.WriteLine("Well Done!");
}
if (Answer == "protons and neutrons")
{
Console.WriteLine("Well Done!");
}
Console.WriteLine("Try Again");
break;
}
}
}
}
}
}
Your code is quite strange; for example you are trying to read a response before you have even printed a question. However, your immediate question relating to the random number is simple.
You are using int Question = Number.Next(1);. According to MSDN:
Returns a non-negative random integer that is less than the specified maximum.
since you are storing the number as an int, and you have 1 as the specified maximum, you will always receive 0 from this assignment. I would assume that you have other case statements in your switch, and if you use the number of questions you have rather than 1, your switch will work. You will still have other issues with things printing in the wrong order, though....
I haven't a living clue how to write this in c#. I know how to do it in Delphi.
This is how I would do it in Delphi:
Case Total of
80..100 : ShowMessage ('You got an A!');
60..79 : ShowMessage ('You got a B!');
50..59 : ShowMessage ('You got a C!');
40..49 : ShowMessage ('You got a D!');
0..39 : ShowMessage ('You got an E...');
end;
I have read tutorials for this, but I wouldn't know how to use/write it in the way I need it.
Here's my version in c#:
switch (Total) //'Total' is a bunch of Integers divided together to get a Percentage
{
case 80..100: //Where 80% to 100% would achieve an A
{
MessageBox.Show("You got an A!");
}
case 60..79: //Where 60% to 79% would achieve a B
{
MessageBox.Show("You got a B!");
}
Is this possible?
Thanks.
To express a range in a switch / case statement in C# you have to manually list out the cases
switch (Total) {
case 80:
case 81:
...
case 100:
MessageBox.Show("you got an A");
break;
...
}
For large ranges such as this though it may be better to just use a series of if statements
if (Total >= 80 && Total <= 100) {
MessageBox.Show("you got an A");
} else if (Total >= 70) {
MessageBox.Show("you got a B");
}
C# does not have a particularly flexible switch statement. This is intentional, options are limited to ensure that code generation is fast. C# has never been a language that hides execution cost. Runtime implementation is through a jump table, indexed by the switch() expression. Very fast, but not very flexible.
The alternative is an explicit if/else if chain. The exact same code that a VB.NET or Delphi compiler generates, but written by hand. Not terribly pretty, but effective enough:
if (Total < 0 || Total > 100) throw new ArgumentException("Not a valid grade");
if (Total >= 80) ShowMessage ('You got an A!');
else if (Total >= 60) ShowMessage ('You got a B!');
else if (Total >= 50) ShowMessage ('You got a C!');
else if (Total >= 40) ShowMessage ('You got a D!');
else ShowMessage ('You got an E...');
This now also shows the cost associated with the code, there can be up to 6 comparisons on the Total value. If speed is essential and the range is limited then consider switching to a lookup table, a Dictionary<>. Not necessary here, ShowMessage() is an expensive method.
If it is supposed to be a switch then it should be like this:
switch(Total)
{
case 100:
case 99:
//...
case 80:
MessageBox.Show("You got an A!");
break;
case 79:
// ...
}
If it is okay to use if-statements I would recommend to do it like this:
if (Total < 0)
{
}
else if (Total < 40)
MessageBox.Show("You got an E...")
else if (Total < 50)
MessageBox.Show("You got a D!");
else if (Total < 60)
// etc.
Hop you could use this answer.
AFAIK you can't do it natively in C# but if you want to do it with a switch, like you stated in your question, there is a workaround for that (for fixed ranges).
Considering your interval of 20 by 20:
int interval= (value-1) / 20;
switch (interval)
{
case 0: // 1-20
//Do stuffs
break;
case 1: // 21-40
//Do stuffs
break;
// and so on
}
A solution to solve your problem is to do it like this.
switch (Total)
{
case 1: case 2: case 3:
// Do Something
break;
case 4: case 5: case 6:
// Do Something
break;
default:
// Do Something
break;
}
Multiple Cases in Switch:
What about this?:
var s = "EEEEDCBBAAA";
var result = s[Total/10];
MessageBox.Show("you got a " + result);
Because Switch Statements Smells :)
Update
Didn't realize the a / an difference, but:
MessageBox.Show(string.Format("you got a{0} {1}",
result == "A" || result == "E" ? "n" : "",
result));
You could use a switch/case statement by creating a very long case statement or an extension method that turned a range of numbers into a constant. But it's probably easier to use an if/else block.
Personally, I like the readability of Enumerable.Range slightly over >= and <=. However, it is a slower operation because you're creating an enumerable of ints everytime you do a comparison. You'll probably on notice performance issues when you get in the tens of thousands of grads though.
if(Enumerable.Range(80,100).Contains(Total))
{
MessageBox.Show("You got an A!");
}
else if(Enumerable.Range(60, 79).Contains(Total))
{
MessageBox.Show("You got a B!");
}
else if(Enumerable.Range(50, 59).Contains(Total))
{
MessageBox.Show("You got a C!");
}
else if(Enumerable.Range(40, 49).Contains(Total))
{
MessageBox.Show("You got a D!");
}
else if(Enumerable.Range(0, 39).Contains(Total))
{
MessageBox.Show("You got an E...");
}
Use an action lookup (like a command pattern)
static void Main(string[] args)
{
var theGrade = 89;
var gradeLookup = new Dictionary<Func<int, bool>, Action>
{
{ x => x >= 90, () => ShowMessage("You got an A!") },
{ x => x >= 80 && x < 90, () => ShowMessage("You got an B!") },
};
gradeLookup.First(x => x.Key(theGrade)).Value();
Console.ReadKey();
}
static void ShowMessage(string msg)
{
Console.WriteLine(msg);
}
You can also simply divide by 10 to reduce the checks, but this would only work for some college scales:
static void Main(string[] args)
{
var theGrade = 80;
switch (theGrade / 10)
{
case 10:
case 9:
ShowMessage("You got an A");
break;
case 8:
ShowMessage("You got a B");
break;
case 7:
ShowMessage("You got a C");
break;
case 6:
ShowMessage("You got a D");
break;
default:
ShowMessage("You got a F");
break;
}
Console.ReadKey();
}
What about this code:
private string GetTotalCode(int total) {
if (Total >= 80 && Total <= 100)
return "A"
if ...
}
and then simplify switch:
switch (GetTotalCode(Total)) {
case "A":
MessageBox.Show("you got an A");
break;
...
}
Welcome, I've a problem with small funcion in switch.
My problem is "Use of unassigned local variable 'matrix'"
Here is a code:
static void Main(string[] args)
{
char wyj = 'n';
do
{
Console.WriteLine("1. add numbers into matrix \n2. show matrix \n3. end");
int a;
Console.Write("\nYour choice: ");
a = int.Parse(Console.ReadLine());
switch (a)
{
case 1:
Console.WriteLine("You choose: 1");
int element;
Console.Write("\nsize of matrix: ");
int matrixsize;
matrixsize = Int32.Parse(Console.ReadLine());
int[,] matrix = new int[matrixsize, matrixsize];
for (int i = 0; i <= matrixsize - 1; i++)
{
for (int j = 0; j <= matrixsize - 1; j++)
{
Console.Write("element{0},{1} =", i + 1, j + 1);
element = int.Parse(Console.ReadLine());
matrix[i, j] = element;
}
}
break;
case 2:
Console.WriteLine("You choose 2");
foreach (int x in matrix)
Console.Write(x);
break;
case 3:
Console.WriteLine("End the program? y- yes, n- no");
wyj = char.Parse(Console.ReadLine());
break;
}
}
while (wyj != 'y');
Console.WriteLine("Koniec programu!");
Console.ReadKey();
}
What i need to do?
After Doc Brown answer, in case 2 nothing happens, the matrix is empty.
I think the loop is the problem?
You should not assume that the user first enters 1, then 2, but expect that this might happen the other way round.
the declaration int[,] matrix must be done before the switch statement, and you should set the variable to null there int[,] matrix=null;
the initialization matrix = new int[matrixsize, matrixsize] can stay where it is, but
in the case 2 block, you have to check if matrix was initialized if(matrix!=null) {/*...*/}
You've made an assumption that the compiler can't verify--that you will always generate the matrix be forming viewing it. The compiler knows that this doesn't have to be the case in a switch statement, so it prevents you from using a variable which may never have been set (or in this case, even declared). If you want to keep this code, declare the variable outside of the case and initialize it to a new matrix. Then check in case two if it is safe to display.
The matrix variable is local to the switch. The case 2 uses the variable from case 1, because case does not introduce a scope, but it is never initialized there, because the initializer is not executed when doing case 2.
Moving the variable out of the switch will silence the error if you provide initializer, but it will still be a new variable in each iteration, so when you fill it in in case 1, it will come out empty when doing case 2 in next iteration. You need to move the variable all the way out of the loop to have to values persist.
You still should not assume that user provides the inputs in correct order, so in the case 2 you have to check that the matrix was already filled in.
Im new to c# and Im having a little problem. I want to make an easy program to ask the user for a integer number between 1-50, and then to display on the console if its a odd number or not. So, what i tried is this:
Console.WriteLine("Skriv ut ett heltal: ");
int x = int.Parse(Console.ReadLine());
if (x == 1,3,5,7,9,11,13,15,17,19)
{
Console.WriteLine("The number is odd");
}
else
{
Console.WriteLine("The number is not odd");
}
Now i get an error at my if statements condition. How can i fix this?
C# does not allow you specify multiple values to check a variable against using a single if statement. You would need to check each value (1, 3, 5, etc) individually if you wanted to do it this way, and that would be a lot of redundant typing.
In this particular example, an easier way to check if something is odd or even is to check the remainder after dividing by 2, using the modulus operator %:
if (x % 2 == 1)
{
Console.WriteLine("The number is odd");
}
else
{
Console.WriteLine("The number is even");
}
However, if you really do need to check against a list, then the easy way is to use the Contains method on an array (an ICollection<T>, really). To make it nice and easy, you could even write an extension function that lets you check against a list in a syntactically pretty fashion:
public static class ExtensionFunctions
{
public static bool In<T>(this T v, params T[] vals)
{
return vals.Contains(v);
}
}
Then you could say:
if (x.In(1,3,5,7,9,11,13,15,17,19))
{
Console.WriteLine("The number is definitely odd and in range 1..19");
}
else
{
Console.WriteLine("The number is even, or is not in the range 1..19");
}
Voila! :)
if(x % 2 == 0)
{
// It's even
}
else
{
// It's odd
}
If you want to test whether x is a number in a particular list:
int[] list = new int[]{ 1,3,5,7,9,11,13,15,17,19};
if(list.Contains(x))
The common way to check to see if an integer is odd is to check if it divides evenly by 2:
if(x % 2 == 1)
x == 1,3,5,7,9,11,13,15,17,19 is not valid syntax for expressing multiple options. If you really want to do this then you can use a switch statement:
switch(x) {
case 1:
case 3:
case 5:
case 7:
case 9:
case 11:
case 13:
case 15:
case 17:
case 19:
// is odd
break;
default:
// is even
break;
}
The correct way would be to use the modulo operator % to determine if a number is exactly divisible by 2 or not, rather than trying every odd number, like so:
if( x % 2 == 0 ) {
// even number
} else {
// odd number
}
That's not valid C#. You can't test set inclusion like that. In any case, it's not practical to test for all the numbers in the world.
Why don't you just do this instead;
if (x &1 == 1) // mask the 1 bit
Bitwise operations are pretty quick so that code should be pretty fast.
Your if statement should be like this if you are having multiple conditions:
if any 1 of conditions is true:
if(x == 1 || x == 3 || x == 5)
{
//it is true
}
if all of the condition must be true:
if(x == 1 && y == 3 && z == 5)
{
//it is true
}
But if you are only looking for odd/even numbers. Use the % operator as the other answer says.
While, as others have pointed out, this is not the best way to solve this problem, the reason you're getting an error in this case is because you can't have multiple values like that in an if statement. You have to word it like this:
if (x == 1 || x == 3 || x == 5)
If you don't know, || is the symbol for 'or'
Try the following:
Console.WriteLine("Skriv ut ett heltal: ");
int x = int.Parse(Console.ReadLine());
Console.WriteLine(x % 2 == 1 ? "The number is odd" : "The number is not odd");
x % 2 == 1 does a modulus of 2 on the input (takes as many '2's off as possible until the number is between 0 and 2 - so 0 or 1 in this case)
One way to do that is:
if (x == 1 || 3 || 5){
Console.writeLine("oddetall");
}
or so it is possible to create an Array []
int[] odd = new int[3]; // how many odd to be tested
if(x=odd){
Console.WriteLine("Oddetall");
}