I'm trying to make it so when the given answer is neither 1 nor 2 the message "Please enter a valid answer." shows up and it goes back to the question.
Here's my code:
Coloration(ConsoleColor.DarkMagenta, "What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int i = 0;
string input1 = Console.ReadLine();
// If answer is not 2, go through this, if answer is 2 continue
if (input1 != "2")
{
// If answer is 1 add 1 to i
if (input1 == "1")
{
i++;
}
// If answer is neither 1 nor 2; go back to question
if (input1 != "1" || input1 != "2")
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
}
}
You want something more like this...
Console.WriteLine("What do you want to do? [1/2]");
Console.WriteLine("1. Draw");
Console.WriteLine("2. Stay");
int userChoice = 0;
bool validInput = false;
while (!validInput)
{
Console.WriteLine();
Console.WriteLine("Enter choice [1/2]...");
string input = Console.ReadLine();
string trimmedInput = input.Trim();
if (trimmedInput == "1" || trimmedInput == "2")
{
validInput = true;
userChoice = Int32.Parse(trimmedInput);
}
}
// We leave the while loop here once validInput == true
// Now take action based on userChoice
Console.WriteLine("You chose " + userChoice);
Console.ReadLine();
As others have noted, you need to keep watching user input. You have your answer but I wanted to also introduce you to the concept of a Read Eval Print Loop (AKA a REPL). Your current solution is not going to scale well. Take a look at the following implementation of your desired UI:
using System;
using System.Collections.Generic;
namespace MyProgram
{
class Program
{
// Don't actually use inner classes. This is just for demonstration purposes.
class Command
{
public Command(string description, Action action)
{
this.Description = description;
this.Action = action;
}
public string Description { get; private set; }
public Action Action { get; private set; }
}
static void Main(string[] args)
{
// Create a dictionary of commands, mapped to the input that evokes each command.
var availableCommands = new Dictionary<string, Command>();
// Note that since we are storing the descriptions / commands in one place, it makes
// changing a description or adding/modifying a command trivial. Want "Draw" to be invoked
// by "d" instead of "1"? Change it here and you're done.
availableCommands.Add("1", new Command("Draw", Draw));
availableCommands.Add("2", new Command("Stay", Stay));
// This command demonstrates how to use a lambda as an action if you so desire.
availableCommands.Add("3", new Command("Exit", () => System.Environment.Exit(1)));
// Build command list string
var cmdList = string.Join('/', availableCommands.Keys);
// Display welcome message
Coloration(ConsoleColor.DarkMagenta, $"What do you want to do? [{cmdList}]");
// Show user initial list of commands
DisplayAvailableCommands(availableCommands);
// Read Eval Print Loop (REPL).
while (true)
{
var userInput = Console.ReadLine();
// If the user entered a valid command, execute it.
if (availableCommands.ContainsKey(userInput))
{
availableCommands[userInput].Action();
// If you want the user to be able to perform additional actions after their initial successful
// action, don't return here.
return;
}
// Otherwise, let them know they didn't enter a valid command and show them a list of commands
else
{
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
DisplayAvailableCommands(availableCommands);
}
}
}
// I'm just assuming your coloration method looks something like this...
static void Coloration(ConsoleColor color, string message)
{
// Keep track of original color so we can set it again.
var originalColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ForegroundColor = originalColor;
}
static void DisplayAvailableCommands(Dictionary<string, Command> commands)
{
// We always want a line above the commands
Console.WriteLine("Available commands:");
foreach (string key in commands.Keys)
{
var command = commands[key];
Console.WriteLine($"{key}. {command.Description}");
}
}
static void Draw()
{
Coloration(ConsoleColor.DarkGreen, "You chose to draw!");
}
static void Stay()
{
Coloration(ConsoleColor.DarkGreen, "You chose to stay!");
}
}
}
Adding new commands will be a breeze. And you can further refactor this to even smaller single-purpose methods. Each command could have its' own class in the event that your commands become more complicated (and in a real app, they will. Trust me). You can refactor the REPL to its' own class/method as well (take a look at this implementation I did a while back for example).
Anyway, this is my $.02 on a more correct way you could build a user interface of this nature. Your current solution is going to work, but it's not going to be fun to work with long-term. Hopefully this helps.
use a while loop to continuously ask for input if not valid, then check the input with a switch statement
bool flag = false;
while(!flag)
{
switch(input1)
{
case "1":
flag = true;
break;
case "2":
flag = true;
break;
default:
Coloration(ConsoleColor.Red, "Please enter a valid answer.");
break;
}
}
Related
C# newbie. Trying to make a simple gradebook program where user:
Enters names of students until 'done' is entered
Enter grades for each user, then calculate average
Part 2 works, but my problem is with part one--you have to hit enter twice to commit the name to the list. For instance, if I enter Bob, Lisa, Kevin, Jane--only Bob and Kevin would make it in--the second line (even if you type something) acts as the line where the console.read is committed to the list.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Csharp
{
class MainClass
{
static List<string> mylist = new List<string> { };
public static void Main(string[] args)
{
UserInput();
GradeEnter();
}
public static void UserInput()
{
Console.WriteLine("Enter Some names (type 'done' when finished)");
do
{
mylist.Add(Console.ReadLine());
} while (!Console.ReadLine().Equals("done"));
}
public static void GradeEnter()
{
foreach (var x in mylist)
{
List<int> myInts = new List<int>();
Console.WriteLine("\nEnter grades for {0}, (enter any letter when done)", x);
while (Int32.TryParse(Console.ReadLine(), out int number))
{
myInts.Add(number);
}
Console.Write("Average is ");
Console.Write(myInts.Average());
}
}
}
}
Any help on this would be much much appreciated!
Thanks
You are calling ReadLine twice.
You can try this instead:
public static void UserInput()
{
Console.WriteLine("Enter Some names (type done to exit)");
string name = Console.ReadLine();
while (!name.Equals("done"));
{
mylist.Add(name);
name = Console.ReadLine();
}
}
Another way of doing the same
public static void UserInput()
{
Console.WriteLine("Enter Some names (type done to exit)");
while (true);
{
string name = Console.ReadLine();
if (name == "done")
{
// This will stop the while-loop
break;
}
mylist.Add(name);
}
}
Now let's analyze what your code is doing
do
{
// Read line and add it to the list. Even if the user writes "done"
mylist.Add(Console.ReadLine());
// Read the console again, if the user enters done, exit. But if the user enters other name, you are discarding it, you are not adding it to the list
} while (!Console.ReadLine().Equals("done"));
Some test cases using your code:
1. Peter <- gets added to the list
2. Lucas <- does not get added to the list, just checks if it is done
3. Mario <- gets added to the list
4. Juan <- again, just checking if it is done, so not added to the list
5. done <- It is treated like a name, so it will be added to the list
6. done <- now it will finish :)
Read name once and then either add it to myList or stop looping:
public static void UserInput() {
Console.WriteLine("Enter Some names (type done to exit)");
for (string name = Console.ReadLine(); !name.Equals("done"); name = Console.ReadLine())
mylist.Add(name);
}
Thanks for everyone's help. I ended up using a combination of while(true) and an if statement:
Console.WriteLine("Enter some names (type 'done' when finished)");
do
{
string name = Console.ReadLine();
if (!name.Equals("done"))
{
mylist.Add(name);
}
else
break;
} while (true);
I wish to make a small insurance application. The application asks your name and then checks if name already exists; if they exist then you get a message this name is already used.
if not then you will be asked what for insurance do you want and then on the screen you get a message the name is correctly signed up.
and i have a function that lists all my client's names and the kind of insurance as a generic list
I make a generic list and in my function i use foreach so i can print every item in the generic list everything works good but if i add a person to my list and i try back and write the same name i don't get error.
Question: Why I don't get a error? what is the problem actually?
Thank you in advance
my code is here under:
public static List<string> klantgegevens = new List<string>();
public static void Main(string[] args)
{
retry:
string naam;
int verzekeringkeuze;
string alleklantgegevens;
Console.WriteLine("wat is u naam");
naam = Console.ReadLine();
if (klantgegevens.Contains(naam))
{
Console.WriteLine("deze naam bestaat al");
}
else
{
Console.WriteLine("kies u soort verzekering: 1-auto,2-leven,3-woning");
verzekeringkeuze = int.Parse(Console.ReadLine());
switch (verzekeringkeuze)
{
case 1:
Console.WriteLine(alleklantgegevens = $"{naam}:auto");
break;
case 2:
Console.WriteLine(alleklantgegevens = $"{naam}:leven");
break;
case 3:
Console.WriteLine(alleklantgegevens = $"{naam}:woning");
break;
default:
break;
}
Console.WriteLine($"{naam} werd correct ingeschreven");
Console.ReadLine();
alleklantgegevens = $"{naam}:{verzekeringkeuze}";
klantgegevens.Add(alleklantgegevens);
}
Printall();
goto retry;
}
public static void Printall()
{
foreach (string gegevens in klantgegevens)
{
Console.WriteLine($"alle klantgegevens:{gegevens}");
}
Console.ReadLine();
}
No error because you check Contains(naam) not $"{naam}:{verzekeringkeuze}" which is what you put in the list.
I'm trying to build a custom commandline for my app, i have several basic commands, and i simply use bunch of "if" statements to check what the command is. currently it looks something like this
public void ExecuteCommand()
{
string input = ReadLine(); //gets last string from input
bool isDone = false; //need bool to check whether command was executed or no, by default false.
Match result = Regex.Match(input, #"([^\s]+)"); //to get command name
string commandName = result.Value.ToLower();
string value = Regex.Match(input, #"\s(.*)").Value; //to get its parameter. currently everything after ' ' space.
if (commandName == "close")
{
Close(); isDone = true;
}
//so commandline is separate window, and appendedForm is a main form. in which some functions are executed.
if (commandName == "exit")
{
appendedForm.Close();
}
if (commandName == "spoof")
{
appendedForm.Fn_Spoof();
isDone = true;
}
if(commandName == "spoofstop")
{
appendedForm.Fn_StopCapture();
isDone = true;
}
if(commandName == "scan")
{
appendedForm.Fn_Scan(); isDone = true;
}
if(commandName == "clear")
{
output.Text = "";
WriteLine("Console cleared. Cache is empty.");
//data_lines.Clear();
isDone = true;
}
...
}
So that's basically it. I have a mainForm, and commandline form. string input is typed into commandline, then I check the name of command and execute some function from mainForm.
My question is, what is the best way of implementing such kind of thing? I surely can just continue writing bunch of "if"s, but something tells me that it's not the best way to make it.
I've thought of creating class "Command"
public class Command
{
public string name;
public string description;
public bool hasParameter;
Command()
{
}
}
And storing all commands in some sort of array, but I am not sure how would I use this to call a function from mainForm.
Any ideas are welcome!
You could stuff all commands into a Dictionary<string, someDelegate>; if you can live with all commands having the same return type.
I have used string and set up a few commands.
I make use of the params keyword to avoid the ugly new object[] on each call.
You still need to cast the arguments, unless you can make them all one type. (Which may actually be not such a bad idea, as they all come from an input string..)
Here is an example:
public delegate string cmdDel(params object[] args);
Dictionary<string, cmdDel> cmd = new Dictionary<string, cmdDel>();
Add a few functions:
cmd.Add("clear", cmd_clear);
cmd.Add("exit", cmd_exit);
cmd.Add("add", cmd_add);
cmd.Add("log", cmd_log);
With these bodies:
public string cmd_clear(params object[] args)
{
return "cleared";
}
public string cmd_exit(params object[] args)
{
return "exit";
}
public string cmd_add(params object[] args)
{
return ((int)args[0] + (int)args[1]).ToString();
}
public string cmd_log(params object[] args)
{
StringBuilder log = new StringBuilder();
foreach (object a in args) log.Append(a.ToString() + " ");
return log.ToString();
}
And test:
Console.WriteLine(cmd["clear"]());
Console.WriteLine(cmd["add"]( 23, 42));
Console.WriteLine(cmd["log"]( 23, "+" + 42, "=", cmd["add"]( 23, 42) ));
Console.WriteLine(cmd["exit"]());
cleared
65
23 + 42 = 65
exit
Of course you still need to use (at least) as many lines for setup as you have commands. And also need to do a similar amount of error checking.
But the command processing part can get pretty simple.
I'm currently trying to manipulate a sort of room system using switches. Now how I would love to do this is referencing one string that will always output into the same value. For example:
int roomIs = 0;
Console.WriteLine("Hello World. Type /Help for help or /Play to play!");
roomIs = 1;
string Enter = Console.ReadLine();
switch (Enter)
{
case ("/Help"):
Console.Clear();
Console.WriteLine("Welcome to the help room, type /Return to return to your last room!");
break;
case ("/Return"):
if (roomIs == 1){
Console.Clear();
Console.WriteLine("Hello World. Type /Help for help or /Play to play!")
}
break;
}
How can I reference the string Enter multiple times under the same name? So I can simply test what input I get, instead of having to create a new string every time I want to add in new options. (In the code I wish to reference the string Enter again when doing the /Return command, that is where I need help.)
I've tried looking through the StringBuilder function, yet I can't seem to make it apply to this.
I guess your're wanting:
int roomIs = 0;
Console.WriteLine("Hello World. Type /Help for help or /Play to play!");
roomIs = 1;
var Enter = default(string);
do
{
Enter = Console.ReadLine();
switch (Enter)
{
case ("/Help"):
Console.Clear();
Console.WriteLine("Welcome to the help room, type /Return to return to your last room!");
break;
case ("/Return"):
if (roomIs == 1)
{
Console.Clear();
Console.WriteLine("Hello World. Type /Help for help or /Play to play!");
}
break;
}
}
while (!string.IsNullOrEmpty(Enter));
is that correct?
I have been trying to work this concept out for days. I have a console program with 3 classes :
1) Main program
2) Create Login screen
3) Actual Login screen
Here is the code:
class Program
{
static void Main(string[] args)
{
//Instantiate Main Menu
Menu myMenu = new Menu();
myMenu.mainMenu();
//testing global values
Login myLogin = new Login();
Console.Write("The new Login is ");
Console.WriteLine(myLogin.newLogin);
//Pause
Console.WriteLine("Press Any Key...");
Console.ReadLine();
}
}
class Menu
{
public void mainMenu()
{
// [create menu that prints choices on the screen]
start:
Console.Clear();
Console.WriteLine("PLEASE CHOOSE AN OPTION");
Console.WriteLine();
Console.WriteLine("[1] LOGIN \n[2] CREATE LOGIN");
Console.WriteLine();
Console.Write("> ");
string menuChoice = Console.ReadLine();
// [switch/case for Main Menu]
switch (menuChoice)
{
case "1":
Console.WriteLine("You chose 1");
break;
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
myLogin.createLogin();
Console.WriteLine(myLogin.newLogin);
break;
default:
Console.WriteLine("INVALID OPTION... TRY AGAIN.");
System.Threading.Thread.Sleep(5000);
goto start;
}
}
class Login
{
// [empty containers for newLogin & newPass]
public string newLogin { get; set; }
public string newPass { get; set; }
public void createLogin()
{
// [display new login screen & assign newLogin & newPass]
Console.Clear();
Console.WriteLine("CREATE NEW LOGIN");
Console.WriteLine();
Console.Write("LOGIN: ");
newLogin = Console.ReadLine();
Console.Write("PASSWORD: ");
newPass = Console.ReadLine();
// [instantiate & return to main menu]
Menu myMenu = new Menu();
myMenu.mainMenu();
}
}
Now when I try to output the code from main program the value is null. Do I have the wrong structure here? I dont really need to store more than one login and pass (for now) so an array is not needed at this point, but im sure ill learn that down the road. I am self learning so I am trying to keep things as simple as I can until I nail the concept.
I want to store the newLogin and newPass and print the values in main. Please help.
Thanks
Mike
In this code:
.....
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
Console.WriteLine(myLogin.newLogin); //WRITE TO CONSOLE
myLogin.createLogin(); // QUERY AFTER WRITE
......
You first write an emtpy login, and after only query for it. So it's "normal" that you don't see any login information on the scree, as it printed before it was intitialized and after never printed again.
To resolve this, just invert function calls:
.....
case "2":
// [instantiate createLogin]
Login myLogin = new Login();
myLogin.createLogin(); // QUERY
Console.WriteLine(myLogin.newLogin); //WRITE TO CONSOLE
...
EDIT
If you want to operate over Login, one of possible solutions is:
class Menu
{
private Login _login = new Login(); // EVERYWHERE IN MENU USE THIS FIELD, THE SAME INSTANCE
.....
case "2":
// [instantiate createLogin]
//Login myLogin = new Login(); NO MORE NEW INSTANCE BUT USE ALREADY AVAILABLE ONE
_login.createLogin(); // QUERY
Console.WriteLine(_login .newLogin); //WRITE TO CONSOLE
...
}
Are you sure it's showing up as null in Main()? You're also printing myLogin.newLogin in your Menu switch/case. When you print it in your Menu, you're printing it before calling myLogin.createLogin() so it should be null, but by the time it gets back to Main() it should be set correctly.
I found an answer. It may not be the best, but it works. Once I corrected the Query/Write problem (listed above) I started thinking more about instances and realized that BY CREATING THE NEW INSTANCE I AM IN FACT CLEARING THE DATA. Sorry for the caps but my intent is to help some other self learner.
Ok so in theory I want to keep the createLogin method once its called in the case. How do I keep it? I made the createLogin, newLogin, and newPass classes static so that the value can be assigned and the class can then be called from main. By calling it without instantiating it, it keeps the value assigned.
class Login
{
// [empty containers for newLogin & newPass]
public static string newLogin { get; set; }
public static string newPass { get; set; }
public static void createLogin()
{
// [display new login screen & assign values]
Console.Clear();
Console.WriteLine("CREATE NEW LOGIN");
Console.WriteLine();
Console.Write("LOGIN: ");
newLogin = Console.ReadLine();
Console.Write("PASSWORD: ");
newPass = Console.ReadLine();
// [instantiate & return to main menu]
//Menu myMenu = new Menu();
//myMenu.mainMenu();
}
and in main:
//testing global values
Console.Write("The new Login is ");
Console.WriteLine(Login.newLogin);
This works, thanks everyone for contributing. It was with others comments that I was able to figure this one out. Hope my solution is clear for someone else. Peace.