Methods and Loops. Way over my head - c#

So I'm trying to get this Method of GetValidString(). Once I get this method done, the rest of the code should be easy.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ReviewEchProject
{
class Program
{
//Arrays that can be called upon anytime
static string[,] employeeInfo = new string[20, 3]; //Used to contain First Name, Last Name, and Title
static int[] badgeArray = new int[20]; //Used to contain badge number
//Main method will be used to call upon the other methods
static void Main(string[] args)
{
Console.WriteLine("Welcome to the Employee Data Base. Please Type a letter to accept the command.");
Console.WriteLine();
Console.WriteLine("A = Add Employee E = Edit Employee S= Search Employee X= Exit");
string userInput = Console.ReadLine().ToUpper();
switch (userInput)
{
case "A":
AddEmployee();
break;
case "E":
EditEmployee();
break;
case "S":
SearchEmployee();
break;
case "X":
break;
default:
Console.WriteLine("Sorry, Invalid Input. Program will now shut down.");
break;
}
Console.WriteLine();
Console.WriteLine("Have a nice day!");
Console.ReadLine();
}
public static void SearchEmployee()
{
Console.WriteLine("I am in the SearchEmployee method");
}
public static void EditEmployee()
{
Console.WriteLine("I am in the EditEmployee method");
}
public static void AddEmployee()
{
for (int i = 0; i < badgeArray.Length; i = i + 1)
{
if (badgeArray[i] != 0)
{
Console.WriteLine("ERROR: Database is full.");
}
if (badgeArray[i] == 0)
{
int badge = GetEmployeeBadgeNumber();
badgeArray[i] = badge;
//Used to create badge number
//Not sure if done correctly, but call upon three times to place names for each slot
string firstName = GetValidString();
employeeInfo[i, 0] = firstName;
string lastName = GetValidString();
employeeInfo[i, 1] = lastName;
string titleName = GetValidString();
employeeInfo[i, 2] = titleName;
Console.WriteLine("Database upload ... ... Success.");
}
}
}
public static int GetEmployeeBadgeNumber()
{
//Needs to return an int that is at least 100 an no greater than 999.
//This method asks for the value from the user.
//Warn the user about this constraint, and stay in a loop until the user gets it right.
return 100;
}
public static string GetValidString()
{
//loop that it stays in until the user enters a valid entry, and when the user does enter a valid entry, it should return the value the user enters
//ask the user to enter a value with a message that uses the passed in messageString
//warn the user the input string must be must be at least 3 letters and less than 20. verify the length. if its not acceptable, write error message and loop again
return "Test";
}
}
}
Same conflicts apply. I'm thinking for the GetValidString() method, I should use a while loop to make sure that it can loop through everything.
**I am forced to use a 2D Array, so I have to use it.

There is far too much code here to write for you. I will however offer suggestions.
An Employee Class with properties for fName, lName, title, badge would make this easier than using 2D arrays
Create an Array of Employees => Employee[] Employees = new Employee[20]
Your methods would then turn into simple loops

Related

Best way to store user input from loop for further operations in another method

This just an example, I would like to be able to use the stored values from the array inside the first method in the second method to find the arithmetic mean, the problem is how do I access it? Or is the array itself a wrong solution?
using System;
namespace arithmetic_mean
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("How many decimal numbers do you plan to enter?");
string userInput = Console.ReadLine();
int num_user;
int.TryParse(userInput, out num_user);
first_method(num_user);
}
static void first_method(int num_user)
{
string[] newarray = new string[num_user];
for (int i = 0; i < num_user; i++)
{
Console.WriteLine("Enter a decimal number:");
newarray[i] = Console.ReadLine();
}
}
static void second_method(string newarray)
{
Convert.ToDouble(newarray);
// get arithmetic_mean
}
}
}
Theres a lot of issues with your code regarding style and best design practices. I won't get into that here and just focus on the question: How do I use the array from first_method somewhere besides first_method?
There are a few ways to use values from one method in another. The simplest way is via the return value. I've rewritten first_method to return the array:
static string[] first_method(int num_user) // The signature changed: void -> string[]
{
string[] newarray = new string[num_user];
for (int i = 0; i < num_user; i++)
{
Console.WriteLine("Enter a decimal number:");
newarray[i] = Console.ReadLine();
}
return newarray; // Added this line.
}
So now you can use that array in Main:
static void Main(string[] args)
{
Console.WriteLine("How many decimal numbers do you plan to enter?");
string userInput = Console.ReadLine();
int num_user;
int.TryParse(userInput, out num_user);
string[] inputs = first_method(num_user); // The return value of first_method is now stored.
// Now it's possible to use the array in second_method:
foreach(var input in inputs)
second_method(input);
}
Again, theres a litany of other issues with your code, but you're clearly new to this. I hope to see you get better in the near future!
In general case you can just enumerate values without storing them (imagine that you get values from, say, a database and you have 10 billion of them), i.e.
using System.Collections.General;
using System.Linq;
...
static IEnumerable<double> first_method(int num_user) {
// for eaxh user
for (int i = 0; i < num_user; ++i) {
// we keep asking until valid value is provided
while (true) {
Console.WriteLine($"For user #{i + 1} enter a decimal number: ");
if (double.TryParse(Console.ReadLine(), out var result)) {
// we return result and keep on doing for the next user
// note yield return, not return
yield return result;
break;
}
Console.WriteNumber("Syntax error. Please, repeat again");
}
}
}
Then whenever you want a collection you can materialize the enumeration:
double[] data = first_method(num_user).ToArray();
If you want to compute arithmetic mean
static void second_method(int num_user)
{
double mean = first_method(num_user).Average();
...
}
Or even, without second_method
static void Main(string[] args)
{
int num_user;
do { // keep asking until correct value provided
Console.WriteLine("How many decimal numbers do you plan to enter?");
string userInput = Console.ReadLine();
}
while(!int.TryParse(userInput, out num_user) && num_user > 0);
double mean = first_method(num_user).Average();
Console.WriteLine($"users: {num_user}, mean: {mean}");
}
Create a List
Add them in there
and pass that to the method.
Easiest, Clear, simple.
I belive best approach is to make small methods which do take arguments and return results of operation. In below example you can see that in Main method there are 3 lines of code which are high level description what program should do. Read numbers from console, then calculate mean, and print mean to console.
Methods like ReadNumberFromConsole have well defined name so you can understand what it does even without reading it's code. Result of work is returned so it can be passed to next method. This way you can easily test and modify code if you need.
using System;
namespace ConsoleApp7
{
internal class Program
{
private static void Main(string[] args)
{
decimal[] numbers = ReadNumbersFromConsole();
decimal mean = CalculateMean(numbers);
PrintMean(mean);
}
private static decimal[] ReadNumbersFromConsole()
{
string userInput = string.Empty;
Console.WriteLine("How many decimal numbers do you plan to enter?");
userInput = Console.ReadLine();
int numbersLength = int.Parse(userInput);
decimal[] numbers = new decimal[numbersLength];
for (int i = 0; i < numbersLength; i++)
{
Console.WriteLine("Enter a decimal number:");
userInput = Console.ReadLine();
decimal number = decimal.Parse(userInput);
numbers[i] = number;
}
return numbers;
}
private static decimal CalculateMean(decimal[] numbers)
{
// Do your calculations here
return 0;
}
private static void PrintMean(decimal mean)
{
// Example display
Console.WriteLine($"Calculate mean is {mean}");
}
}
}

How to determine input when the can have a variable?

I'm working on this commandline based dice. And I want it to be able to output statistics and reset those internal statistics. Currently I have the following classes: Dice and DiceInterface.
I want the user to be able to use the following format for input: "'Throw' to throw the dice, alternate use 'Throw(x)', 'Stat(side)' to see how many times (side) has been thrown, or 'Reset' to reset thrown statistics"
I need a way to determine if the user has typed Throw, Throw(x), Stat(side) or Reset. Throw and Reset are obvious to me but I find it quite difficult to imagine a way to do Throw(x) and Stat(side). Does anyone have any tips or a solution?
Thanks in advance!
using System;
using System.Collections.Generic;
using System.Text;
namespace Oefening_2
{
class DiceInterface
{
static void Main()
{
StartProgram();
}
static void StartProgram()
{
Console.WriteLine("Hello, how many sides would you like the dice to have?");
var input = Console.ReadLine();
if (Int32.TryParse(input, out int number))
{
int desiredSides = number;
Dice NewDice = new Dice(desiredSides);
Console.WriteLine("What would you like to do? ");
Console.WriteLine("Type: 'Throw' to throw the dice, alternate use 'Throw(x)', 'Stat(side)' to see how many times (side) has been thrown, or 'Reset' to reset thrown statistics");
MainIO(NewDice);
}
else
{
Console.WriteLine("That is not an integer! The program will restart now...");
StartProgram();
}
}
static void MainIO(Dice CurrentDice)
{
Console.Write("Input: ");
string input = Console.ReadLine();
//Throw
if (input == "Throw")
{
Console.WriteLine(CurrentDice.Throw());
MainIO(CurrentDice);
}
//Throw(x)
else if(input == "")
//Thrown(side)
//Reset
else if (input == "Reset")
{
CurrentDice.ResetStatistics();
MainIO(CurrentDice);
}
}
}
}
using System;
namespace Oefening_2
{
class Dice
{
public int Sides { get; set; }
private readonly Random _rnd = new Random();
public int[] Thrown;
public Dice(int sides)
{
Sides = sides;
Thrown = new int[sides--];
}
public Dice():this(6)
{
}
public int Throw()
{
int thrownNumber = _rnd.Next(1, Sides);
Thrown[thrownNumber]++;
return thrownNumber;
}
public int NrOfTimesThrown(int side)
{
int result;
result = Thrown[side];
return result;
}
public void ResetStatistics()
{
for(int i = 0 ; i < Sides; i++)
{
Thrown[i] = 0;
}
}
}
}
This can be fairly simply done with StartsWith to check if a string starts with some prefix, and use .Remove to get anything after this prefix:
if(input.StartsWith("Stat"){
var parameterString = input.Remove(0, "Stat".Length);
if(int.TryParse(parameterString , out var side){
...
}
}
If I correctly understood your problem, it could be solved with an approach like this:
Console.WriteLine("Enter a value");
var s = Console.ReadLine();
if(s.Contains('('))
{
int pFrom = s.IndexOf("(");
int pTo = s.LastIndexOf(")");
var myChoice = s.Substring(0, pFrom);
var myValue = s.Substring(pFrom + 1, pTo - pFrom);
Console.WriteLine($"You choosed : {myChoice}");
Console.WriteLine($"With a value of: {myValue}");
}
This is just a brief example of how to "understand" if there is a value and then recover it.
I hope this could help you somehow.

Alternative to goto statement

I'm pretty new to C# (started learning it a week ago) with a little bit of experience in batch and Expression 2, and I've been working on a text-based game in an attempt to learn more. I used goto statements at first, but according to pretty much everyone I've found, goto statements are some amalgam of death and despair, so I want to learn cleaner, less evil ways to achieve the same effect. Here's a crummy example script I made to demonstrate what I mean:
using System;
namespace TestScript
{
class Program
{
public static void Main(string[] args)
{
string ConsoleReadinator;
string ConsoleReadinator2;
int Go = 0;
mainmenu:
do
{
Go = 0;
Console.Clear();
Console.WriteLine("Main Menu:");
Console.WriteLine("Store or something");
ConsoleReadinator = Console.ReadLine().ToUpper();
if (ConsoleReadinator == "STORE") { Go = 1; }
} while (Go == 0);
// In-game store example
{
Go = 0;
do
{
Console.Clear();
Console.WriteLine("In-game store I guess");
Console.WriteLine("Stuff you can buy, etc");
ConsoleReadinator2 = Console.ReadLine().ToUpper();
if (ConsoleReadinator2 == "GO") { Go = 1; }
} while (Go == 0);
goto mainmenu;
}
}
}
}
This script is functional, but I'd like to avoid using goto as a way to go back to previous statements in order to navigate menus and maybe to repeat algorithms for turn-based games. I read about using methods for this in Alternative to using goto statement in C# (which is basically the same question I have, except a bit more vague), but the example Greg made there didn't work for me at all, to the point that it's probably not worth trying to make that particular example work.
As far as I can see you want an infinite loop:
...
while (true)
{
do
{
...
} while (Go == 0);
Go = 0;
do
{
...
} while (Go == 0);
}
You could use recursion in order to go back and execute code again. For this purpose you could move your code to a separate method and call it in this method:
class Program
{
public static void Main(string[] args)
{
string ConsoleReadinator;
string ConsoleReadinator2;
Method(0);
}
private static void Method(int Go)
{
do
{
..
} while (Go == 0);
// In-game store example
do
{
...
} while (Go == 0);
Method(Go);
}
}
Or you could use loops in a better way. Let's have a look at the example when we want user to enter an integer number :
public static void Main(string[] args)
{
int num;
// This loop ends only when user enters proper integer number
do
{
Console.Clear();
Console.Write("Please enter some integer number: ");
} while(!int.TryParse(Console.ReadLine(), out num));
}
This could be done other way with recursion:
public static int EnterNumber()
{
Console.Clear();
Console.Write("Please enter some integer number: ");
// if the number is successfully parsed return number else run this method again
return int.TryParse(Console.ReadLine(), out num) ? num : EnterNumber();
}
public static void Main(string[] args)
{
int num = EnterNumber();
}
With all the options we have (methods, loops and recursion) there is no practical use case for using GO TOs anymore.
In general you use methods or lambda expressions. So your mainmenu would become a method that you call again at the end of the code.
One suggestion would be to use a switch case construct like this:
static void Main(string[] args)
{
string ConsoleReadinator;
string MENU_TEXT = "Main Menu:";
string ADDITIONAL_INFO = "Store or something";
bool endProg = false;
ConsoleReadinator = printMenu(MENU_TEXT, ADDITIONAL_INFO);
// as long "EXIT" is not typed
while (!endProg)
{
switch (ConsoleReadinator)
{
case "STORE":
// Do your Store Stuff
// maybe change MENU_TEXT and ADDITIONAL_INFO
// and print a new Menu
ConsoleReadinator = printMenu(MENU_TEXT, ADDITIONAL_INFO);
break;
case "GO":
// Do your Go Stuff
break;
case "EXIT":
endProg = true; // set exit condition to true
break;
default:
break;
}
}
Console.ReadKey();
}
// one Method to use for Menu display
public static string printMenu(string menuText, string additionalInfo)
{
Console.Clear();
Console.WriteLine(menuText);
Console.WriteLine(additionalInfo);
return Console.ReadLine().ToUpper();
}

Returning a value from a static void to a static void, that make use of public variables - some guidance please

Just so everyone knows I have literally just started writing C#, and this is practice.
I found a GuessTheNumberGame code on the internet and have been trying to improve the basic game so that feedback is given, and the user can change the numbers.
I had the program working but wanted to put the 'NumberChange' module separate from the 'Code' Method.
I have made a Main() Method inside of my 'GuessTheNumberGame' with executes the 'Code' method.
The thing is when I go to change the number range the 'NumberChange' module won't change the values of 'Public Static int from' or 'Public static int to'; and because of this the range of the numbers remains the same.
Code below:
using System;
namespace GuessThatNumber
{
class GuessTheNumberGame
{
static void Main()
{
Code(from, to, new_range);
}
public static int new_range = 0;
public static int from = 1;
public static int to = 10;
static void Code(int from, int to, int new_range)
{
//int from = 1; // The range the user will guess from.
//int to = 10; //The range the user will guess to.
int guessedNumber; //This will hold the value that the user guessed.
int Counter = 0; //Counter is used to count the number of guesses the user makes.
int selection = 0; //This value is for the selection at the start of the program
//int new_range = 0;
bool exit = false;
while (exit == false)
{
Console.WriteLine("What would you like to do?");
Console.WriteLine("1: Alter the range of guessed numbers? The range is currently from {0} to {1}.", from, to);
Console.WriteLine("2: Try to guess the number?");
Console.WriteLine("3: Exit the program?");
Console.WriteLine("Please enter a number:");
if (int.TryParse(Console.ReadLine(), out selection))
{
if (selection == 2)
{
int randomNumber = new Random().Next(from, to); //Generates a random number between the (from, to) variables.
Console.Write("The number is between {0} and {1}. ", from, to);
while (true)
{
Console.Write("Make a guess: ");
if (int.TryParse(Console.ReadLine(), out guessedNumber))
{
if (guessedNumber == randomNumber)
{
Console.WriteLine("You guessed the right number!");
if (Counter < 2)
{
Console.WriteLine("You guessed the number in only 1 turn! Amazing!");
Console.WriteLine(" ");
}
else
{
Console.WriteLine("You guessed " + Counter + " times.");
Console.WriteLine(" ");
}
break;
}
else
{
Console.WriteLine("Your guess was too {0}.", (guessedNumber > randomNumber) ? "high" : "low");
Counter = Counter + 1;
}
}
else
{
Console.WriteLine("Input was not an integer.");
}
}
//Console.WriteLine();
//Console.WriteLine("Press any key to exit.");
//Console.ReadKey();
}
else if (selection == 1)
{
NumberChange(from, to, new_range);
}
else
{
exit = true;
}
}
}
}
static int NumberChange(int from, int to, int new_range)
{
Console.WriteLine("Please enter the number that the guess will start from.");
int.TryParse(Console.ReadLine(), out new_range);
from = new_range;
Console.WriteLine("Now enter the number that the guess will go to.");
int.TryParse(Console.ReadLine(), out new_range);
to = new_range;
return new_range;
}
}
}
Please read about passing parameters by reference in C#.
So far, your parameters are passed by value. That means that upon calling Code() in the beginning of your program, the current values of public static int from and public static int to are copied into the parameters from and to.
The same happens when you invoke NumberChange(): The values of the parameters (local variables) from and to are copied into the parameters of the NumberChange() method with the same names, but if those values are modified within NumberChange, the new values don't ever get back from there; you have just modified the local variables from and to that only exist within the respective method.
Instead, you could declare your parameters using the ref keyword:
static int NumberChange(ref int from, ref int to, int new_range)
This means that you will have to invoke your method using the ref keyword for the respective arguments, too:
NumberChange(ref from, ref to, new_range);
Also, note two issues about your NumberChange() method:
You pass in a new_range argument, but you do not use it. In fact, it is overridden in your call to TryParse(). Therefore, you could simply declare int new_range as a local variable rather than passing it as a parameter.
You return a value from that method, but you do not use that value. Therefore, you could declare your method as void and drop the return statement.
Lastly, if you want your public static int from and public static int to variables to be changed by Code(), add the ref keyword analogously to NumberChange(). However, this is not really useful with your current code, as the program ends right after leaving Code() and the new values wouldn't be used at all.
You are using static variables, then passing them into a method that has access to them already. Passing them in essentially overrides the static versions with the local ones.
Change your method to this:
private static void NumberChange()
{
int new_range;
Console.WriteLine("Please enter the number that the guess will start from.");
int.TryParse(Console.ReadLine(), out new_range);
from = new_range;
Console.WriteLine("Now enter the number that the guess will go to.");
int.TryParse(Console.ReadLine(), out new_range);
to = new_range;
}
static void Code()
{
}
And delete this line:
public static int new_range = 0;
If you pass your variables by reference. Then the function your passing them can change them.
something like this
static int NumberChange(ref int from, ref int to, ref int new_range)
{
//Your code here
}
Adn the same for your Code method

C# console application - commission calculator - how to use method within method

I'm new to C# and I have encountered some problems with my console application that I'm recently working on. I am trying to have 3 methods:
getsales to get the sales the user made, calcCom to calculate the commission for the sales and finally main to make them work and establish the program.
I'm having trouble to make those methods work with(in) each other.
After i entered all the sales, the program goes to the else-statement and tells me "invalid entry". Since i haven't really gotten to output the variables I didn't expect any kind of output, but I want the program to tell the user the commission and sale for each person.
Please excuse me if I misused any terms or words, like I said I am new to this language! :D
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication38
{
class Program
{
public static void getsales ()
{
string inputsales;
double total = 0;
double sale = 0;
for (int salecount = 1; salecount <= 3; ++salecount)
{
Console.WriteLine("Enter sale: ");
inputsales = Console.ReadLine();
sale = Convert.ToDouble(inputsales);
total = total + sale;
Console.WriteLine();
}
}
public static void calcComm ()
{
double total = 0;
double comm = 0;
comm = total * 0.2;
}
static void Main()
{
Console.WriteLine(" Sunshine Hot Tubs \n Sales Commissions Report\n");
char Letter;
string name;
const string name1 = "Andreas";
const string name2 = "Brittany";
const string name3 = "Eric";
string inputLetter;
Console.WriteLine("Please enter intial or type z to quit");
inputLetter = Console.ReadLine();
Letter = Convert.ToChar(inputLetter);
while (Letter != 'z')
{
if (Letter == 'a')
{
name = name1;
getsales();
calcComm();
}
if (Letter == 'b')
{
name = name2;
getsales();
calcComm();
}
if (Letter == 'e')
{
name = name3;
getsales();
calcComm();
}
else
{
Console.WriteLine("Invalid entry try again");
inputLetter = Console.ReadLine();
}
}
}
}
}
I think your problem is you need this:
if (Letter == 'a')
{
name = name1;
getsales();
calcComm();
}
else if (Letter == 'b')
{
name = name2;
getsales();
calcComm();
}
else if (Letter == 'e')
{
name = name3;
getsales();
calcComm();
}
else
{
Console.WriteLine("Invalid entry try again");
inputLetter = Console.ReadLine();
}
You also need to copy this code after the else block, at the very end of your while loop.
Console.WriteLine("Please enter intial or type z to quit");
inputLetter = Console.ReadLine();
Letter = Convert.ToChar(inputLetter);
Also, remove this line from inside the else block. It isn't needed.
inputLetter = Console.ReadLine();
You probably intended to display the commision on the console. Change your getsales and calcComm to look like this:
public static void getsales ()
{
string inputsales;
double total = 0;
double sale = 0;
for (int salecount = 1; salecount <= 3; ++salecount)
{
Console.WriteLine("Enter sale: ");
inputsales = Console.ReadLine();
sale = Convert.ToDouble(inputsales);
total = total + sale;
Console.WriteLine();
}
calcComm(total);
}
public static void calcComm (double total)
{
double comm = 0;
comm = total * 0.2;
Console.WriteLine(comm);
}
Then remove all calls to calcComm from the Main method.
The variable "total" is in the two methods and they do not persist the data that you are looking for between the two methods that you have defined. That is, the total variable in getSales() method is different from calcComm() method.
You should move this:
double total = 0;
outside of the two methods and put it within the class with a static scope. Like:
class Program
{
static double total;
Also, reinitialize total to zero within your getSales() method.
calcComm() doesn't do anything...
I think you might want to have some of your variables as global so that if they are modified by a method you can still retrieve their value, or even better pass them to the method and get them returned with the new values.
To declare global variables you should declare them inside the class Program but outside any method and then make sure that no other methods have variables with the same name

Categories