Combine check boxes without using if - c#

I'm making a password generator and I have three check boxes: lowercase, uppercase, and number. Right now I have an IF statement that says:
IF (check1.checked == true & check2.checked == true & check3.checked == true)
{
length = Convert.ToInt32(lengthTextBox.Text);
string password = "";
int choice;
Generate gen = new Generate();
for (int i = 1; i <= length; i++)
{
choice = rnd.Next(1, 4);
if (choice == 1)
{
password = password + gen.lower();
}
else if (choice == 2)
{
password = password + gen.upper();
}
else if (choice == 3)
{
password = password + gen.number();
}
}
passwordTextBox.Text = password;
}
Else IF (check1.checked == true & check2.checked == true)
{
length = Convert.ToInt32(lengthTextBox.Text);
string password = "";
int choice;
Generate gen = new Generate();
for (int i = 1; i <= length; i++)
{
choice = rnd.Next(1, 3);
if (choice == 1)
{
password = password + gen.lower();
}
else if (choice == 2)
{
password = password + gen.upper();
}
}
passwordTextBox.Text = password;
}
and so on. This method is terribly inefficient. I ran into this problem while making a cash register program (10 choices of toppings, check the ones you want, and the program adds the prices together. If you uncheck a topping, the price will be subtracted by that amount.), so I just gave up on it. But now, I am determined to find a way to metaphorically go shopping.

Although it is not really clear what your code does, you seem to be able to call the methods consecutive. So why not do it like this;
if (check1.Checked)
Generate.lowercase();
if (check2.Checked)
Generate.uppercase();
if (check3.Checked)
Generate.number();
Also you should probably want to use more descriptive names for your controls and variables.

if(check1.checked) Generate.lowercase();
if(check2.checked) Generate.uppercase();
...

So what you really need to do here is find a way of making the selection of choice dynamic. One way of doing this is to create a list of functions in which each function is capable of generating a value. At the start you populate the list with the relevant functions based on what's checked, and then you can have a single loop that simply chooses one of the functions from that list:
List<Func<char>> generators = new List<Func<char>>();
if (lowercaseCheckbox.Checked)
generators.Add(() => gen.lowercase());
if (uppercaseCheckbox.Checked)
generators.Add(() => gen.uppercase());
if (numberCheckbox.Checked)
generators.Add(() => gen.number());
int length = Convert.ToInt32(lengthTextBox.Text);
StringBuilder password = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++)
{
int choice = random.Next(generators.Count);
password.Append(generators[choice]());
}
string result = password.ToString();
Note that rather than appending characters to a string repeatedly in a loop you should be using a StringBuilder to avoid constant re-allocation and copying of the values.
I also suggest using more meaningful names for your checkbox variables; it makes the code much more readable.

It depends on what framework you're using and what patterns you have applied, but there are better ways to do this. You could use bit flags and have the check boxes and them together.
FlagVariable output = FlagVariable.None;
if( topping1.IsChecked )
{
output &= FlagVariable.Topping1;
}
if( topping2.IsChecked )
{
output &= FlagVariable.Topping2;
}
// etc...
then later
if( output | FlagVariable.Topping1 )
{
// it has topping 1
}
This is pretty efficient and maintainable. You'll still have to write associative code between the check boxes and their corresponding flag value (this is the part that depends on your framework/patterns, because in WPF with MVVM you might be able to avoid a lot of if-then code).

You could simply split them up:
if (check1.checked) Generate.lowercase();
if (check2.checked) Generate.upperrcase();
if (check3.checked) Generate.number();
Logically, there is no between this way and the grouped way.

In case of password generation #Gerald Versluis 's answer, is definetely worth looking at.
In the case of the shopping, where you have flavours. "Checking" off flavours, to later add the price of the ones that are "checked off", it just doesn't scale very well, as you have already realised.
In that case it's better to add flavours, to a list, which then is calculated to a total.
This can be applied to the password generation as well. Where you add different "Password" generators, thereby letting it scale alot better, and use C# great OOP capabilities. The buzz-word here is: Polymorhism

Related

Range in for loop using Array

I'm pretty new to C# and want the users to be able to write in 5 numbers between 1 to 25. The issue I'm having is that I don't want the user to type a number over 25 or a number below 1.
Also this is a task for my studies and my teacher want us to use arrays so I'm not allowed to use List.
int[] usernum = new int[4];
for (int i = 0; i < usernum.Length; i++)
{
usernum[i] = Convert.ToInt32(Console.ReadLine());
}
Ok, to start off, some annotations to your code:
int[] usernum = new int[4]; // should be: new int[5];
for (int i = 0; i < usernum.Length; i++)
{
usernum[i] = Convert.ToInt32(Console.ReadLine()); // use int.TryParse instead
}
Now, I don't want to just give you the code, since this should obviously be a learning experience.
What you need to do, though is integrate a "validation" cycle. That means:
Read in string from user
Try to parse string to number
If that fails: back to 1.
Check if number < 1 or > 25
If so: back to 1.
If you are here, you passed both checks and can
set usernum[i] = number
Next "i"
Obviously, there are some slight variations in how you twist and turn your checks and arrange loops which are equally valid.
For example: You can decide if you want to check if number is inside bounds or if you want to check if the number is outside bounds and jump or not jump accordingly ...
Why int.TryParse instead of Convert.ToInt32?
There are some rule of thumbs that can spare you from severe headaches:
"Never trust user input"
"Do not use exceptions for control flow"
Using Convert here, breaks both.
For one, Convert.ToInt32 throws if the string does not represent an integer value (chars other than +-0..9, value > int.Max or < int.Min). So in using it, you trust the user to type in a valid integer. Not a good idea.
Then, it throwing means: the case, that a user (maybe just made a typo) did not provide valid input is controlling your flow to error handling. But this case is not at all "exceptional". In fact, you should expect it. int.TryParse makes this possible, in that it returns you a flag (boolean) that informs you about success or failure of the conversion attempt (instead of throwing).
Though I would recommend you to learn if else loop first https://www.w3schools.com/cs/cs_conditions.asp
here is the code if needed
int[] usernum = new int[4];
for (int i = 0; i < usernum.Length; i++)
{
var result = Console.ReadLine();
int currentResult;
if (!int.TryParse(result, out currentResult))
{
Console.WriteLine("Invalid input - must be a valid integer value");
i--;
continue;
}
if(currentResult < 1 || currentResult > 25)
{
Console.WriteLine("Invalid input - must be between 1 & 25");
i--;
continue;
}
usernum[i] = currentResult;
}
for-loop might not be the ideal solution for this use-case where you need to conditionally increment the index.
This should do the trick:
int[] userNumbers = new int[5];
int i = 0;
while (i < userNumbers.Length)
{
string rawInput = Console.ReadLine();
bool isNumberValid = int.TryParse(rawInput, out int inputNumber); // as suggested by #Fildor
if(isNumberValid && inputNumber >= 1 && inputNumber <= 25) // increment counter only if 1 <= input <= 25
{
userNumbers[i] = inputNumber;
i++;
}
}

Best way to choose two random ints to assign values to

I am creating a Dungeons and Dragons Character Creator. There is a randomize feature that is going to create a complete character sheet. There is a part that I have gotten to and I am not quite sure the best way to proceed.
The way I have the racial modifiers set up is with if statements. Here is an example.
if (raceInt == 0 || raceInt == 2 || raceInt == 10)
{
raceStrMod = 2;
}
if (raceInt == 3 || raceInt == 4 || raceInt == 5 || raceInt == 11 || raceInt == 12)
{
raceDexMod = 2;
}
However there are races that have modifiers that let you select two stats to add a modifier to, such as Strength or Dexterity. What would be the best way to select two random ints for just those races?
For example, the half-elf race which would get +2 to Dex and then +1 to two other random stats. So I need to find a way to randomly select two of the remaining ints to make the value = 1.
My race mod ints are initialized as
int raceStrMod = 0;
int raceDexMod = 0;
int raceConMod = 0;
int raceIntMod = 0;
int raceWisMod = 0;
int raceChaMod = 0;
Then the if statements assign a value dependent on which race was randomly selected.
Thank you all for the input! This is how I ended up coding it
if (raceInt == 9)
{
int randomX = rnd.Next(1, 5);
int randomY = rnd.Next(1, 5);
int attempts = 0;
while (randomX == randomY && attempts < 10)
{
randomY = rnd.Next(1, 5);
attempts++;
}
//if they are still not unique after 10 attempts
if (randomX == randomY)
{
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
}
int[] randomNumbers = { randomX, randomY };
foreach (int i in randomNumbers)
{
switch (i)
{
case 1:
raceStrMod = 1;
break;
case 2:
raceDexMod = 1;
break;
case 3:
raceConMod = 1;
break;
case 4:
raceIntMod = 1;
break;
case 5:
raceWisMod = 1;
break;
}
}
}
Has your class introduced you to enum types yet? If not, is there any restriction on your final project with respect to using language features that weren't taught in the class?
Your question is arguably too broad, as there are many different ways to address this sort of thing even in real-world code, and the classroom context introduces potential roadblocks that while might constrain the question, being unknown they make it impossible to know what answer is actually going to work for you.
That said…
Ignoring the classroom aspect and focusing only on the problem itself, I would use enum types and dictionaries for this sort of thing. For example:
enum Attribute
{
Strength,
Dexterity,
Constitution,
Charisma,
Intelligence,
Wisdom,
Count, // must always be last
}
Dictionary<Attribute, int> modifiers = new Dictionary<Attribute, int>();
Then you can pick a random attribute like (assuming you have a random variable referencing a Random object…don't make the classic newbie mistake of creating a new Random object every time you want to pick a new random number):
Attribute attributeToModify = (Attribute)random.Next((int)Attribute.Count);
And you can store that selection like:
modifiers[attributeToModify] = 1;
This can be used to store however many modifiers you like. You can encapsulate that in an object representing the character itself, or you could put it into a separate AttributeModifiers class. One advantage of doing the latter would be that if you have modifiers that come from different sources, you can track that in the character object as a list of AttributeModifier instances, each in turn keeping track of what the actual source of those modifiers are.
This just barely scratches the surface. As I noted, the question itself is fairly broad. But I strongly recommend using the available language features to ensure that your variables represent things in a type-specific way, rather than just using int values for things that aren't really integers, and to use collection classes that more correctly represent the semantics of what your code is intended to do.
Note that this also means you probably should have an enum type for the races. E.g.:
enum Race
{
Dwarf,
Elf,
HalfElf,
Halfling,
HalfOrc,
Human,
// etc.
}
And your chain of if statements is probably better represented as a switch:
Attribute racialMod;
switch (race)
{
case Human:
case Halfling:
// etc.
racialMod = Attribute.Strength;
break;
case Elf:
case HalfElf:
// etc.
racialMod = Attribute.Dexterity;
break;
}
modifiers[racialMod] = 2;
Something like that. The point is to make sure the code reads more like what the original specification would say (if you actually had written one). This will make the code easier to understand, and it will be less likely for you to put bugs in the code (e.g. you accidentally type the wrong magic, unnamed integer).
I am creating a Dungeons and Dragons Character Creator.
That's a fun beginner project; I did the same when I was learning to program.
I need to find a way to randomly select two of the remaining...
You need to find two distinct values, call then x and y. The solution you've arrived at is:
Generate x
Try to generate y ten times
If no attempt succeeded to find a distinct y, hard-code a choice.
That works, and you almost never have to use the hard-coded choice. But I thought you might be interested to know that there is an easier way to generate two distinct numbers. Let's suppose we want two distinct numbers from 0, 1, 2, 3 or 4. (Obviously if you want a different range, say, 1 through 5, you can solve that problem by generating two distinct numbers 0->4 and then adding one to each.)
The improved algorithm is:
Choose x between 0 and 4 as usual.
Choose n between 1 and 4.
y = (x + n) % 5;
Think about it this way. Suppose we make a list like this:
0, 1, 2, 3, 4, 0, 1, 2, 3
We randomly choose x from the first five entries on the list, and then we choose y by stepping forwards between 1 and 4 steps. Since the list does not repeat in one to four steps, we know that we'll get two unique elements. The math does the equivalent of that.
You could similarly have used % in your program:
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
could be written
randomY = randomX % 5 + 1
If you're unfamiliar with %, it is the remainder operator. It is the complement of the / operator. The rule is:
int x = whatever;
int y = whatever;
int r = x % y;
is the same as:
int r = x - (x / y) * y;
That is, it is the remainder when x is divided by y. Keep in mind that the remainder can be negative!
(Disclaimer: I don't love this option, but couldn't think of another way other than reflection which is even nastier)
You could define a class that masks the fact that all of the mods are stored as an array and therefore can be indexed using a random number.
Something like the following:
public class StatMods
{
public int RaceStrMod { get { return this.mods[0]; } set { this.mods[0] = value; } }
public int RaceDexMod { get { return this.mods[1]; } set { this.mods[1] = value; } }
public int RaceConMod { get { return this.mods[2]; } set { this.mods[2] = value; } }
public int RaceIntMod { get { return this.mods[3]; } set { this.mods[3] = value; } }
public int RaceWisMod { get { return this.mods[4]; } set { this.mods[4] = value; } }
public int RaceChaMod { get { return this.mods[5]; } set { this.mods[5] = value; } }
private readonly int[] mods;
private static readonly Random rand = new Random();
public StatMods()
{
this.mods = new int[6];
}
public void ApplyRandomMod(int modification)
{
this.mods[rand.Next(0, 6)] += modification;
}
}

Comparing char arrays method

I've been playing space engineers which has been epic since they added in-game programming, I'm trying to make a gps auto-pilot navigation script and have to get the block positions finding the blocks by name looking for a smaller string within their bigger string name. I wrote this method to find a small string (word) in a larger string (name of the block):
bool contains(string text, string wordInText)
{
char[] chText = text.ToCharArray();
char[] chWord = wordInText.ToCharArray();
int index = 0;
for(int i = 0 ; i < chText.Length - chWord.Length ; i++)
for(int j = 0; j < chWord.Length;j++,index++)
if (chWord[0] == chText[i])
index = i;
else if (chWord[j] == chText[index]){}
else if (index == chWord.Length-1)
return true;
else break;
return false;
}
Am I even doing it right, should I be doing it another shorter way?
This is simple with .Contains() which returns a bool.
text.Contains(wordInText);
If you simply want to check if a string contains an other string, then you can use string.Contains, the string class already provides a bunch of methods for string operations.
As already mentioned, the String class already has a Contains method that should give you what you need.
That said, your code doesn't work. I can see where you're going with it, but it's just not going to work. Stepping through it in a proper dev environment would show you why, but since this is more in the way of a script that's probably not an option.
So... the basic idea is to iterate through the string you're searching in, looking for matches against the string your searching. Your outer for statement looks fine for this, but your inner statements are a bit messed up.
Firstly, you're doing the first character check repeatedly. It's wasteful, and misplaced. Do it once per iteration of the outer loop.
Second, your exit condition is going to fire when the first character of wordInText matches the characters at index wordInText.Length in text which is not apparently what you want.
In fact you're all tripped up over the index variable. It isn't actually useful, so I'd drop it completely.
Here's a similar piece of code that should work. It is still much slower than the library String.Compare method, but hopefully it shows you how you might achieve the same thing.
for (int i = 0; i <= chText.Length - chWord.Length; i++)
{
if (chText[i] == chWord[0])
{
int j;
for (j = 0; j < chWord.Length; j++)
{
if (chText[i + j] != chWord[j])
break;
}
if (j == chWord.Length)
return true;
}
}
return false;

How do I easily parse a textbox to perform calculations if operators are found?

Part of my job as an accounting associate requires me to assign expense groups to various items on invoices. For instance, if an office supply company sent us some goods I may have to separate copier paper from pens, and code those to separate expense groups.
Dividing amounts from like expense groups into the overall shipping and tax amounts was a tedious operation, but I decided that I could work smarter by writing a program which would adjust the amounts for me given the input: items[], shipping, tax. This is working like a charm and has really decreased my time needed to work on these tasks.
However, I want to implement an Excel-style functionality whereby I can have + and - operators in the text boxes that will allow me to easily add like items together on one line. (I.e. Pens, sharpies, notepads, which would all be on separate lines on an invoice, all need to be calculated and returned as one sum.)
I'm currently taking the txtValue.Text and converting it to double to perform calculations. I would like to be able to parse that Text value and evaluate the statement entered. If I can glance at an invoice and type in 16.49+22.38+47.06 and know that everything will be fine when I hit my calculate button, then this is going to save me time adding them together on a calculator, for instance.
I wrote this once in VBA for Excel, which natively allows for that, but it just doesn't feel as good as something I custom-make.
string value = "1.2+5.3-1";
char[] delimiters = new char[] { '+', '-' };
string[] parts = value.Split(delimiters);
string[] signs = Regex.Split(value, "[0-9]|\\.");
This will give you an array of numbers (you'll need to convert them to double) and an array of the signs (there will be some empty elements aswell, you should ignore those.
Just iterate over them and use a switch do the actual mathematical operations.
There are several ways to tackle this problem. This is a rough solution I came up with. There are probably a dozen more elegant ways to go about it.
public double Parse(string input)
{
char lastoperator = '0';
double result = 0;
for (int i = 0; i < input.Length; i++)
{
string temp = "";
if (char.IsDigit(input[i]) || input[i] == '.')
temp += input[i];
else if(input[i] == '+' || input[i] == '-')
{
double val;
if(double.TryParse(temp, out val))
{
if(lastoperator == '+')
result += val;
else if(lastoperator == '-')
result -= val;
else
result = val;
lastoperator = input[i];
temp = "";
}
//else error
}
else
continue;
}
return result;
}
Hope that helps.

how to generate a voucher code in c#?

I need to generate a voucher code[ 5 to 10 digit] for one time use only. what is the best way to generate and check if been used?
edited: I would prefer alpha-numeric characters - amazon like gift voucher codes that must be unique.
When generating voucher codes - you should consider whether having a sequence which is predictable is really what you want.
For example, Voucher Codes: ABC101, ABC102, ABC103 etc are fairly predictable. A user could quite easily guess voucher codes.
To protect against this - you need some way of preventing random guesses from working.
Two approaches:
Embed a checksum in your voucher codes.
The last number on a credit card is a checksum (Check digit) - when you add up the other numbers in a certain way, lets you ensure someone has entered a number correctly. See: http://www.beachnet.com/~hstiles/cardtype.html (first link out of google) for how this is done for credit cards.
Have a large key-space, that is only sparsely populated.
For example, if you want to generate 1,000 vouchers - then a key-space of 1,000,000 means you should be able to use random-generation (with duplicate and sequential checking) to ensure it's difficult to guess another voucher code.
Here's a sample app using the large key-space approach:
static Random random = new Random();
static void Main(string[] args)
{
int vouchersToGenerate = 10;
int lengthOfVoucher = 10;
List<string> generatedVouchers = new List<string>();
char[] keys = "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890".ToCharArray();
Console.WriteLine("Vouchers: ");
while(generatedVouchers.Count < vouchersToGenerate)
{
var voucher = GenerateVoucher(keys, lengthOfVoucher);
if (!generatedVouchers.Contains(voucher))
{
generatedVouchers.Add(voucher);
Console.WriteLine("\t[#{0}] {1}", generatedVouchers.Count, voucher);
}
}
Console.WriteLine("done");
Console.ReadLine();
}
private static string GenerateVoucher(char[] keys, int lengthOfVoucher)
{
return Enumerable
.Range(1, lengthOfVoucher) // for(i.. )
.Select(k => keys[random.Next(0, keys.Length - 1)]) // generate a new random char
.Aggregate("", (e, c) => e + c); // join into a string
}
Building on the answers from Will Hughes & Shekhar_Pro (and just because I found this question interesting) here's another implementation but I've been a bit liberal with your requirement for the length of the voucher code.
Using a base 32 encoder I found you can use the Tick value to generate alpha-numeric strings. The encoding of a tick count to base 32 produces a 13 character string which can be formatted to make it more readable.
public void GenerateCodes()
{
Random random = new Random();
DateTime timeValue = DateTime.MinValue;
// Create 10 codes just to see the random generation.
for(int i=0; i<10; ++i)
{
int rand = random.Next(3600)+1; // add one to avoid 0 result.
timeValue = timeValue.AddMinutes(rand);
byte[] b = System.BitConverter.GetBytes(timeValue.Ticks);
string voucherCode = Transcoder.Base32Encode(b);
Console.WriteLine(string.Format("{0}-{1}-{2}",
voucherCode.Substring(0,4),
voucherCode.Substring(4,4),
voucherCode.Substring(8,5)));
}
}
Here's the output
AARI-3RCP-AAAAA
ACOM-AAZF-AIAAA
ABIH-LV7W-AIAAA
ADPL-26FL-AMAAA
ABBL-W6LV-AQAAA
ADTP-HFIR-AYAAA
ACDG-JH5K-A4AAA
ADDE-GTST-BEAAA
AAWL-3ZNN-BIAAA
AAGK-4G3Y-BQAAA
If you use a known seed for the Random object and remember how many codes you have already created you can continue to generate codes; e.g. if you need more codes and want to be certain you won't generate duplicates.
Here's one way: Generate a bunch of unique numbers between 10000 and 9999999999 put it in a database. Every time you give one to a user, mark it as used (or delete it if you're trying to save space).
EDIT: Generate the unique alpha-numeric values in the beginning. You'll probably have to keep them around for validation (as others have pointed out).
If your app is limited to using only Numerical digits then i think Timestamps (DateTime.Now.Ticks) can be a good way to get unique code every time. You can use random nums but that will have overhead of checking every number that its been issued already or not. If you can use alphabets also then surely go with GUID.
For checking if its been used or not you need to maintain a database and query it to check for validity.
If you prefer alphanumerical, you could use Guid.NewGuid() method:
Guid g = Guid.NewGuid();
Random rn = new Random();
string gs = g.ToString();
int randomInt = rn.Next(5,10+1);
Console.WriteLine(gs.Substring(gs.Length - randomInt - 1, randomInt));
To check if it was not used store somwhere previously generated codes and compare.
private void AutoPurchaseVouNo1()
{
try
{
int Num = 0;
con.Close();
con.Open();
string incre = "SELECT MAX(VoucherNoint+1) FROM tbl_PurchaseAllCompany";
SqlCommand command = new SqlCommand(incre, con);
if (Convert.IsDBNull(command.ExecuteScalar()))
{
Num = 100;
txtVoucherNoInt1.Text = Convert.ToString(Num);
txtVoucherNo1.Text = Convert.ToString("ABC" + Num);
}
else
{
Num = (int)(command.ExecuteScalar());
txtVoucherNoInt1.Text = Convert.ToString(Num);
txtVoucherNo1.Text = Convert.ToString("ABC" + Num);
}
con.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex, "Error !!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Try this method for creating Voucher Number like ABC100, ABC101, ABC102, etc.
Try this code
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[15];
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}

Categories

Resources