I'm trying to replicate the Mastermind game within c# and have hit a hurdle, so to speak. The problem I'm facing is at the stage where player 2 guesses which 3 checkboxes are correct from the 6 available. (8 rows for 8 attempts/lives at guessing). The code I have works when player 2 guesses the correct checkboxes, however when the incorrect checkboxes are selected and the "guess" button is clicked nothing happens. I have a second if statement to check this but obviously something must be wrong. The code for the button click event is:
private void Guess_button_Click(object sender, EventArgs e)
{
int boxesChecked = 0; // Default value
CheckBox[] checkBoxArray = new CheckBox[]
{ checkBox1, checkBox2, checkBox3, checkBox4, checkBox5, checkBox6 };
for (int i = 0; i < checkBoxArray.Length; i++)
{
if (checkBoxArray[i].Checked)
boxesChecked++;
}
if (boxesChecked > 3)
MessageBox.Show("You have checked " + boxesChecked.ToString() +
" checkboxes. Only 3 are allowed.");
else if (boxesChecked < 3)
MessageBox.Show("You have checked " + boxesChecked.ToString() +
" checkboxes. Please choose 3.");
if (checkBox1.Checked == cb1)
if (checkBox2.Checked == cb2)
if (checkBox3.Checked == cb3)
if (checkBox4.Checked == cb4)
if (checkBox5.Checked == cb5)
if (checkBox6.Checked == cb6)
{
MessageBox.Show("Congratulations, You Win!",
"Game Won");
if (MessageBox.Show("Would you like to play again?",
"Play Again?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
p1input restart = new p1input();
this.Close(); // Close current window
restart.Show(); // Open restart (instance of p1input)
}
else
{
Environment.Exit(0); // Terminate Application
}
if (checkBox1.Checked != cb1)
if (checkBox2.Checked != cb2)
if (checkBox3.Checked != cb3)
if (checkBox4.Checked != cb4)
if (checkBox5.Checked != cb5)
if (checkBox6.Checked != cb6)
{
MessageBox.Show("Unlucky, Guess Again!");
checkBox1.Visible = false;
checkBox2.Visible = false;
checkBox3.Visible = false;
checkBox4.Visible = false;
checkBox5.Visible = false;
checkBox6.Visible = false;
}
}
}
Ok, let's go. There a few things to review at your code:
1. How many checkbox are checked?
Let's use a little lamba to make that for a little bit prettier:
boxesChecked = checkBoxArray.Where<CheckBox>(x => x.Checked).Count();
2. If the user doesn't have checked 3 checkboxes, let's show the message and leave the method!
It's a little bit simplified too, you may wish to change it:
if (boxesChecked != 3)
{
MessageBox.Show(string.Format("You have checked {0} checkboxes. Please choose 3.", boxesChecked));
return;
}
3. Verify the result
Let's change those if a little bit. Notice the main else condition (player lost!):
if (checkBox1.Checked == cb1
&& checkBox2.Checked == cb2
&& checkBox3.Checked == cb3
&& checkBox4.Checked == cb4
&& checkBox5.Checked == cb5
&& checkBox6.Checked == cb6)
{
MessageBox.Show("Congratulations, You Win!", "Game Won"); // Display MessageBox
if (MessageBox.Show("Would you like to play again?", "Play Again?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
p1input restart = new p1input();
this.Close(); // Close current window
restart.Show(); // Open restart (instance of p1input)
}
else
{
Environment.Exit(0); // Terminate Application
}
}
else
{
MessageBox.Show("Unlucky, Guess Again!");
checkBox1.Visible = false;
checkBox2.Visible = false;
checkBox3.Visible = false;
checkBox4.Visible = false;
checkBox5.Visible = false;
checkBox6.Visible = false;
}
Please note that I'm not saying that this is the best design for a game, I'm just pointing out a few things to change on your code.
UPDATE
Based on spender's comment, let's review your method. Please, check it out:
private void Guess_button_Click(object sender, EventArgs e)
{
int boxesChecked = 0; // Default value
List<CheckBox> AllTheCheckBoxes = new List<CheckBox> { checkBox1, checkBox2, checkBox3, checkBox4, checkBox5, checkBox6 };
boxesChecked = AllTheCheckBoxes.Where<CheckBox>(x => x.Checked).Count();
if (boxesChecked != 3)
{
MessageBox.Show(string.Format("You have checked {0} checkboxes. Please choose 3.", boxesChecked));
return;
}
if (AllTheCheckBoxes.Any<CheckBox>(x => x.Checked != Convert.ToBoolean(x.Tag)))
{
MessageBox.Show("Unlucky, Guess Again!");
AllTheCheckBoxes.ForEach(x => x.Visible = false);
return;
}
MessageBox.Show("Congratulations, You Win!", "Game Won"); // Display MessageBox
if (MessageBox.Show("Would you like to play again?", "Play Again?", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
p1input restart = new p1input();
this.Close(); // Close current window
restart.Show(); // Open restart (instance of p1input)
}
else
{
Environment.Exit(0); // Terminate Application
}
}
Notice that I'm using the Tag property. It's an arbitrary string, that developer may use for any purpose. Here I'm expecting that the correct value (true or false) is stored at this property.
UPDATE 2
Regarding OP comment about finding all the checkboxes (looks like its 48 total).
You can use the following statement (understand it and improve it to your needs).
List<CheckBox> AllTheCheckBoxes = this.Controls.AsQueryable().OfType<CheckBox>().Where(x => x.Tag != null).ToList();
Your check for an incorrect value appears to be inside the braces of the if statements for when the user guesses correctly.
In other words, it won't ever be hit. You need to break it out of the braces so it runs.
Like others said, all those nested ifs are going to hurt you in the end. Consider cleaning up that bit so you can understand what's happening better.
Related
I'm new here and I have a problem (I think the solution is simple, but I can't solve this problem alone). I have to throw a few checkbox on userform (that is simple) but when I write something like this:
if(checkBox1.Checked)
{
MessageBox.Show("ok1");
}
else if(checkBox1.Checked && checkBox2.Checked)
{
MessageBox.Show("ok2");
}
else
{
MessageBox.Show("co nie tak");
}
always get "ok1" MsgBox...
Any ideas what I'm doing wrong? Thanks for helping.
The if statement will always go into the first block that is true. So if checkbox1 is checked you will always get "ok1". You can never get into the second block ( "ok2" ) because if it is true, the first check would also be true.
I think you want to switch your checks:
if(checkBox1.Checked && checkBox2.Checked)
{
MessageBox.Show("ok2");
}
else if(checkBox1.Checked)
{
MessageBox.Show("ok1");
}
else
{
MessageBox.Show("co nie tak");
}
You may also be looking to build up your string by adding to it. The += means add to the end of the string.
My example code is just an example, since I don't really know what you are trying to do, but it might give you some ideas.
if (checkBox1.checked )
{
mic.HTMLBody = "1) Example1";
}
if ( checkBox2.checked )
{
mic.HTMLBody += "<br>"""2) Example2";
if ( ComboBox2.Text == "Pan" )
{
mic.HTMLBody += "<br>Pana";
}
}
from the code i see if checkbox1.checked is true then "ok1" should display and the second an third evaluations would never be evavluated. if checkbox1.checked is false then only the third option would be evaluated and the second option should never be evaluated at all. Should be more like:
if (checkBox1.Checked)
{
if (checkBox2.Checked)
{
MessageBox.Show("ok2");
}
else
{
MessageBox.Show("ok1");
}
}
else
{
MessageBox.Show("co nie tak");
}
As it is currently written, it is impossible for it to enter the else if, because whenever the else if condition is true, the if condition is also true.
It goes from up to down, the first that is true is entered and the rest are ignored.
Instead you should switch their place as follows:
if(checkBox1.Checked && checkBox2.Checked)
{
MessageBox.Show("ok2");
}
else if(checkBox1.Checked)
{
MessageBox.Show("ok1");
}
else
{
MessageBox.Show("co nie tak");
}
A little unclear what you really want shown, but if you want it to first show ok1 and then ok2 then you can do this:
if(checkBox1.Checked)
{
MessageBox.Show("ok1");
if(checkBox2.Checked) {
MessageBox.Show("ok2");
//MessageBox.Show("ok1 ok2"); //If you want to show them both at the same time
}
}
else
{
MessageBox.Show("co nie tak");
}
I tried this one on a Console and it might be the logic you need. The inline comments will give you a bit of insight of what is doing what:
check1 = true;
check2 = true;
if (check1)
{
if (check2)
{
// Prints if BOTH check1 and check2 are TRUE
Console.WriteLine("ok2");
}
else
{
// Prints if ONLY check1 is TRUE
Console.WriteLine("ok1");
}
}
else
{
// Prints if BOTH check1 and check2 are FALSE
Console.WriteLine("co nie tak");
}
bool Check = checkBox1.Checked;
bool Check2 = checkBox2.Checked;
if (Check == true && Check2 == true)
{ MessageBox.Show("ok 1 & 2"); }
if (Check == true)
{ MessageBox.Show("ok 1"); }
if (Check2 == true)
{ MessageBox.Show("ok 2 "); }
else
{ MessageBox.Show("Not Checked"); }
I am trying to make if you got enough gold then comes you need rock, if you got enough rock then you need enough gold, but if you have both then you can "Upgrade". But if you got both then it goes back to the you need gold.
void Update()
{
if(enoughgold == true & enoughrocks == true)
{
Upgrade.text = "Upgrade to 2014!";
}
if(sellrocks.gold > 9999)
{
enoughgold = true;
}
else
{
enoughgold = false;
}
if(click.rock > 2999)
{
enoughrocks = true;
}
else
{
enoughrocks = false;
}
if(enoughgold == true)
{
Upgrade.text = "You need 3,000 Rocks!";
}
else
{
Upgrade.text = "You need 10,000 Gold!";
}
if (enoughrocks == true)
{
Upgrade.text = "You need 10,000 Gold!";
}
else
{
Upgrade.text = "You need 3,000 Rocks!";
}
}
How about something like this? You first see whether the user has enough gold and rocks and then do the checking.
I have simplified if (enoughgold == true) to if (enoughgold) as the == true is redundant.
void Update()
{
enoughgold = sellrocks.gold > 9999;
enoughrocks = click.rock > 2999;
if (enoughgold && enoughrocks)
Upgrade.text = "Upgrade to 2014!";
else if (enoughgold && !enoughrocks)
Upgrade.text = "You need 3,000 Rocks!";
else if (!enoughgold && enoughrocks)
Upgrade.text = "You need 10,000 Gold!";
else if (!enoughgold && !enoughrocks)
Upgrade.text = "You need 10,000 Gold and 3,000 Rocks!";
}
You could also create an enum to handle all 4 possibilities: if the user has only enough rocks, if the user has only enough gold, if the user has enough of both and if the user doesn't have enough of any.
So I have a this model http://i.imgur.com/tz8ZVPT.png , and I would like create a Update with a Program, so I first create the update, fill in all the neccesary items, find a MachineType and maybe a program, but if none is found, get the first program from the MachineType.
Note: All MachineTypes have at least 1 program.
for (int i = 0; i < dgvInput.Rows.Count; i++)
{
DataGridViewRow row = dgvInput.Rows[i];
int machineTypeId = Convert.ToInt32(row.Cells[1].Value);
Update update = new Update();
update.MachineType.Add(Check.prombase.MachineTypes.First(mt => mt.MachineTypeId == machineTypeId));
foreach (Program program in database.Programs)
{
if (program.ProgramVersion.Split('v')[0] == row.Cells[5].Value.ToString())
{ //If a program is added here, it will save it
update.Program.Add(program);
break;
}
}
if (update.Program.Count == 0)
foreach (Program program in database.Programs)
{ //When a program is added here, it will NOT save it
if (program.MachineType.MachineTypeId == machineTypeId)
{
update.Program.Add(program);
break; //When debugging it comes here everytime
}
}
//Here it is always: update.Program.Count = 1
database.AddToUpdates(update);
database.SaveChanges();
if (update.MachineType.Count == 0 || update.Program.Count == 0)
MessageBox.Show("This error is nevers shown!");
}
The problem is, it always says it has a program but in reality it is not.
What am I doing wrong that it wont add a Program to my Update?
edit VARAK:
After replacing the code it still won't save it, also added this at the end
reloadDatabase();
foreach(Update update in database.Updates)
if (update.Program.Count == 0)
MessageBox.Show("This can't be happening");
Please try this:
for (int i = 0; i < dgvInput.Rows.Count; i++)
{
DataGridViewRow row = dgvInput.Rows[i];
int machineTypeId = Convert.ToInt32(row.Cells[1].Value);
Update update = new Update();
update.MachineType.Add(Check.prombase.MachineTypes.First(mt => mt.MachineTypeId == machineTypeId));
var programVal = row.Cells[5].Value.ToString() + "v";
var program = database.Programs.FirstOrDefault(prog => prog.ProgramVersion.StartsWith(programVal));
if (program == null)
program = database.Programs.First(prog => prog.MachineType.MachineTypeId == machineTypeId);
update.Program.Add(program);
database.AddToUpdates(update);
database.SaveChanges();
//This will never show an error as the update that you are accessing here is the one you created in memory (Not the one in the DB)
if (update.MachineType.Count == 0 || update.Program.Count == 0)
MessageBox.Show("This will never show!");
//To get the error, pull the update from the database again
var updateNew = database.Updates.First(upd => upd.UpdateId == update.UpdateId);
if (updateNew.MachineType.Count == 0 || updateNew.Program.Count == 0)
MessageBox.Show("This will show if prog was not saved");
}
This code should be more efficient and might shed a bit more light if it doesn't work.
Finally found the solution, as you can see in my model the Program can have 1 Update, so when a new Update gets created the with the same Program as another Update, that other Update will lose the Program connected.
I have my website built in ASP.NET 2.0 and C#. I have textbox called tbCode where a user enters a code. I am trying to check that entered value against multiple values in the code behind on a button click.
This is my mark up so far.
protected void btUpdate_Click(object sender, EventArgs e)
{
if ((this.tbcode.Text.Trim().ToUpper() != "AB12") ||(this.tbcode.Text.Trim().ToUpper() != "DE14") || (this.tbcode.Text.Trim().ToUpper() != "XW16"))
{
lbmessage.Text = "Invalid Promo code. Please enter again";
}
else if ((this.tbcode.Text.Trim().ToUpper() == "AB12") || (this.tbcode.Text.Trim().ToUpper() == "DE14") || (this.tbcode.Text.Trim().ToUpper() == "XW16"))
{
Order.Shipping.Cost = 0;
this.lShipping.Text = Order.Shipping.Cost.ToString("c");
this.lSubtotal.Text = Order.Subtotal.ToString("c");
this.lTotal.Text = Order.TotalCost.ToString("c");
Order.PomoCode = this.tbcode.Text.Trim().ToUpper();
lbmessage.Text = "Promo Code Applied.";
}
else
{
this.lShipping.Text = Order.Shipping.Cost.ToString("c");
this.lSubtotal.Text = Order.Subtotal.ToString("c");
this.lTotal.Text = Order.TotalCost.ToString("c");
}
}
when i hit the button its always saying invalid code. not sure where am i making the mistake. It works perfectly if I am checking against just one value rather than the 3.
Thanks and appreciate it
Here is likely what you wanted to do:
protected void btUpdate_Click(object sender, EventArgs e)
{
string tbcodeValue = this.tbcode.Text.Trim().ToUpper();
string[] validCodes = new string[] { "AB12", "DE14", "XW16" };
if (!validCodes.Contains(tbcodeValue))
{
lbmessage.Text = "Invalid Promo code. Please enter again";
}
else
{
Order.Shipping.Cost = 0;
this.lShipping.Text = Order.Shipping.Cost.ToString("c");
this.lSubtotal.Text = Order.Subtotal.ToString("c");
this.lTotal.Text = Order.TotalCost.ToString("c");
Order.PomoCode = tbcodeValue;
lbmessage.Text = "Promo Code Applied.";
}
}
First off, you were calling this.tbcode.Text.Trim().ToUpper() all over the place. That really clutters up your code and makes it hard to read. Assigning that to a variable not only makes the code cleaner, but avoids performing all of those string manipulation functions over and over.
Next, it appears that your intent is to say, "if the textbox value isn't any of these values, run some code saying it's invalid. The easiest way to do that is to put all of the valid values into a container of some sort and see if it contains the value you're interested in. Your next block of code is basically for, "if it is one of the valid values". So if it does contain the string then it is valid. As for your else, I couldn't figure out what the intent of it was. Either the string is invalid, or it's valid. I don't see any third case there, so I just removed it.
You need to change your ||'s to &&'s in the first if statement. You are always going to fall into that block otherwise.
Try this:
if ((this.tbcode.Text.Trim().ToUpper() != "AB12") && (this.tbcode.Text.Trim().ToUpper() != "DE14") && (this.tbcode.Text.Trim().ToUpper() != "XW16"))
{
lbmessage.Text = "Invalid Promo code. Please enter again";
}
else if ((this.tbcode.Text.Trim().ToUpper() == "AB12") || (this.tbcode.Text.Trim().ToUpper() == "DE14") || (this.tbcode.Text.Trim().ToUpper() == "XW16"))
{
Order.Shipping.Cost = 0;
this.lShipping.Text = Order.Shipping.Cost.ToString("c");
this.lSubtotal.Text = Order.Subtotal.ToString("c");
this.lTotal.Text = Order.TotalCost.ToString("c");
Order.PomoCode = this.tbcode.Text.Trim().ToUpper();
lbmessage.Text = "Promo Code Applied.";
}
else
{
this.lShipping.Text = Order.Shipping.Cost.ToString("c");
this.lSubtotal.Text = Order.Subtotal.ToString("c");
this.lTotal.Text = Order.TotalCost.ToString("c");
}
You could also employ a switch;case; block.
String testtext = this.tbcode.Text.Trim().ToUpper();
switch(testtext)
{
case "AB12":
// Do stuff for this case
break;
case "Text2":
// Do stuff for this case
break;
default:
// anything that fails all above tests goes here
break;
}
Just be sure to either break, return, or continue after each case or you will get a compile error. Also default needs to be last in line.
I'm messing with some kind of dictionary, that is supposed to translate words from one textbox to other, and the other way around, but It doesn't act as I'd like it to. The code for the button is:
private void button1_Click(object sender, EventArgs e)
{
string[] lines = File.ReadAllLines("C:/words.txt");
int i = 0;
var items = from line in lines
where i++ != 0
let words = line.Split('|')
where words.Count() > 1
select new
{
word = words[0],
translation = words[1]
};
foreach (var item in items)
{
if (textBox1.Text == item.word)
{
textBox2.Text = item.translation;
}
if (textBox2.Text == item.translation)
{
textBox1.Text = item.word;
}
else
{
label3.Text = ("not found");
}
}
}
Edit: Doesn't work with "else if" either.
You need an else if, otherwise the else is only happening from the second if:
if (textBox1.Text == item.word)
{
textBox2.Text = item.translation;
}
else if (textBox2.Text == item.translation)
{
textBox1.Text = item.word;
}
else
{
label3.Text = ("not found");
}
Try to use else if (textBox2.Text == item.translation) instead of if (textBox2.Text == item.translation).
ELSE IF!
I find it best to avoid if statements where possible, and I especially try to avoid else and else if. The reason for this is that it simply gets confusing when there are multiple conditions to try and follow. Here is possibly a cleaner way to understand what is going on and also solve your issue.
foreach (var item in items)
{
if (textBox1.Text == item.word)
{
textBox2.Text = item.translation;
continue; // Don't process anything else in this loop.
}
if (textBox2.Text == item.translation)
{
textBox1.Text = item.word;
continue; // Don't process anything else in this loop.
}
label3.Text = ("not found");
}
Since we don't want any other logic to execute (my assumption) if one of our if statements is true, we simply use continue to skip the rest of the logic in the foreach and move to the next item.
Why is this in a loop anyway? Won't the text in the first iteration be overwritten by subsequent iterations?
From what I can see it is that there's no else if, that second if will only work if the first if is true. Try this:
foreach (var item in items)
{
if (textBox1.Text = item.word)
{
textBox2.Text = item.translation;
}
else if (textBox2.Text = item.translation)
{
textBox1.Text = item.word;
}
else
{
label3.Text = ("not found");
}
}