I am currently trying to get my snake console game running but I have came up with something that I do not quite understand. I don't really think that the != operator is not working correctly, so I must have made a mistake but I have no idea why it it is like that:
// not working
if (food.x != snakeElements.Last().x && food.y != snakeElements.Last().y)
// working
if (!(food.x == snakeElements.Last().x && food.y == snakeElements.Last().y))
Isn't it all the same?
Using De Morgan's laws (!a && !b) is the same as !(a || b) so your first example should be:
if (food.x != snakeElements.Last().x || food.y != snakeElements.Last().y)
The && should be || in the first if.
if (food.x != snakeElements.Last().x || food.y != snakeElements.Last().y)
If you write out what you actually mean by your boolean condition, you can see more clearly what the difference is.
// not working
if (food.x != snakeElements.Last().x && food.y != snakeElements.Last().y)
This means:
"The food is not in the same column as the last snake element, and the food is not in the same row as the last snake element"
The logic error is a bit more obvious now. What if the food's position is (10,3), and the last element's position is (14,3)?
Compare with:
// working
if (!(food.x == snakeElements.Last().x && food.y == snakeElements.Last().y))
Which means:
"It's not true that (the food is in the same row as the last snake element and the food is in the same column as the last snake element)"
Now the condition is false if and only if the food has the same X and Y as the last snake element.
No, it is not same.
If this works...
if (!(food.x == snakeElements.Last().x && food.y == snakeElements.Last().y)) // working
Then this should work too...
if (food.x != snakeElements.Last().x || food.y != snakeElements.Last().y) // should work
Notice the change in the sign from logical AND (&&) to logical OR (||).
I think the boolean logic is different in two cases:
both comparisons must be not equal for the if to evaluate to true.
either one has to be not equal for if to evaluate to true
They are different.
To be clear, I'll call food.x as X and snakeElements.Last().x as X', others as Y and Y'.
First one is saying:
if X is different than X' AND Y is different than Y' is true
Second one is saying:
if X is equal to X' AND Y is equal to Y' is false
Assume that X, X', Y, Y' are integers
If we say that X = 3, X' = 5, Y = 1, Y' = 4, first statement is true, because X != X' Y != Y' are both true. However, second would also be true becase X is not equal to X'.
Related
I thought I understood programming well enough to get the results I was looking for but alas this simply is not working for me. I've reduced my code to a simple Console application for assistance. The goal was to print out a 5x5 grid of 1's and 0's. Actually, I wanted to create a random x and y value such as 2 and 1 and I call this EmptyX and EmptyY. In this spot and only this spot, I should get a '0' printed. In all other cells there should be '1'. So it should be a grid of all 1's expect for the spot identified by EmptyX and EmptyY. My code below, although works, puts zero's down the entire column and row.
Why is this happening? I keep looking at my code and it seems my logic is good to me but of course it is not. How else can I make the grid with only a single 0 at the spot EmptyX and EmptyY?
class Program
{
static void Main(string[] args)
{
int EmptyX = new Random().Next(5);
int EmptyY = new Random().Next(5);
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
if ((x != EmptyX) && (y != EmptyY))
Console.Write("1");
else
Console.Write("0");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
Something like this with the 2 and 1 example:
11111
11011
11111
11111
11111
The problem is you have confused AND and OR in the context of NOT. This is a very common logic error (as seen in this post).
If conditions, believe it or not, can mess up even experienced developers. I have seen it happen (never intentionally) over and over to senior developers who aren't paying attention. So, be reassured, you are not alone.
The best way to deal with complicated if conditions is to write Ridiculously Obvious Code (ROC) where you make the point of the logic ridiculously clear by using obvious naming and maybe being a bit verbose with the code. In most cases, drawing out the code a bit doesn't affect performance, because the compiler will optimize out the extra working variables and generate exactly the same IL.
So for example, instead of writing
if ((x != EmptyX) || (y != EmptyY)) //I fixed it for you
Console.Write("1");
else
Console.Write("0");
You could write something like
bool isOnEmptyColumn = (x == EmptyX);
bool isOnEmptyRow = (y == EmptyY);
bool isOnEmptyCell = isOnEmptyColumn && isOnEmptyRow;
if (isOnEmptyCell)
{
Console.Write("0");
}
else
{
Console.Write("1");
}
The above takes several lines more of code but is ridiculously obvious, and makes it much harder to goof up the combination of your logical operators.
If you find that the verbosity of the logic check makes your method too long, you can extract the logic to a separate function. In this example, I also use guard pattern to simplify the logic even further:
private bool IsOnEmptyCell(int x, int y)
{
if (x != EmptyX) return false;
if (y != EmptyY) return false;
return true;
}
//Main program
if (IsOnEmptyCell(x,y))
{
Console.Write("0");
}
else
{
Console.Write("1");
}
Again, rest assured this won't affect performance, as the compiler will automatically inline your code when necessary. The important thing is to focus on writing source code that is easy to understand and difficult to misunderstand.
your code will print 0 whenever
x=EmptyX or y=EmptyY
for example
if EmptyX =3 and EmptyY=3 and x=0 and y=3
if ((x != EmptyX) && (y != EmptyY))
if ((x != 3) && (y != 3))
if ((0 != 3) && (3 != 3))
if ((true) && (false))
if (false)
and it will not print '1' when it should.
change your condition to
if ((x != EmptyX) || (y != EmptyY))
Modify your if else condition.
Method-1.
if ((x == EmptyX) && (y == EmptyY))
Console.Write("0");
else
Console.Write("1");
Method-2.
if ((x != EmptyX) || (y != EmptyY))
System.out.print("1");
else
System.out.print("0");
In C#, if I want to check to make sure that a value does not equal X or Y, I would write something like this:
if(x != 1 && x != 2)
{
//dosomething
}
I want to see if there is a way to write that with OR instead of AND. Something like this (which doesn't work, but its what I am trying to do):
if(x != (1 || 2))
{
//dosomething
}
Obviously that doesn't work because it is trying to evaluate 1 || 2 as its own statement. Does there exist a way to write that correctly?
You can always invert an AND into an OR:
if (!(x == 1 || x == 2))
{
...
}
You have to reverse all the conditions to do it though, as above. The process for doing so is described in De Morgan's Laws (thanks #RichardEverett!).
You could try this one:
if(!(x == 1 || x == 2))
but honestly, I don't see the reason of doing so.
This statement if(x != 1 && x != 2) is far more clear and readable than the above and it does the same.
This (x == 1 || x == 2) evaluates to true if x is either 1 or 2. Hence taking the negation of this, you get that you want.
No, C# doesn't support such a construct presently.
The following is about as close as I could get it, but it's slow!
if (!new[] { 1, 2 }.Contains(x)) { ... }
OK, So here is my if check, no matter how I've tried it, it's not going through properly, it keeps stopping.
DateTime now = new DateTime();
string s = "Everyday";
string currentTime = now.ToString("HH:mm");
string remDate = "21:00"; //set to a minute or two i the future
string CurrentDay = "Sunday";
if ((s.ToUpper() == "WORKDAYS") ||(s.ToUpper() == "EVERYDAY" || s.ToUpper() == CurrentDay.ToUpper())
&& ((currentTime == remDate) && (s.ToUpper() != "SUNDAY") && (s.ToUpper() != "SATURDAY")))
{
MessageBox.Show("Success!!!!");
}
So when it hits the if check, it stops, never gets to the message box. No matter what order I've tried the checks it's not working, been staring at this for a while, thought someone out there could either show me a better way, or see what I'm missing.
Cause it will work only at 21:00
UPD:
Sorry, it was mistake. Real reason in first line
You have to write DateTime now = DateTime.Now;
If you see that your s is Everyday, hence the first condition is met. But you have AND condition with
(currentTime == remDate) && (s.ToUpper() != "SUNDAY") && (s.ToUpper() != "SATURDAY")
which will only be true when time is 21:00
which isn't true at this time. Hence the condition is failed.
Lets start by making your code more readable, which also helps show your || and && issues.
DateTime now = new DateTime();
string s = "Everyday";
string currentTime = now.ToString("HH:mm");
string remDate = "21:00"; //set to a minute or two i the future
string CurrentDay = "Sunday";
if (
// condition 1
(s.ToUpper() == "WORKDAYS")
// condition 2
|| (
s.ToUpper() == "EVERYDAY"
|| s.ToUpper() == CurrentDay.ToUpper()
)
// condition 3
&& (
// condition 3.1
(currentTime == remDate)
&& (s.ToUpper() != "SUNDAY")
&& (s.ToUpper() != "SATURDAY")
)
)
{
// I'm using LINQPad, so I just output this to the results
"Success!!!!".Dump();
}
One issue is condition 3.1: (currentTime == remDate). Given the sample input provided this has to be true, so your message box will only display when the time is 21:00.
Another issue is that condition 2 and condition 3 will (because they are joined with &&) be treated as a group. Is this what you really meant?
The logic of this if statement is hard to follow and the grouping or/and expressions add to the confusion.
Try writing the conditions out in english, maybe as a bullet list, and see if the mistake doesn't become obvious to you.
Here I assume that your variable CurrentDay is equal to DayOfWeek.Monday.ToString().ToUpper().
according to your statement, it looks like
if(false || true && false)
Because (s.ToUpper() == "WORKDAYS") is always false, until you change s.
and (s.ToUpper() == "EVERYDAY" || s.ToUpper() == CurrentDay.ToUpper()) is always true until you change s
and ((currentTime == remDate) && (s.ToUpper() != "SUNDAY") && (s.ToUpper() != "SATURDAY")
&& (CurrentDay == s)) is always false, because (CurrentDay == s) is false.
Hence if statement is always false, then MessageBox.Show("Success!!!!"); cannot be executed..
I got it working. I should have explained it better, what I was trying to do is have it check the time of day and then check the day, and then have an alert pop up, the values come from the end user, stored in a sqlite db.
The problem was the grouping and the order and I had a duplicate check in my code.
what i ended up with was:
if ((s.ToUpper() == "WORKDAYS") || (s.ToUpper() == "EVERYDAY" || s.ToUpper() == CurrentDay.ToUpper())
&& ((currentTime == remDate) && (s.ToUpper() != "SUNDAY") && (s.ToUpper() != "SATURDAY")))
{
}
I had it do all my OR checks first, then had it pull in the last group of AND's and then i grouped them, this works for me and does the job.
I'm writing my own reminder application and this was my weekday check that i implemented. Probably a better way to do it, but this was what i came up with.
Thanks for the help
replace:
string currentTime = now.ToString("HH:mm");
and
(currentTime == remDate)
by this:
DateTime currentTime = DateTime.Now
and
(currentTime.ToString("HH:mm") == remDate)
I want to create a simple do-while statement that makes sure the user input is either Y or N and if not asks them to input again. If it is Y or N then the app continues. This is what I have so far but my application though it is just stuck in a loop asking the user input. New to C# -- thanks for any help.
string answer = "";
do
{
//Ask the user if they want to roll the dice
Console.WriteLine("Would you like to roll the dice (y or n)?");
//Get the user's response and validate that it is either 'y' or 'n'.
answer = Console.ReadLine();
} while (answer != "Y" || answer != "N");
Looks like a simple boolean logic error.
Your while statement should be:
while (answer != "Y" && answer != "N");
Since you want to be sure that the answer is not yet Y and the answer is also not yet N. Loop while it is neither. Hope this helps!
Your logic is OR || instead of AND &&. It will always either not be Y or not be N because it cannot be BOTH at once. When it's N it isn't Y and the opposite is also true.
Use AND && instead.
Also, your comparison is case sensitive. Consider checking for upper and lower case.
2 things
As all said replace || with &&
Match uppercase of what user enter with your Y & N cause user can enter y. A Y and y, both are positive decisions of user.
answer.ToUpper() != "Y" && answer.ToUpper() != "N"
Change the || to an && and this should fix it for you.
Another way to look at it could be this:
The break conditions is whenever the answer is "Y" or the answer is "N".
You want the loop to continue whenever the break condition is not met so you can have
(answer == "Y" || answer == "N") and then not the result
while(!(answer == "Y" || answer == "N")
I'm teaching myself some C# and got the idea to build a temperature calculator. I want to use a do-while loop to ensure the user picks a valid menu choice. What I tried to do was:
do
{
//etc etc etc;
} (while menuChoice != 1||2||3);
In other words, keep doing what is inside the loop unless menuChoice is 1, 2 or 3. VS2010 Express tells me I can't do that. Is there a way to do this that way or do I have to do something else? Any suggestions on how to do this or should I use some other solution?
do { // stuff
} while (menuChoice != 1 && menuChoice != 2 && menuChoice != 3);
do {
// etc.
} while(menuChoice != 1 &&
menuChoice != 2 &&
menuChoice != 3
);
Each of the clauses of a conjunction must be an expression that evaluates to a bool. Note that != 2 is not an expression that evaluates to a bool. In fact, it's not even a legal expression. This is why you must specify menuChoice != 2.
Also, note that you should use && because the clauses. You want menuChoice to equal 1, or to equal 2, or to equal 3. Therefore you want
!(menuChoice == 1 || menuChoice == 2 || menuChoice == 3)
as the condition in the while loop. By DeMorgan's Laws, this is equivalent to
menuChoice != 1 && menuChoice != 2 && menuChoice != 3
EDIT:
How about this? this would allow you to have a non-contiguous set of numbers and is far more extensible than having a million || statements...:
int[] menuOptions = { 1, 2, 3 };
...
while(!menuOptions.Contains(menuChoice))
Or:
do {
// etc.
} while(menuChoice > 3 || menuChoice < 1);
Just to provide yet one more solution:
using System.Collections.Generic; // for the List<T>
do
{
}
while (!(new List<Int32>(new[]{ 1, 2, 3 })).Contains(menuChoice));
And yes, this is not the best solution, it is, however, an alternative (and useful if your list of options grows).