Shorting long if statement - c#

I have spent hours making a tic tac toe game just using mainly if else statements, some of the code I just copy and pasted...
How would I just create one instance of the code, then refer to it later on? - when I need that code, instead of just copy and pasting massive lines of code each time. In this block of code, I am getting a random number between 1 to 10 this number will be stored in RI... then when it's Ai's turn the computer will randomly input an X in the button, then using this code it will check to determine if the computer has won. I hope that make sense =)
do
{
storeRI = rc.Next(0, 10); //storing random number into storeRI so it can be used later on in life.
if (storeRI == 1 && btn1.Text == "")
{
btn1.Text = "X";
Turn = 1;
if (btn1.Text == "X" & btn2.Text == "X" & btn3.Text == "X")
{
btn1.BackColor = Color.Green;
btn2.BackColor = Color.Green;
btn3.BackColor = Color.Green;
XScore += 1;
lblPScoreX.Text = XScore.ToString();
foreach (Button btn in buttonList)
btn.Enabled = false;
}
else if (btn1.Text == "X" & btn4.Text == "X" & btn7.Text == "X")
{
btn1.BackColor = Color.Green;
btn4.BackColor = Color.Green;
btn7.BackColor = Color.Green;
XScore += 1;
lblPScoreX.Text = XScore.ToString();
foreach (Button btn in buttonList)
btn.Enabled = false;
}
}
}
for example this code, is some of the code, that I have copied atleast 10 times, and it just makes me code look ugly and really hard to read.

for example this code, is some of the code, that I have copied atleast 10 times
Any time you have copied code, you should try to move it into a method. You can then just call the method directly. In your case, a method could easily accept the three buttons to affect, and work on them directly.

bool TestWin(Button btnA, Button btnB, button btnC)
{
if (btnA.Text == "X" & btnB.Text == "X" & btnC.Text == "X")
{
btnA.BackColor = Color.Green;
btnB.BackColor = Color.Green;
btnC.BackColor = Color.Green;
XScore += 1;
lblPScoreX.Text = XScore.ToString();
foreach (Button btn in buttonList)
{
btn.Enabled = false;
}
return true;
}
return false;
}
if (!TestWin(btn1, btn2, btn3))
TestWin(btn1, btn4, btn7);

The refactoring technique you may want to look into is Consolidate Duplicate Conditional Fragments
if (btn1.Text == "X" & btn2.Text == "X" & btn3.Text == "X")
{
btn2.BackColor = Color.Green;
btn3.BackColor = Color.Green;
}
else if (btn1.Text == "X" & btn4.Text == "X" & btn7.Text == "X")
{
btn4.BackColor = Color.Green;
btn7.BackColor = Color.Green;
}
else
{
return/break/continue; // hard to tell which you what as you have a do without a corresponding while
}
btn1.BackColor = Color.Green;
XScore += 1;
lblPScoreX.Text = XScore.ToString();
foreach (Button btn in buttonList)
{
btn.Enabled = false;
}

if (btn1.Text == "X")
{
btn1.BackColor = Color.Green;
if(btn2.Text == "X" & btn3.Text == "X")
btn2.BackColor = Color.Green;
btn3.BackColor = Color.Green;
}
else if (btn4.Text == "X" & btn7.Text == "X")
{
btn4.BackColor = Color.Green;
btn7.BackColor = Color.Green;
}
XScore += 1;
lblPScoreX.Text = XScore.ToString();
foreach (Button btn in buttonList)
{
btn.Enabled = false;
}
}

Nothing wrong with a long if else statement; it's better to have long readable code than short unmanageable code.
The one thing I can see that might help is to add in a method (with some changed to match your types):
public void ChangeButtonColor(Color thisColor, params Button[] buttons)
{
foreach (Button thisButton in buttons)
{
thisButton.BackColor = thisColor
}
}
then you can just add in to you code:
ChangeButtonColor(Color.Green, btn1, btn2, btn3);
This would save you some duplicated code.

Related

NullExceptionError when trying to load image from Resources

I have my resources embedded in the system, the string I search for them with matches the name of the image yet I still get a ArgumentNullException... How come?
//Check if currencies are chosen
private void Action()
{
label1.Text = null;
//Checks if items are selected then what currencies are chosen
if (listBox1.SelectedIndex == -1 || listBox2.SelectedIndex == -1)
{
label1.Text = "Please select currencies";
}
else
{
LB1 = listBox1.SelectedItem.ToString();
LB2 = listBox2.SelectedItem.ToString();
Conversion();
}
pictureBox1.Image = Properties.Resources.ResourceManager.GetObject(LB1) as Image;
pictureBox2.Image = Properties.Resources.ResourceManager.GetObject(LB2) as Image;
}
Picture of Resource images
Thank you so much in advance!
You've got a small logic flaw. You are setting variables inside an if condition but using them outside, even if the if condition doesn't execute.
if (listBox1.SelectedIndex == -1 || listBox2.SelectedIndex == -1)
{
label1.Text = "Please select currencies";
}
else
{
LB1 = listBox1.SelectedItem.ToString(); //Doesn't always run
LB2 = listBox2.SelectedItem.ToString();
Conversion();
}
//Always runs
pictureBox1.Image = Properties.Resources.ResourceManager.GetObject(LB1) as Image;
pictureBox2.Image = Properties.Resources.ResourceManager.GetObject(LB2) as Image;
You should probably change it to something more like this:
if (listBox1.SelectedIndex == -1 || listBox2.SelectedIndex == -1)
{
label1.Text = "Please select currencies";
}
else
{
LB1 = listBox1.SelectedItem.ToString();
LB2 = listBox2.SelectedItem.ToString();
Conversion();
pictureBox1.Image = Properties.Resources.ResourceManager.GetObject(LB1) as Image;
pictureBox2.Image = Properties.Resources.ResourceManager.GetObject(LB2) as Image; }
}
Or better yet, use a guard, and use local variables, so that the compiler will catch this sort of flaw in the future:
if (listBox1.SelectedIndex == -1 || listBox2.SelectedIndex == -1)
{
label1.Text = "Please select currencies";
return;
}
var lb1 = listBox1.SelectedItem.ToString();
var lb2 = listBox2.SelectedItem.ToString();
Conversion(lb1, lb2);
pictureBox1.Image = Properties.Resources.ResourceManager.GetObject(lb2) as Image;
pictureBox2.Image = Properties.Resources.ResourceManager.GetObject(lb2) as Image;

Public void int increment by 1 every loop (Beginner)

I'd basically like to know how I can increase Player.SetPoints(); by 1 every time it loops. I got this in my class public void SetPoints(int p) { points = p; }, just thought that would be worth mentioning. So far the only way I've gotten this to work is to use Player.SetPoints(+1); but that only puts 1 to the scoreboard and never increases again. Sorry If I'm not clear enough, I'm very new to programming. This is a sample of my code so you might be able to understand it a bit more, I'm making a tic tac toe game as an assignment for school.
if (Btn1.Text != "" && Btn2.Text != "" && Btn3.Text != "")
{
if (Btn1.Text == Btn2.Text && Btn1.Text == Btn3.Text)
{
Btn1.BackColor = Color.Green;
Btn1.ForeColor = Color.White;
Btn2.BackColor = Color.Green;
Btn2.ForeColor = Color.White;
Btn3.BackColor = Color.Green;
Btn3.ForeColor = Color.White;
if (Btn1.Text == "X")
{
MessageBox.Show(lblpl1.Text + " Has Won!");
Player1.SetPoints(+0);
playerscore1.Text = Player1.GetPoints().ToString();
}
else
{
MessageBox.Show(lblpl2.Text + " Has Won!");
Player2.SetPoints(+0);
playerscore2.Text = Player2.GetPoints().ToString();
}
click1++;
click2++;
click3++;
click4++;
click5++;
click6++;
click7++;
click8++;
click9++;
restartbtn.Visible = true;
}
}
In order increase something in each button click you need to save the previous value in a variable. You are doing a similar think with clicks:
click1++;
Your method sets the points to a given value. If you give it 1 it sets it to 1. It looks like you don't want to set points to an individual value, you want to increase it each time, so instead of declaring a method like that you can change it to:
public void IncreasePoints()
{
points++;
}
And simply call it without passing any value.
Player1.IncreasePoints();

How to make two pictures not visible after a certain time

I'm making a memotest and I need to press two different images and they need to keep visible for 3-5 seconds. I've tried Thread.Sleep(5000) but it doesn't show me the second one. What should I do?
The only way I've founded to see for some seconds the images was by putting a MessageBox but that isn't the idea and I don't know other way to do it.
if (pic != null && pic.Name == fondos[i].Name)
{
if (CantClick == 0)
{
ParejaActual = listRandom[i].pareja;
CantClick = 1;
primerI = i;
picAnterior = pic;
imgAnterior = img;
pic.Visible = false;
}
else if (CantClick == 1)
{
pic.Visible = false;
if (ParejaActual == listRandom[i].pareja)
{
SoundPlayer simpleSound = (new SoundPlayer(Configuracion.RootFolder + "aplau.wav"));
simpleSound.Play();
Ganando++;
label3.Text = Ganando.ToString();
//MessageBox.Show("Si");
//NO SE DESTAPA LA SEGUNDA.
//Thread.Sleep(5000);
CantClick = 0;
img.Visible = false;
imgAnterior.Visible = false;
Application.DoEvents();
}
else
{
(new SoundPlayer(Configuracion.RootFolder + "sad.wav")).Play();
MessageBox.Show("No");
Mal++;
CantClick = 0;
label4.Text = Mal.ToString();
pic.Visible = true;
picAnterior.Visible = true;
}
}
}
Thank you!
Instead of using Thread.Sleep , use System.Timers class. After an interval, just hide one image and show the other. Tell me if you want any other help.

Telerik Radgridview Winforms Change Cell/Row background color

I am simply wanting to run a validation check fired from a button event on the form. For each row inside the grid, it checks the first cell to see if the value matches a string. For every one that fails, i'm wanting it to either change the cell or the row background color to be RED. When the user corrects the cell value and hit the button again, it will reverse back to the default color. For the life of me i can't get it to change the color. I know there is an event for cellformatting but surely i do not have to go through an event just to alter the style of a cell/row. I am trying the below code without any luck. All the examples i'v seen are event based so hoping i can avoid this entirely.
if (!ValidateParametersExistInScript(rtxtQuery.Text))
{
GridViewCellInfo cell = rgvNewParameters.Rows[0].Cells["ParameterName"];
cell.Style.BackColor = Color.Red;
cell.Style.DrawFill = true;
MessageBox.Show("Parameters do not match definition inside query, " +
"please check spelling and try again.");
}
You must first set CustomizeFill to true before you can modify the back color of the GridViewCellInfo.
if (!ValidateParametersExistInScript(rtxtQuery.Text))
{
GridViewCellInfo cell = rgvNewParameters.Rows[0].Cells["ParameterName"];
cell.Style.CustomizeFill = true;
cell.Style.BackColor = Color.Red;
cell.Style.DrawFill = true;
MessageBox.Show("Parameters do not match definition inside query, " +
"please check spelling and try again.");
}
private void radGridLedgerAccount_CellFormatting(object sender, CellFormattingEventArgs e)
{
if (e.RowIndex == 0 || e.RowIndex==radGridLedgerAccount.Rows.Count-1)
{
e.CellElement.DrawFill = true;
e.CellElement.ForeColor = Color.White;
e.CellElement.NumberOfColors = 1;
e.CellElement.BackColor = Color.Red;
}
else
{
if (e.CellElement.ColumnInfo.Name == "months") //checking for the text in header cell
{
if (e.RowIndex != 0)
{
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml("#6599FF");
e.CellElement.DrawFill = true;
e.CellElement.ForeColor = Color.White;
e.CellElement.NumberOfColors = 1;
e.CellElement.BackColor = col;
}
}
else
{
e.CellElement.DrawFill = true;
e.CellElement.ForeColor = Color.Black;
e.CellElement.NumberOfColors = 1;
e.CellElement.BackColor = Color.White;
e.CellElement.ResetValue(LightVisualElement.ForeColorProperty, ValueResetFlags.Local);
}
}

Dynamic GroupBoxes always align to top

I have this application where several groupboxes are in a vertical line. They can be enabled and disabled individually. I want to always align the groupboxes to the top, no matter if the ones normally being in between to is enabled or not.
Say we have three groupboxes (1, 2, 3). The middle one (2) gets disabled. Normally the two other boxes (1,3) locations wont be affected by this. But I want the last groupbox (3) to then take the place that the middle groupbox (2) would normally be in.
Any ideas how to accomplish this the most simple way?
This is what im doing at the moment which isnt good enough for scaling
if (isForgeIncluded == "True" | isForgeIncluded == "true")
{
forgeBox.Visible = true;
if (headerPic == "False" | headerPic == "false")
{
PictureBox1.Visible = false;
forgeBox.Location = new Point(6, 5);
pathBox.Location = new Point(6, 112);
}
else
{
}
}
else
{
forgeBox.Visible = false;
if (headerPic == "False" | headerPic == "false")
{
PictureBox1.Visible = false;
pathBox.Location = new Point(6, 5);
}
else
{
pathBox.Location = new Point(6, 168);
}
}
set groupbox2 location(x,y) to groupbox3 location(x,y) while your groupbox2 disables - might be from a specific event.
I managed to figure out a solution to this, which is "more dynamic" but not 100% dynamic, as i will have to go add new GroupBoxes to an array manually. However, this does work, and takes care of the picturebox in the beginning
int nextBoxLocation = 0;
int boxHeightAdd = 0;
int spacing = 6;
if (headerPic == "True" | headerPic == "true")
{
PictureBox1.Visible = true;
nextBoxLocation = PictureBox1.Height + spacing;
}
if (isForgeIncluded == "True" | isForgeIncluded == "true")
{
forgeBox.Visible = true;
}
GroupBox[] boxes = {forgeBox , pathBox , typeBox};
foreach(GroupBox box in boxes)
{
if (box.Visible == true)
{
box.Location = new Point(6, nextBoxLocation);
boxHeightAdd = box.Height;
}
if (box.Name == "pathBox" && (minecraftPathVar == Environment.ExpandEnvironmentVariables("C:\\Users\\" + Environment.UserName + "\\AppData\\Roaming\\.minecraft")))
{
defRadioPath.Visible = false;
minecraftRadioPath.Visible = false;
box.Height = 75;
boxHeightAdd = 75;
}
nextBoxLocation += boxHeightAdd + spacing;
boxHeightAdd = 0;
}

Categories