Re-factor common code between if and else if [closed] - c#

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have an if...else if statement as follows:
If(x > y && order.invoice != 1)
{
DoSomething();
x = x + y;
}
else if(order.invoice == 1)
{
x = x + y;
}
Is there a better way to re-factor this. I kind of not feeling well having x = x + y in both if and else if.

if (order.invoice != 1 && x > y) {
DoSomething();
}
if (order.invoice == 1 || x > y) {
x = x + y;
}

You can either do the assignment twice or do one of the if statements twice. This calculation is simple enough that I wouldn't worry about it.
It can be shortened as such, though:
if(x > y && order.invoice != 1)
{
DoSomething();
x += y;
}
else if(order.invoice == 1)
{
x += y;
}
One more option could be to use an flag to see whether or not to increment, but you still have the same tug-of-war between complexity and single calls vs. simplicity and semi-redundant code.
bool increment = false;
if(x > y && order.invoice != 1)
{
DoSomething();
increment = true;
}
else if(order.invoice == 1)
{
increment = true
}
if (increment) { x += y; }

Here's a proof/systematic way to refactor it. Start with:
if (x > y && order.invoice != 1)
{
DoSomething();
x = x + y;
}
else if (order.invoice == 1)
{
x = x + y;
}
So the question is, what set of inputs leads to x = x + y? Well:
x = x + y
<=> (x > y && order.invoice != 1) ||
(!(x > y && order.invoice != 1) && order.invoice == 1)
<=> (x > y && order.invoice != 1) ||
((x <= y || order.invoice == 1) && order.invoice == 1)
<=> (x > y && order.invoice != 1) ||
((x <= y && order.invoice == 1) || (order.invoice == 1 && order.invoice == 1)
<=> (x > y && order.invoice != 1) ||
((x <= y && order.invoice == 1) || order.invoice == 1)
<=> (x > y && order.invoice != 1) ||
order.invoice == 1
<=> (x > y || order.invoice == 1) && (order.invoice != 1 || order.invoice == 1)
<=> (x > y || order.invoice == 1)
Thus it's equivalent to
if (x > y && order.invoice != 1)
{
DoSomething();
}
if (x > y || order.invoice == 1)
{
x = x + y;
}
You can also use a truth table
x > y | order.invoice == 1 | x = x + y
F | F | N
F | T | Y
T | F | Y
T | T | Y
which again gives you
x = x + y
<=> !(x <= y && order.invoice != 1)
<=> x > y || order.invoice == 1
Lastly, I disagree with this sort of refactoring unless it actually makes the code more understandable.
Saving lines of code doesn't mean you made the code more readable (and therefore does not make it
obviously more maintainable)

Related

recursive stackoverflow minesweeper c#

I am writing a game of minesweeper. Below is code for 3 methods in minesweeper. The first method is to check all the spaces around the button pressed and to count how many bombs are around it. The next method is to be called recursively, in order that if the user pressed a button with 0 buttons around it, it will open all of the squares that also indicate 0 squares around it. The third method is to check that it will be in bound the check. The empty space recursive call is getting me a stackoverflow error, what am I doing wrong?
Thanks!
private int GameLogicChecker(int x, int y)
{
int count = 0;
if (_grid[x, y] != -1)
{
if (x + 1 < SizeX)
{ //Right
if (_grid[x + 1, y] == -1)
count++;
}
if (x - 1 > 0)
{ //Left
if (_grid[x - 1, y] == -1)
count++;
}
if (y + 1 < SizeY)
{ //Upper
if (_grid[x, y + 1] == -1)
count++;
}
if (y - 1 > 0)
{ //Lower
if (_grid[x, y - 1] == -1)
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY)
{ //Right-Upper
if (_grid[x + 1, y + 1] == -1)
count++;
}
if (x + 1 < SizeX && y - 1 > 0)
{ //Right-Lower
if (_grid[x + 1, y - 1] == -1)
count++;
}
if (x - 1 > 0 && y + 1 < SizeY)
{ //Left-Upper
if (_grid[x - 1, y + 1] == -1)
count++;
}
if (x - 1 > 0 && y - 1 > 0)
{ //Left-Lower
if (_grid[x - 1, y - 1] == -1)
count++;
}
}
return count;
}
void OpenEmptySpace(int x, int y)
{
for (var k = -1; k <= 1; k++)
{
for (var l = -1; l <= 1; l++)
{
if (CheckBounds(x + k, y + l) && GameLogicChecker(x + k, y + l) == 0)
{
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
}
}
}
private bool CheckBounds(int x, int y)
{
return x >= 0 && x < SizeX && y >= 0 && y < SizeY;
}
For k = 0 and l = 0, you are calling yourself again and again and again...
Thanks to #BenVoigt for pointing out that two zeroes adjacent to each other will also lead to infinite recursion. So, in order to solve that one method is to create a boolean grid too and set a particular cell's value to true if it has been run through once. Assuming the grid is called Explored, I've added the condition for it in the code below.
If you insist on your current code, try changing the condition to:
if (CheckBounds(x + k, y + l)
&& GameLogicChecker(x + k, y + l) == 0
&& !(k == 0 && l == 0)
&& !Explored[x + k, y + l])
{
Explored[x + k, y + l] = true;
_buttons[x + k, y + l].Text = "0";
OpenEmptySpace(x + k, y + l);
}
Here is another answer for you, rewriting your methods one-by-one following better coding practices. Like in the other answer, a boolean grid called Explored[SizeX, SizeY] has been assumed.
1. GameLogicChecker()
private int GameLogicChecker(int x, int y)
{
if (_grid[x, y] == -1) return 0;
int count = 0;
if (x + 1 < SizeX && _grid[x + 1, y] == -1) //Right
{
count++;
}
if (x - 1 > 0 && _grid[x - 1, y] == -1) //Left
{
count++;
}
if (y + 1 < SizeY && _grid[x, y + 1] == -1) //Upper
{
count++;
}
if (y - 1 > 0 && _grid[x, y - 1] == -1) //Lower
{
count++;
}
if (x + 1 < SizeX && y + 1 < SizeY && _grid[x + 1, y + 1] == -1) //Right-Upper
{
count++;
}
if (x + 1 < SizeX && y - 1 > 0 && _grid[x + 1, y - 1] == -1) //Right-Lower
{
count++;
}
if (x - 1 > 0 && y + 1 < SizeY && _grid[x - 1, y + 1] == -1) //Left-Upper
{
count++;
}
if (x - 1 > 0 && y - 1 > 0 && _grid[x - 1, y - 1] == -1) //Left-Lower
{
count++;
}
return count;
}
What's better? Quicker returning from the method for special case. Reduced nesting in If(...) blocks.
2. OpenEmptySpace()
public/private void OpenEmptySpace(int x, int y)
{
for (var deltaX = -1; deltaX <= 1; deltaX += 2)
{
for (var deltaY = -1; deltaY <= 1; deltaY += 2)
{
var thisX = x + deltaX;
var thisY = y + deltaY;
if (OpeningNotNeeded(thisX, thisY))
{
continue;
}
Explored[thisX, thisY] = true;
_buttons[thisX, thisY].Text = "0";
OpenEmptySpace(thisX, thisY);
}
}
}
private bool OpeningNotNeeded(int x, int y)
{
return !CheckBounds(x, y)
|| GameLogicChecker(x, y) != 0
|| Explored[x, y];
}
What's better? Properly named indexing variables in both loops. Properly written condition (+= 2 instead of ++). Reduced nesting in If(...). Easier to read method call in the If(...) instead of three predicates. Useful temporary variables added which make it clear what x + k and y + l were in the code written earlier.
3. CheckBounds() is written fine.

C# IndexOutOfRange Array Exception

I'm trying to create a 2D char array to hold a grid of chars which will be used as a sort of 'map' for a 2D console game.
I am getting a:
IndexOutOfRange exception
..and cannot see why. I've stepped through the code in debug mode and still cannot see the issue.
It steps through the code fine until it hits X = 25 and Y = 1, the upper right boundary of my grid.
I have _gameWidth and _gameHeight created as follows, outside of main but still inside the class:
static int _gameWidth = 25;
static int _gameHeight = 15;
Following is the code that fails, when trying to generate and populate the grid. It fails at this point:
else if (x == _gameWidth && y == 1)
_grid[x, y] = '╕';
static void GenerateGrid()
{
for (int y = 1; y <= _gameHeight; y++)
{
for (int x = 1; x <= _gameWidth; x++)
{
if (x == 1 && y == 1)
_grid[x, y] = '╒';
else if (x == _gameWidth && y == _gameHeight)
_grid[x, y] = '╛';
else if (x == _gameWidth && y == 1)
_grid[x, y] = '╕';
else if (x == 1 && y == _gameHeight)
_grid[x, y] = '╘';
else if ((x != 1 && y == _gameHeight) || (x != _gameWidth && y == 1))
_grid[x, y] = '═';
else if ((x == 1 && y > 1 && y < _gameHeight) || (x == _gameWidth && y > 1 && y < _gameHeight))
_grid[x, y] = '│';
else
_grid[x, y] = 'x';
}
Console.WriteLine("");
}
}
Change
for (int i = 1; i <= gameHeight; i++)
to
for (int i = 0; i < gameHeight; i++)
and do the same for width.
EDIT:
This is because array indexes start at the number 0 and end with the length of the array minus 1.
This exception means that you have accessed an invalid index. From the way you have written the loop I can tell that you think that indexes go from 1 to the length of the array. Arrays are zero-based, though. Use the standard loop form:
for (int i = 0; i < length; i++)
Your loop starts at one. You can use the Visual Studio for loop template. Just type "for<tab><tab>".
Your program might benefit from the Code Review Stack Exchange site.

Add selected elements to list using for loop

I'm trying to add the integers 6 from 30, except for 22 and 26, to a List using a for loop. But 22 and 26 are still being added. What did I do wrong?
List<int> lineNumbers = new List<int>();
for (int x = 6; x < 30; x++)
{
if ((x != 22) || (x != 26))
{
lineNumbers.Add(x);
}
}
The two integers are not added if the code is like below:
for (int x = 6; x < 30; x++)
{
if (x == 22 )
{
}
else if (x == 26)
{
}
else
{
lineNumbers.Add(x);
}
}
You need to replace the || with &&:
for (int x = 6; x < 30; x++)
{
if ((x != 22) && (x != 26))
{
lineNumbers.Add(x);
}
}
Or perhaps, to be more clear:
for (int x = 6; x < 30; x++)
{
if ((x == 22) || (x == 26))
continue;
lineNumbers.Add(x);
}
Alternatively, you could perform this as a one-liner using LINQ. This isn't necessarily faster or anything, so if your for loop is clearer to you, then keep it as-is.
lineNumbers.AddRange(Enumerable.Range(6, 24).Except(new[] { 22, 26 }));
Change your conditions. Use && instead of ||
if ((x != 22) && (x != 26))
Use && instead of || because you want to match between both conditions.
if ((x != 22) && (x != 26))
You can also do this using LINQ (not necessarily but I like LINQ :)
var lineNumbers = Enumerable.Range(6, 30).Except(new[] {22, 26}).ToList();
Replace if ((x != 22) || (x != 26)) to if ((x != 22) && (x != 26))
Or you can use continue like below :
for (int x = 6; x < 30; x++)
{
if ((x == 22) || (x == 26))
continue;
else
lineNumbers.Add(x);
}

Modulus Visual Studio 2013

I was just wondering how I could state if x + y + z % 2 == 0 BUT only do this statement IF the three values aren't set to 0. I require the values to be 0.
Example of my code & posStatus may hold variables of the value 0. The problem is when all three of them are 0 an issue occurs. The user and program over time fill in these values.
else if (posStatus[0] + posStatus[4] + posStatus[8] % 2 == 0)
{
if (posStatus[0] == 0)
{
posStatus[0] = 2;
return;
}
else if (posStatus[4] == 0)
{
posStatus[4] = 2;
return;
}
else if (posStatus[8] == 0)
{
posStatus[8] = 2;
return;
}
}
if((x!=0 && y!=0 && z!=0) && x + y + z % 2 == 0)
//do your stuff
Logical operators in C# are converted to series of if-else constructions during compilation, so if first condition is not true, other ones won't be checked.
if(posStatus[0] != 0 &&
posStatus[4] != 0 &&
posStatus[8] != 0 &&
(posStatus[0] + posStatus[4] + posStatus[8]) % 2 == 0)
{
// Do something
}
if((posStatus[0]!=0 && posStatus[4]!=0 && posStatus[8]!=0) &&
(posStatus[0] + posStatus[4] + posStatus[8]) % 2 == 0)
{
}

Replace buttons location

l have problem with my c# winform project.
In my project I have a function that switches the location of buttons to their old location if they are in the same area.
private void myText_MouseUp(object sender, MouseEventArgs e)
{
Point q = new Point(0, 0);
Point q2 = new Point(0, 0);
bool flag = false;
int r = 0;
foreach (Control p in this.Controls)
{
for (int i = 0; i < counter; i++)
{
if (flag)
{
if (p.Location.X == locationx[i] && p.Location.Y == locationy[i])
{
oldx = e.X;
oldy = e.Y;
flag = true;
r = i;
}
}
}
}
foreach (Control p in this.Controls)
{
for (int j = 0; j < counter; j++)
{
if ((locationx[j] == p.Location.X) && (locationy[j] == p.Location.Y))
{
Point arrr = new Point(oldx, oldy);
buttons[j].Location = arrr;
buttons[r].Location = new Point(locationx[j], locationy[j]);
}
}
}
}
The problem with this code is that if they are in the same area, the buttons do not switch their locations. Instead they goes to the last button location.
If someone could help me that will help me alot :)
The if statement always evaluates to true. This means that the final j loop will do this:
// last time round the i loop, i == counter-1
// and q == new Point(locationx[counter-1], locationy[counter-1])
for (int j = 0; j < counter; j++)
{
Point q2 = new Point(locationx[j], locationy[j]);
buttons[i].Location = q2;
buttons[j].Location = q;
}
The net result of this is that every button's Location is set to q, which is
new Point(locationx[counter-1], locationy[counter-1])
Why does the if statement always evaluate to true. Well, first of all let's look at a couple of the or clauses in the if statement:
|| ((q.Y >= q2.Y) && (q.X <= q2.X))
|| ((q.Y >= q2.Y) && (q.X == q2.X))
This is equivalent to
|| ((q.Y >= q2.Y) && (q.X <= q2.X))
The line containing the == test has absolutely no impact on the final result of the condition. In fact all the lines containing == can be similarly treated. This leaves:
|| ((q.Y >= q2.Y) && (q.X <= q2.X))
|| ((q.Y >= q2.Y) && (q.X >= q2.X))
|| ((q.Y <= q2.Y) && (q.X >= q2.X))
|| ((q.Y <= q2.Y) && (q.X <= q2.X))
We can condense
|| ((q.Y >= q2.Y) && (q.X <= q2.X))
|| ((q.Y >= q2.Y) && (q.X >= q2.X))
into
|| ((q.Y >= q2.Y)
and similarly
|| ((q.Y <= q2.Y) && (q.X >= q2.X))
|| ((q.Y <= q2.Y) && (q.X <= q2.X))
is the same as
|| ((q.Y <= q2.Y)
Combine
|| ((q.Y >= q2.Y)
|| ((q.Y <= q2.Y)
and you can see that the if condition always evaluates to true.

Categories