Windows form application - C# Random numer guessing game - c#

I need a little help with a Random Number Guessing Game in visual studio. I got the brunt of the code down but I am having troubles with the Random number generator and getting the random number to port into the click events. As always, I don't really need code but some guidance and/or explanations as to what I am doing wrong and if there is a more effecient way to do things in the beginner phases of learning. Below is my code, the comments are the parts where I am having troubles. Thanks for any help as the help I've recieved to date as been phenominal.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace LAB6B
{
public partial class game : Form
{
public game()
{
InitializeComponent();
//Generate Random number between 1 and 100
//Not sure if there is a better way?
Random rand1 = new Random();
int num1 = rand1.Next(1,50);
int num2 = rand1.Next(1,50);
int answer = num1 + num2;
}
private void evaluate_Click(object sender, EventArgs e)
{
int count = 0;
int choice = Convert.ToInt32(guess);
if (guess.Text != string.Empty)
{
// set counter to keep track of how many tries
// should this be done by a loop or will it count without a loop?
count++;
//compare user input against random number
//Can’t import the random number for comparision
if (choice < answer)
{
Evaluate.Visible = false;
lblMessage.Visible = true;
lblMessage.Text = "Too Low!";
Clear.Visible = true;
BackColor = Color.LightSeaGreen;
}
else if (choice > answer)
{
Evaluate.Visible = false;
lblMessage.Visible = true;
lblMessage.Text = "Too High!";
Clear.Visible = true;
BackColor = Color.SlateBlue;
}
else
{
//Display correct message along with how many times it took to get it
MessageBox.Show(" Eso es CORRECTO! It took you {0} tries. ", count);
}
}
}
private void Clear_Click(object sender, EventArgs e)
{
guess.Text = "";
Evaluate.Visible = true;
lblMessage.Visible = false;
Clear.Visible = false;
BackColor = Color.PowderBlue;
}
}
}

As the rand1 and answer variables are defined within the constructor, you can only access them in the constructor. Defining answer on the class level will solve most of the problems, as you will be able to access it both from the constructor and the click handlers, like this:
private int answer;
private int count;
public game()
{
InitializeComponent();
//Generate Random number between 1 and 100
Random random= new Random();
// no need for num1 and num2, it's just as random
answer = random.Next(1,101);
}

I think you have an issue of scope. The "answer" variable is declared inside your constructor, so it will not be visible to the code inside evaluate_Click(…).

Looks like you need to declare answer as a class variable. When you declare a variable in a constructor, it's still local to that method and not available to other methods.

I do not really know what you want answered, but an obvious error is that you must define your count variable as a member variable in order to keep track of the number of tries. As it is now, the count will always be initialized as zero each time the user presses the button.

First of, you need to declare your variable answer in the page level so it can be used by other page level functions.
Do it like this
public partial class game : Form
{
int answer;
public game()
{
}
}
in your counter you can use a static counter or a page level variable also such as the variable answer
just reset the counter when the user have guessed correctly

Related

This do while loop is is going on forever and I can’t get it to stop

I’m trying to make a game where you have to choose a random number, and the computer will tell you if you’re right or not. But in the code I have, the loop will just keep executing what is in the if command. If I try to break it’ll just do what’s in the while part of it. I want to be able to enter a number, tell you if it’s right or not, and then let you guess again. Thanks for the help! Also, ignore how part of the code isn’t counting as code. I couldn’t get it to go into the code part, and I didn’t try very hard either. Also sorry about the abnormal variable names.
using System;
using System.Threading;
namespace newProject
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("useless intro");
int shortOut;
Random rnd = new Random();
int daNumber = rnd.Next(9);
string userNumber = Console.ReadLine();
bool isParsable = Int32.TryParse(userNumber, out shortOut);
if (isParsable)
{
do
{
if (shortOut != daNumber)
{
Console.WriteLine("no");
}
} while (shortOut != daNumber);
Console.WriteLine("that's it yeah");
}
}
}
}
Your code is asking for the user input only once. It then checks if it is an int and, if it is, it then starts the loop that never changes the variables. It's going to loop forever.
You need to ask for the user's input repeatedly until they guess correctly. Asking for the input needs to be in the loop. And you should only break out of the loop when they get it right.
Here's how I would do it:
Random rnd = new Random();
//choose a number between 0 and 8 inclusive
int daNumber = rnd.Next(9);
// start with a value that the user would never enter
int daGuess = int.MinValue;
//loop if the two numbers are not the same
while (daGuess != daNumber)
{
Console.WriteLine("Enter your guess:");
if (int.TryParse(Console.ReadLine(), out daGuess))
{
if (daGuess != daNumber)
{
Console.WriteLine("no");
}
else
{
Console.WriteLine("that's it yeah");
}
}
}
You don't need to check the guess match twice. What you want is an infinite loop that breaks when the condition is true.
int daNumber = new Random().Next(9);
while(true)
{
if (Int32.TryParse(Console.ReadLine(), out int shortOut))
{
if (shortOut == daNumber)
{
Console.WriteLine("that's it yeah");
break;
}
Console.WriteLine("no ");
}
else
{
Console.WriteLine("cannot be parsed as int");
}
}
}

Creating Calculator with Class - C#, However unable to solve error

I'm trying to create a Calculator with a Class. However using references from the internet particularly from this website (https://www.sourcecodester.com/tutorials/c/7548/simple-calculator-using-class-c.html)
It did not mention to declare "Information" or whatsoever.
When I typed in the code, the error list return with Information does not exist in current context.
Is there a way to modify the code below? Thank you so much.
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
private void Form4_Load(object sender, EventArgs e)
{
}
public void RadioButton_Click(object sender, System.EventArgs e)
{
//call a constructor method and return to cal as an instance of a class
calculate cal = new calculate();
//declaring the string variable represent as a textbox
string txtnum1 = TextBox1.Text;
string txtnum2 = TextBox2.Text;
//declaring the double variable
double dbl_val1 = default(double);
double dbl_val2 = default(double);
if (**Information**.IsNumeric(txtnum1) && **Information**.IsNumeric(txtnum2)) //check if the textbox has a numeric value
{
//convert the string to double
dbl_val1 = double.Parse(txtnum1);
dbl_val2 = double.Parse(txtnum2);
//get the value of the converted variable
//to pass it into the variable in the class
cal.num1 = dbl_val1;
cal.num2 = dbl_val2;
//the condition is, if the radiobutton is clicked,
//the operation of MDAS executes.
if (Radio_Multiplication.Checked)
{
//result:
cal.multiply(); //call a subname in a class for multiplying
}
else if (Radio_Addition.Checked)
{
//result:
cal.add(); //call a subname in a class for adding
}
else if (Radio_Subtraction.Checked)
{
//result:
cal.subtract(); //call a subname in a class for subtracting
}
}
else
{
//the result is:
//if the textbox is empty or has a string value
TextBox3.Text = "Enter a number";
return;
}
//put the result of the MDAS to a textbox.
TextBox3.Text = cal.total.ToString();
}
}
I had a quick look at the link and they don't appear to have declared Information anywhere nor have they indicated that they've overridden anything so...I don't know.
That line, however, is just validating that the information entered into the two text boxes are actually numbers and not anything else that can't be calculated.
There are lots of methods you could use to check those numbers. Options would include, but are not limited to:
if(Int32.TryParse(txtNum1, out int temp1) && Int32.TryParse(txtNum2, out int temp2))
{
do stuff;
}
or
if(txtNum1.All(char.IsDigit) && txtNum2.All(char.IsDigit))
{
do stuff;
}
There are other options, but those two might be worth looking into.
Downloading the sample project, I had a look at what Information refers to. Turns out, it's a class from the Microsoft.VisualBasic namespace, presumably for exposing certain aspects of the VB core library to all .NET languages. You can use it in your program by adding a reference to Microsoft.VisualBasic to your project and adding:
using Microsoft.VisualBasic;
to the top of your code file.
(Personally, I can't imagine that this approach is terribly efficient. It's supposed to take an object and determine if it can be evaluated as a number, and I have no idea what approaches it uses to make that deduction based on any random object. You would probably be better off using one of the alternatives that Benny O'Neill suggests.)

How to progress my Five Dice game

I am learning to program, in particular starting with C# where I have been experimenting with dice games to become more familiar and to improve myself. I am now trying to create a basic game in windows forms, where two players roll 5 dice and keep record of their score.
Rules:
Begin with 5 dice
If a 1 or 4 appears, player scores no points and those dice are removed. Otherwise add all the dice to total
Continue with remaining dice until there a no dice left over
So far I have an Image array which stores all my dice images in my resources and a button which will roll the dice. What I need help with specifically is being able to remove the penalized dice (setting that particular one back to blank) and allowing the player to continue rolling their remaining dice until none are left.
At the moment I am unsure as to where I can further this and maybe I am biting off more than I can chew. I am loving coding and any help would be much appreciated.
Here's an image of the interface:
public partial class Form1 : Form
{
Image[] diceImages;
int[] dice;
int[] diceResults;
Random random;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
diceImages = new Image[7];
diceImages[0] = Properties.Resources.blank;
diceImages[1] = Properties.Resources.one;
diceImages[2] = Properties.Resources.two;
diceImages[3] = Properties.Resources.three;
diceImages[4] = Properties.Resources.four;
diceImages[5] = Properties.Resources.five;
diceImages[6] = Properties.Resources.six;
dice = new int[5] { 0, 0, 0, 0, 0 };
random = new Random();
diceResults = new int[6] { 0, 0, 0, 0, 0, 0 };
}
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
GetResults();
ResetResults();
}
private void RollDice()
{
for (int i = 0; i < dice.Length; i++)
{
dice[i] = random.Next(1, 7);
switch (dice[i])
{
case 1:
diceResults[0]++;
break;
case 2:
diceResults[1]++;
break;
case 3:
diceResults[2]++;
break;
case 4:
diceResults[3]++;
break;
case 5:
diceResults[4]++;
break;
case 6:
diceResults[5]++;
break;
}
}
lbl_dice1.Image = diceImages[dice[0]];
lbl_dice2.Image = diceImages[dice[1]];
lbl_dice3.Image = diceImages[dice[2]];
lbl_dice4.Image = diceImages[dice[3]];
lbl_dice5.Image = diceImages[dice[4]];
}
private void GetResults()
{
bool oneRoll = false, fourRoll = false;
for (int i = 0; i < diceResults.Length; i++)
{
if (diceResults[i] == 1 && diceResults[i] == 4)
{
oneRoll = true;
fourRoll = true;
}
}
}
private void ResetResults()
{
}
}
The code you posted has at least a couple of oddities that don't seem to fit with your description:
The code simply increments an element in an array (diceResults) when a given die value is rolled (i.e. the element corresponds to the die value, not the die's order in the game). From your description, I would have expected the code to simply add the die value to a single sum variable.
In your GetResults() method, your code compares the individual element values in the diceResults to the values 2 and 5. In other words, for each possible die value, if that value comes up twice or five times, you set both flags. There are a number of reasons this is strange, but the biggest, most obvious one is that a single variable (i.e. the element diceResults[i]) can never have two different values at the same time. I.e. that array element will never be both 2 and 5, as the if statement requires.
Given those issues, I'm more inclined to focus on the original specification than to trust the code too much in terms of trying to understand what your intended behavior of the code actually is. :)
It seems that the basic question is how best to remove die from play. The suggestion (in the comments above) to use a list to track the dice is certainly a workable one. In that approach, one would iterate through the list to set each element, and if the roll for a given element ever comes up as 1 or 4, remove that element before moving on.
Having done that, one would just iterate through the list again to set the die value images, using the "blank" image for any die beyond the length of the list.
But there is a simpler way, and based on your statement "setting that particular one back to blank", which seems to imply that each blank die should appear in the same position in which it was rolled, it seems like that simpler way might be preferable to you.
Specifically, after rolling the dice, just scan through the dice array and reset any 1 and 4 values to 0, and use this 0 value as a special "sentinel" value to indicate that die is now blank.
Note that however you do this (with a list, or just setting values to 0), there is also the question of whether to show the user the actual 1 and 4 rolls, or to immediately set those rolls to a blank die. I'm going to assume the former, but it would be very easy to implement it the other way instead. (As always, the beginning of good code is a good specification…right now, your specification is a bit light on detail, and thus is vague and ambiguous).
Taking that approach, your code might look something more like this:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
int[] dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Arrays are always initialized with the elements having their default
// values, so there's no need to specify `0` values for `int` arrays explicitly
dice = new int[5];
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Length; i++)
{
if (checkOnesAndFours)
{
// First, clear any 1 or 4 from the previous roll
if (dice[i] == 1 || dice[i] == 4)
{
dice[i] = 0;
}
// Then, ignore any blank die
if (dice[i] == 0)
{
continue;
}
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = diceImages[dice[i]];
}
}
#endregion
}
NOTE: it was not entirely clear to me what you mean to do when a 1 or 4 comes up. Taking what you wrote literally, I understand it to mean that if any die shows a 1 or 4 on a roll, that none of the dice count for that roll. The above code is implemented with that understanding in mind.
It occurs to me that you might have instead meant that only the dice that show 1 or 4 are not counted for the roll, and that the other dice for that roll are still included. It would not be hard to change the above to accommodate that alternative specification.
NOTE: you'll also notice that I have made other changes to the code not technically required in order to address the immediate question. I added comments in the code itself to try to explain why I made those changes, and why I feel they make the code better.
Just for grins, here's a version that does use a list instead:
public partial class Form1 : Form
{
#region Declaration
Image[] diceImages;
Label[] labels;
List<int> dice;
int diceTotal;
bool checkOnesAndFours;
Random random;
#endregion
#region Initialiazation;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Initializing an array this way eliminates the chance of having
// a typo in the array index for the assignment.
diceImages = new Image[]
{
Properties.Resources.blank,
Properties.Resources.one,
Properties.Resources.two,
Properties.Resources.three,
Properties.Resources.four,
Properties.Resources.five,
Properties.Resources.six
};
// Lists must be initialized explicitly with their initial values, as by default
// they are initially empty.
dice = new List<int>(Enumerable.Repeat(0, 5));
random = new Random();
diceTotal = 0;
// For the purposes of setting the dice images, it will be helpful
// to keep the control references in an array. This is both convenient
// and, again, helps guard against typographical errors
labels = new Label[]
{
lbl_dice1,
lbl_dice2,
lbl_dice3,
lbl_dice4,
lbl_dice5
};
}
#endregion
#region Private Methods
private void btn_rollDice_Click(object sender, EventArgs e)
{
RollDice();
}
private void RollDice()
{
bool rolledOneOrFour = false;
int rollTotal = 0;
for (int i = 0; i < dice.Count; i++)
{
// Clear any 1 or 4 from the previous roll
if (checkOnesAndFours && (dice[i] == 1 || dice[i] == 4))
{
// Remove this die from play
dice.RemoveAt(i);
// The next list element to examine is now at the current i value
// and the for loop is going to increment i when the continue
// is executed, so decrement i in anticipation of that
// so that the loop moves on to the correct next element
i--;
continue;
}
dice[i] = random.Next(1, 7);
if (dice[i] == 1 || dice[i] == 4)
{
rolledOneOrFour = true;
}
rollTotal += dice[i];
}
if (!rolledOneOrFour)
{
diceTotal += rollTotal;
}
checkOnesAndFours = true;
for (int i = 0; i < labels.Length; i++)
{
labels[i].Image = i < dice.Count ? diceImages[dice[i]] : diceImages[0];
}
}
#endregion
}
Finally, note that neither of the above addresses a couple of other issues with the code:
Initializing the dice labels at the beginning of a game.
Resetting the entire game once the game has ended (i.e. there are no more dice left).
I leave these two items as an exercise for the reader (of course, if you run into problems with those specific issues, you may always post another question on Stack Overflow asking about each specifically).

Unable to pass a parameter in C#?

Okay. For the iLab my class and I are doing this week, we are working with GUIs. The second program we must design is a guessing game. The program is supposed to randomly generate a number, 0 through 100, and pass that number on to be used later. Here is the code I already have.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Guessing_game
{
public partial class Form1 : Form
{
int target();
public Form1()
{
InitializeComponent();
Random r = new Random();
int target = r.Next(0, 100);
}
private void btnEvaluate_Click(object sender, EventArgs e)
{
if (txtGuess.Text == target)
{
}
}
}
}
}
Mind you, the "btnEvaluate_Click" area is not done. This is because the variable "Target" that should be accessible by the program is unable to be read later on.
After reading through some of the comments, I was able to tweak the code so I get one more error: "Field 'Guessing_game.Form1.target' is never assigned to, and will always have its default value 0" IF anyone is going to try and replicate this, I can tell you exactly how to write it. The GUI should have a label, a text box, and a button. The button needs to get the value given to "target" so it can check the user's guess against target's value. I'm using Visual Studio 2010, if it helps.
Try this, You need to declare target public
Random r = new Random();
int target = r.Next(0, 100);
public Form1()
{
InitializeComponent();
}
private void btnEvaluate_Click(object sender, EventArgs e)
{
if (txtGuess.Text == target)
{
}
}
You have to put int target outside of the public Form(). Inside your event, change target to target.ToString().
The parentheses {} define a scope. You've declared the target variable within the scope of the constructor (Form1). Therefore, in order to make it accessible throughout the class, you can make it a class level variable. For example
int target;
public Form1()
{
InitializeComponent();
Random r = new Random();
target = r.Next(0, 100);
}
(Although if you plan to use the Random object again, you'd want to make that a class level variable as well). Also, you're trying to compare an int to a string. It should be
if (txtGuess.Text == target.ToString())
{
}
That's because target is local to the constructor and therefore can't be seen anywhere else. Make target a field in Form1 instead. Because this is homework, I'll let you try that out on your own; let us know if you're still stumped.

Simple function call in C# GUI

I'm new to C#. I have two textboxes in a form and a button. When I click the button, I want the value 1 to be put into textbox1 and then the squareroot calculated and put into textbox2. I then want the code to loop for each number between 1-20 and place the respective values in the textboxes. I am simply writing this code just to get used to function calls. My code is below but it doesn't seem to do anything:-
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
for (int initialVal = 1; initialVal >= 20; initialVal++)
{
textBox1.Text = initialVal.ToString();
int sum = calculation(initialVal);
textBox2.Text = sum.ToString();
System.Threading.Thread.Sleep(500);
}
}
static int calculation(int x)
{
int sum;
while (x <= 20)
{
sum = x * x;
x++;
return sum;
}
return 0;
}
}
}
Any suggestions on what is wrong with it?
Two things:
1)
for (int initialVal = 1; initialVal >= 20; initialVal++)
This will never do anything because the exit condition is met - you probably meant initialVal <= 20
2) You need to use a background thread - otherwise your GUI won't update until your button1_Click handler is completely finished. E.g. have a look at the BackgroundWorker class.
Your for-loop will never be executed since its condition is not satisfied:
initialVal >= 20
Change it to
initialVal <= 20
to execute the loop 20 times.
Change the loop as suggested by others.
And, for this line, I think you can simply do
int sum = initialVal * initialVal ;
You don't need the calculate to square a number, and that function doesn't do anything meaningful anyway.
Calling Sleep in the GUI can make your app unresponsive, so it's better to use a background thread or a timer. A timer is easier. First, in design view, just drag and drop a Timer (it's in the Components section of your toolbox) onto the form. Set the Interval property to 500. Then double-click it, and put your update code in there. Note you don't need the loop; you just need some code to tell it to increment initialVal with each tick and stop at 20:
private void timer1_Tick(object sender, EventArgs e) {
textBox1.Text = initialVal.ToString();
int sum = calculation(initialVal);
textBox2.Text = sum.ToString();
if (initialVal++ == 20)
timer1.Enabled = false;
}
Now change your button_click code to simply kick of the timer:
private void button1_Click(object sender, EventArgs e) {
initialVal = 1;
timer1.Enabled = true;
}
Finally make initialVal as a member variable since both functions need access to it:
public partial class Form1 : Form {
int initialVal;

Categories