C# - If/Else Help [User and Computer Input Interaction] - c#

I am trying to figure out a way to get the Computer player to respond to my moves basically by seeing "This spot is taken, I should see if another is free and take it".
So far, I'm not making any improvements (been like 5 hours). I want the computer to realize if a certain button (which it chose at random) is taken, it should consider another choice. Not sure where the if/else should actually go or where/what I should put in for it to try another location.
Here's the snippet of code with comments on my idea (likely wrong placement where I want to do things):
if (c.Enabled == true) //if the button is free
{
if ((c.Name == "btn" + Convert.ToString(RandomGenerator.GenRand(1, 9)) )) //if a specific button is free
{
if ((c.Text != "X")) //if its empty
{
//do this
c.Text = "O"; //O will be inside the button
c.Enabled = false; //button can no long be used
CheckComputerWinner(); //check if it finishes task
return;
}
else //if it is an X
{
//try a different button choice instead
//see if that button is empty
//do stuff
//else
//... repeat until all buttons are checked if free
}
}
}
My question is simply: How can I fix this and understand what is going on? Or do it more efficiently?

You could create an array with those buttons so you don't have to check names:
Button[9] gameField;
Creating a [3,3] array might be more intuitive, but for this case a plain array is easier to work with.
Then, you could count how many of them are free:
int freeCount = gameField.Count(b => b.Text != "X");
If you want to randomly select one of the free ones, generate a random number in the range 0 - (freeCount - 1) and select the appropriate button:
int offset = RandomGenerator.GenRand(0, freeCount - 1);
Button target = gameField.Where(b => b.Text != "X").Skip(offset).FirstOrDefault();
if (target != null) {
// check it
}
The extension method Where filters your buttons to only return the free ones. Skip will skip the specified number of elements (for random selection) and FirstOrDefault returns the first element of the resulting sequence (or null if there is none).
Note: You might want to check for some cases before randomly selecting a field to make your AI a bit more ambitious:
Has the computer player two O in a row with the third field being free? If so, select that one.
Has the human player two X in a row with the third field being free? If so, select that one.
There are tricks to exploit that strategy and there are also better heuristics, but i'll leave that to you.

Your looking for a while loop here. You can modify your code as follows:
Button c;
// here you look for a Button within the Controls of your Form. It stops when an Enabled Button with Text != "X" is found
do
{
c = this.Controls.Find("btn" + Convert.ToString(RandomGenerator.GenRand(1, 9)), true).FirstOrDefault() as Button;
} while (c == null || !c.Enabled || c.Text == "X");
c.Text = "O"; //O will be inside the button
c.Enabled = false; //button can no long be used
CheckComputerWinner(); //check if it finishes task
return;

Related

Problem about house/building etc building time passing

Got into a problem and i can't seem to find the issue. I am currently making a war based game where players are able to buy certain buildings and place them wherever they want. When they choose the spot they like it starts building. After specific time passes it finishes building and it appears in the spot.
THE PROBLEM: I can't figure out how to give the building time to buildings if there are more than one of them building. I tried arrays, but it came to nothing.
THE CODE: The code is kind of hard to read. But if it helps, here you go:
public void BuyBuilding(string whichBuilding)
{
if (whichBuilding == "CIV")
{
if (CIVQUANT < MaxCivQuant && decidedNotToBuy == false && howManyAreBuilding < 4)
{
if (ELEM.Money >= 10000) //IF ENOUGH MONEY
{
howManyAreBuilding++;
whichBuildBought[howManyAreBuilding] = whichBuilding;
}
^ Here i made a method that activates whenever a player presses a button, it checks which building it is "CIV" is one of them, i removes 10k from the player's currency (Not shown here for now)and adds a "CIV" value to a whichBuildBought string array. Then we go to update where the game is checking if any building was bought:
private void Update()
{
if (boughtBuildingS == true && whichBuildBought[howManyAreBuilding] == "CIV")
{
ElapsedTimeCalculator(howManyAreBuilding);
if (elapsedTime[howManyAreBuilding] == time.OnDayChanged)
{
elapsedTime[howManyAreBuilding] = 0;
boughtBuildingTime[howManyAreBuilding] = 0;
ElapsedTimeCalculatorPassed = false;
howManyAreBuilding--;
}
}
^ Here i activate an ElapsedTimeCalculator method shown below, Time.OnDayChanged is a day counter, i use it to check if the day the player bought the building matches the day it's supposed to finish building by giving boughtBuildingTime specific array value a current day value and then giving elapsedTime array that value plus how many days its supposed to be building. In the update method if the elapsedTime of that specific building in the array is done it just finished building and some extra things happen that i just removed for now.
public void ElapsedTimeCalculator(int i)
{
if (ElapsedTimeCalculatorPassed == false && whichBuildBought[i] == "CIV")
{
boughtBuildingTime[i] = time.OnDayChanged;
elapsedTime[i] = boughtBuildingTime[i] + 20;
ElapsedTimeCalculatorPassed = true;
}
Thanks in advance for helping! Would really appreciate it.

Is it possible to have multiple checkboxes in the same 'if' statement?

I'm very new to coding and am currently learning C#. More specifically I'm currently struggling with using checkboxes in group boxes. What I'm wondering is if it's possible to have multiple checkboxes in the same 'if' statement?
What I mean by is that, instead of just (for example):
private void button1_Click(object sender, Eventargs e)
{
float optionACheckBox = 149.00f;
if (checkBox1.Checkstate == CheckState.Checked)
{
finalPrice = (optionACheckBox + 60)
}
MessageBox.Show(finalPrice);
}
how would I make it so that instead it would be something like:
if (checkBox1 & checkBox2 = CheckState.Checked)
{
((Value of checkBox1) + (Value of checkBox2) + 60)
}
where if the user checks checkBox1 & checkBox2 then both values can be used in the equation?
Regarding this, would it also be possible to make code that checks if any/what combination of the CheckBoxes in the GroupBox have been checked? Rather than me writing an 'if' statement for every single combination of the different CheckBoxes?
Thank you to anyone who takes the time to read this and for any tips given
More Context (Sorry this is my second ever StackOverFlow post so I'm not very good at proper formatting):
Using Visual Studio 2019
There are three CheckBoxes in total, and all three are in one GroupBox
The CheckBoxes and GroupBox were added to the form using the toolbox feature
You didn't really tell us much about your logic but it seems like you want a hypothetical scenario like:
some fixed base price of the pizza
a price for each topping
a fixed price for applying any number of toppings
As such I'd look at accumulation:
float price = 100;
if(anchoviesCheckbox.Checked)
basePrice += 20;
if(olivesCheckbox.Checked)
basePrice += 30;
if(chilliesCheckbox.Checked)
basePrice += 40;
//if anchovies AND chillies are chosen there is a surcharge because the most of the chefs are allergic to this combination and we have to get the manager to do it
if(anchoviesCheckbox.Checked && chilliesCheckBox.Checked)
basePrice += 50;
//if any one OR more topping has been applied, there is a surcharge
if(anchoviesCheckbox.Checked || olivesCheckbox.Checked || chilliesCheckbox.Checked)
basePrice += 60;
These accumulate because there is no else - if the checkbox is checked, cost is added to the final price. Each checkbox is viewed in isolation. Later some also act in combination.
Note you could of course also check if the base price is greater than 100 to know if to apply a surcharge..
Once you've got that clear in your mind how it works, you can save yourself some of those ifs by treating the checkboxes in the group box as a collection
You can do this in the form constructor:
//put the prices in the checkbox Tag:
anchoviesCheckbox.Tag = 20;
olivesCheckbox.Tag = 30;
chilliesCheckbox.Tag = 20;
Then in your price calc method you can do something like:
float basePrice = 100:
foreach(var cb in toppingsGroupBox.Controls.OfType<CheckBox>().Where(cb => cb.Checked))
basePrice += (int)cb.Tag;
This uses LINQ to pull out just the checked checkboxes, and then extract the price from their tag and add it on. You could even do:
float basePrice = 100 +
toppingsGroupBox.Controls
.OfType<CheckBox>()
.Where(cb => cb.Checked)
.Sum(cb => (int)cb.Tag);
For your adding a surcharge if any topping is chosen:
if(toppingsGroupBox.Controls
.OfType<CheckBox>()
.Any(cb => cb.Checked)))
basePrice += 60;
You could now add 100 different toppings checkboxes to the form and so long as you put the price in the tag there is no more code needs adding to the method that calculates the price
The "manager must add anchovies and chillies" surcharge could also be done with LINQ. For that you'd have to define a custom set of checkboxes and if they are all ticked then apply the surcharge:
class PizzaForm:Form{
CheckBox[] managerSurcharge;
PizzaForm() { // constructor
...
managerSurcharge = new[]{ anchoviesCheckBox, chilliesCheckBox };
}
Then in the price:
if(managerSurcharge.All(cb => cb.Checked))
basePrice += 50;
Not an if in sight! 😀 (yeah, it's really hard to do away with every if..)
But do name your controls and variables well; this code here is easily readable and obvious what it does because of the names. That manager surcharge scenario would be a lot more confusing if you write:
CheckBox array1 = new[]{ checkbox12, checkbox7 }
You can use switch case judgments to assign different outcomes to these different choices.
But because every combination is a judgment situation, no matter what judgment method you use, you need to judge them separately.
The judgment to judge that both are selected should be as follows:
if (checkBox1.Checked && checkBox2.Checked)
{
//To do something
}
Some documents:
checked 、&&、||、== and !=
First of all, you can't compare the checkbox itself with a CheckState so you have to use checkBox1.CheckState == CheckState.Checked or better using Boolean "Checked" property: if(checkBox1.Checked) which will check if the checkbox is checked.
As for your last Question on how to detect if any checkbox is checked you can use || the logical "OR" Operator:
if(checkBox1.Checked || checkBox2.Checked || checkBox3.Checked)
Update
Logical Operator vs Conditional Short Circuit Operator
Logical Operator: & is used to ensure all Operands are evaluated and checked.
Conditional Short Circuit Operator: && is used to skip the right side Operand.
As mentioned in the comments, both will work in the vast majority of the cases, but I would always use the "Conditional Short Circuit Operators" when possible, to skip the unnecessary Check of the right side Operand.

C# assigning several buttons to the same method

I'm trying to build a simple game of 'HangMan' using Win8 GUI. I've build the GUI with 26 buttons on screen, each represent one letter of the alphabet.
I want to connect all the buttons to the same method that checks whatever the value of the button that was pressed matches one of the letter in the selected word. I've looked at this question answers that supposed to help me in this but the one difference i think is that all the logic and methods in my game are on different class, the "Game Manager" class.
How can I subscribe multiple buttons to the same event handler and act according to what button was clicked?
Plus i didnt quit understood how, using this solution the method which i will assign all the buttons to will know which button was pressed. I hope i explaind my situation clear enough, if not i can provide parts of the code for better understanding.
It's a basic method for what you want:
static string key = "Level solution";
char[] chars = key.ToCharArray();
void check (object sender)
{
var button = sender as Button;
character = Convert.ToChar(button.Text);
int i = 0;
foreach (char c in chars)
{
//checks every character to mark them
if (c == character)
{
chars[i] = ' ';
//Makes character unusable for later use
//Anything you want now for true letters, for example showing pics or adding them to a label
}
i++;
}
//checks every character of key again, to see if player is won
int count = 0;
foreach (char c in chars) {
if (c != ' ') count++;
//Adds a number for anything expect space
}
if (count == 0)
{
MessageBox.Show("You won!");
}
}
You can paste it on top of your codes and then use just this code in any button:
check(sender);

Comparing a Selected Index Combo Box to another Selected Index Combo Box

Basically what I am trying to do, is compare the selected Index of two combo boxes in Win Forms.
If ComboBoxA.SelectedIndex == 1 and, ComboBoxB.SelectedIndex == 1, I need to prevent that from happening, by changing ComboBoxB.SelectedIndex to 2.
I tried doing this through an If statement and couldn't get the results I was looking for.
if (Northern.SelectedIndex == 1 && NorthernEnd.SelectedIndex == 1)
NorthernEnd.SelectedIndex = 2;
However, I can't seem to get this to work. I am a beginner in C# working on my last assignment of the term.
You can handle the event to prevent the action:
if (Northern.SelectedIndex == 1 && NorthernEnd.SelectedIndex == 1)
e.Handled = true;
Here is the MSDN ref.

Looping Radio Button Check in Visual C#

I'm new to C#, trying to make a program that is essentially a survey with 30 questions that are answered by selecting one of five radio buttons (Strongly Disagree, Disagree...Strongly Agree, etc).
I have set up a small "block" of code that will check which radio button is checked for the question and assign a value to an array (see below).
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonScore_Click(object sender, EventArgs e)
{
this.textBoxScoreOutput.Text = " ";
int[] score = new int[2]; // Declares the integer of score and sets it to a value of zero
// Question 1
if (radioButtonSD1.Checked == true) // If Strongly Disagree checked give score a value of 1
score[0] = 1;
else if (radioButtonD1.Checked == true) // If Disagree checked give score a value of 2
score[0] = 2;
else if (radioButtonNS1.Checked == true) // If Not Sure checked give score a value of 3
score[0] = 3;
else if (radioButtonA1.Checked == true) // If Agree checked give score a value of 4
score[0] = 4;
else if (radioButtonSA1.Checked == true) // If Strongly Agree is checked give score a value of 5
score[0] = 5;
// Question 2
if (radioButtonSD2.Checked == true) // If Strongly Disagree checked give score a value of 1
score[1] = 1;
else if (radioButtonD2.Checked == true) // If Disagree checked give score a value of 2
score[1] = 2;
else if (radioButtonNS2.Checked == true) // If Not Sure checked give score a value of 3
score[1] = 3;
else if (radioButtonA2.Checked == true) // If Agree checked give score a value of 4
score[1] = 4;
else if (radioButtonSA2.Checked == true) // If Strongly Agree is checked give score a value of 5
score[1] = 5;
// Output values in array to text box
this.textBoxScoreOutput.Text = "Array: ";
foreach (int i in score)
{
this.textBoxScoreOutput.Text += "[" + i.ToString() + "] ";
}
int sum = score.Sum();
this.textBoxScoreOutput.Text += "The Sum of the array is: " + sum.ToString();
}
}
}
So this is checking the first two of the thirty questions and is working exactly how I need it to and thought it would.
I was wondering if I could loop just one of these "blocks" and have it check all thirty questions. I have searched and searched but can't find exactly what I am looking for (I also understand I may not be searching for the right thing either).
I am just trying to avoid having thirty of these "blocks" in my program. I feel like it would just be a mess with thirty of these. Is this possible?
Start with creating a UserControl which encapsulates the logic for a single question:
Question Text
Selected option
Once you have a single question working, you can drop any number of User Controls on to a form, configure the question text and then only have to loop through the set of user controls to get your answers. The answer would be best returned as an enumeration.
There are a number of ways to achieve this, such as code to generate the controls, or binding the selections back to a ViewModel class, but a user control is a great start.
Here's how I do it roughly:
var resultList = new List<KeyValuePair<string, int>>();
foreach (var control in this.Controls)
{
if (control is GroupBox)
{
GroupBox gb = (GroupBox)control;
foreach (Control controll in gb.Controls)
{
if (controll is RadioButton)
{
RadioButton rb = new RadioButton();
rb = (RadioButton)controll;
//rb will allow you to access all of the RadioButton's properties and act accordingly.
if (rb.Checked)
{
int score;
if (rb.Name.Contains("ButtonSD"))
score = 1;
if (rb.Name.Contains("ButtonD"))
score = 2;
//So on...
resultList.Add(new KeyValuePair<string, int>(gb.Name, score));
}
}
}
}
}
Had a rough day so maybe someone can come up with something better, but if you don't feel like reorganizing the whole thing, this might work.

Categories