I would like to know how to go from a method back to main. For example, I want to check if number passes a certain criteria; I would perform a test in a different method and if it returns true, I want to continue using that number back in main. How can go from one method to main again in a continuous loop? I tried calling the main method but the program displays a message for error.
The way my project is set out is that a menu appears for the user to enter a postal code. The menu has many options to add, quit, or view their codes. Once they have added their postal code and it is valid, how can I loop it back to main with the menu appearing again, performing the same functions?
Small section from main:
if (decision.Equals("A"))
{
Console.Write("\n");
Console.WriteLine("Please enter your postal code: ");
for (i = 0; i < 1; i++)
{
postalcodez = Console.ReadLine().ToUpper();
if (isValid(postalcodez, i, number, j, num))
{
postalcode[i] = postalcodez;
Console.WriteLine("It worked!");
Console.ReadLine();
}
}
}
Now it goes through the method to check for conditions. If it returns true, how can I make it go back to main?
public static bool isValid(string postalcodez, int i, int number, int j, int num)
{
if (postalcodez.Length > 7 || postalcodez.Length < 7)
{
return false;
}
if (postalcodez[0].ToString().Equals("W") || postalcodez[0].ToString().Equals("Z"))
{
return false;
}
if (postalcodez.Length.Equals(7))
{
if (postalcodez[3].ToString().Equals(" "))
{
return true;
}
else
{
return false;
}
Another question is that how can I make an array so that I can set a condition for a specific character number. Instead of doing this ( where I hard code specific digits) I want it that the 1, 4 and 6th character must be a certain value :
if (postalcodez[1].ToString().Equals(0) || postalcodez[1].ToString().Equals(1) || postalcodez[1].ToString().Equals(2) || postalcodez[1].ToString().Equals(3) || postalcodez[1].ToString().Equals(4))
{
return true;
}
Since this is for school, I can use any special functions to resolve the issue. It has to be very basic.
It seems like you have a bit of a misunderstanding of what Main() actually is. Main() is, in effect, your entire application. Main is the root that everything will flow back to when the current call stack finishes resolving, and if there are no additional statements after that point, Main will complete, and the application will close. When you call methods from Main, when they return a value (if not void), you are then back inside of Main.
Based on what you have stated is your need, here is a very basic example of what will happen - the flow of the code should be reasonably clear:
private static void Main(string[] args)
{
int number = 5;
bool isValid = VerifyNumber(number);
if (!isValid)
Console.WriteLine("Not valid.");
else
Console.WriteLine("Valid.");
Console.ReadKey();
}
private static bool VerifyNumber(int number)
{
return number > 2;
}
Things to take note of:
Since the method being called from Main has an argument, that argument is provided from inside of Main. This means that when the method finishes, Main still has access to that value.
The output of the method is stored so that work can be done inside of Main based on it.
Related
Original Title: Get-Set to add Object w/multiple properties into a list C#
Edit: I had originally thought the issue was in setting up properties for the list objects, when it was an issue with regards to where I had initialized the list in my main code class.
Original Post:
New to coding, taking a C# course. We're working on encapsulation and get:set/properties.
The assignment says that we have to build a class that creates a die with an input number of sides, and "roll" the die for a random number. Easy!
In a second class, we have to build a function to add or remove any number of dice to the pool, and then roll them all for a result.
I'm assuming they want the dice pool to be a list that is private.
My logic going in was to create the single OneDie class, and then using a xDy notation in the main program prompt to add x number of die with y sides to the list. (ie: add 2d6)
I've built an AddDie function that should do that, but when I check my list count after it's done, the count is 0. The private list (_dicePool) seems to be re-setting to zero every time I try to add a new object to the list. I suspect I'm not building my property DicePool's get/set functionality correctly, but I'm not sure how to call my 2-parameter AddDice function from inside the DicePool{set}, or even if that's the approach I should take.
Assuming the list should be private, am I missing something to permanently add new objects to the list?
Edit to add: OR, would it be better to create a ManyDice object? But how do I build this.Sides and this.Roll from the OneDie object?
Here's my code that's applicable to adding objects (dice) to the list (dicepool).
class ManyDice
{
private List<OneDie> _dicePool = new List<OneDie>();
//What I think I might have to do:
public List<OneDie> DicePool
{
get
{
return this._dicePool;
}
set
{
//???????????? how do I call AddDice, when I need 2 parameters for it?
}
}
public void AddDie(int number, int sides)
{
for (int i = 0; i < number; i++)
{
this.dicePool.Add(new OneDie(sides));
}
}
}
class OneDie
{
private int _sides, _rolledValue;
public int Sides
{
get
{
return this._sides;
}
set
{
this._sides = value;
}
}
public int RollValue
{
get
{
return this._rolledValue;
}
set
{
this._rolledValue = value;
RollIt(value);
}
}
public OneDie()
{
}
public OneDie(int sides)
{
this.Sides = sides;
this.RollValue = sides;
}
private int RollIt (int sides)
{
Random random = new Random((int)DateTime.Now.Ticks);
return random.Next(1, (sides + 1));
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Let's roll some dice!");
Console.WriteLine("Please enter the number of dice you want to roll in the following format:");
Console.WriteLine("xdy, where \"x\" is the number of dice you want and \"y\" is how many sides they have.");
Console.WriteLine("Example: 2d6 is 2 6-sided dice. Perfect for playing Catan! (or Monopoly)");
Console.WriteLine("Please limit your dice to d4, d6, d8, d10, d12, d20");
Console.WriteLine("To add a die, type \"add xdy\" to add x number of y sided dice.");
Console.WriteLine("To remove a die, type \"remove xdy.\" to remove x number of y sided dice.");
Console.WriteLine("Type \"dice\" to see a list of all the dice in the pile.");
Console.WriteLine("Type \"roll\" to roll all the dice and see the results!");
Console.WriteLine("Type \"clear\" to clear all the dice and start agin!");
Console.WriteLine("Type \"exit\" to exit program\n");
PlayDice();
Console.ReadKey();
}
static void PlayDice()
{
do
{
string[] xDy = null;
int numberOfDice = 1;
int numberOfSides=1;
Console.WriteLine("\nEnter your command:");
string option = Console.ReadLine();
option = option.ToLower().Trim();
string[] words = option.Split(' ');
string command = words[0];
//CheckCommand(command);
if (words.Length > 1)
{
xDy = words[1].Split('d');
numberOfDice = int.Parse(xDy[0]);
numberOfSides = int.Parse(xDy[1]);
}
ManyDice die = new ManyDice();
if (command == "exit")
{
Console.WriteLine("Thank you, play again, soon!");
break;
}
else if (command == "add")
{
//numberOfSides=CheckDice(numberOfSides);
die.AddDie(numberOfDice, numberOfSides);
Console.WriteLine("You have {0}ed {1} {2}-sided dice.", command, numberOfDice, numberOfSides);
}
else if (command == "remove")
{
Console.WriteLine("You have {0}d {1} {2}-sided dice.", command, numberOfDice, numberOfSides);
}
else if (command == "dice")
{
Console.WriteLine("These are your dice:");
die.Display();
}
else if (command == "roll")
{
Console.WriteLine("Here is your roll:");
}
else if (command == "clear")
{
Console.WriteLine("All dice have been cleared.");
}
} while (true);
}
static int CheckDice(int sides)
{
List<int> check = new List<int> {4,6,8,10,12,20};
while (!check.Contains(sides))
{
Console.WriteLine("{0}-sided dice are not available.\nPlease enter 4,6,8,10,12 or 20");
sides = int.Parse(Console.ReadLine());
}
return sides;
}
static string CheckCommand(string instructions)
{
List<string> check = new List<string> { "add", "remove", "dice", "roll","clear", "exit" };
while (!check.Contains(instructions))
{
Console.WriteLine("Command not recognized.\nPlease enter \"add\", \"remove\", \"dice\", \"roll\",\"clear\", or \"exit\"");
instructions = Console.ReadLine();
}
return instructions;
}
}
New Answer based on comments and updated question:
The line ManyDice die = new ManyDice(); is wiping your dice list clean every loop through your program. It's replacing your variable with a new instance of the class, with a fresh list and all.
Simply move that line before the start of the loop:
before the line do {
and then every iteration will use the same instance of ManyDice, and will all share the variable die, without overwriting it.
OLD ANSWER: From what I can see, your program only runs once. And then you need to start it again to put in another dice. Your main function only asks for input once. Whenever you start the program again, all the memory used in the program gets cleared. Unless I’m missing something, that is why your list continues to be reset. You’re actually running a completely new program the next time you try to add dice. So it has no knowledge of the previous runs.
One solution is to say (pseudo code)
While (running) {
// what you have now
if (option == “done”) running = false;
if (option == “roll”) // roll all dice.
}
This will keep prompting the user for commands until they type done. And it remains the same program so that you don’t lose the data from earlier commands.
Update based on comment: you’re recreating the ManyDice instance on each iteration, effectively starting from scratch. Save the instance outside the while loop and then reuse it.
Hint:
Your rolling should probably be done by manyDice.RollAll() And maybe should return a List of RollResults.
Here is my dilemma:
public void checkCountProgress(int countProgress, int totalDataSize){ //work done here}
public void func1(int passVar)
{
for(int = 0; i<= 2000; i+=64){
//do work
checkCountProgress(i, 2000);
}
}
Everytime when I iterate through the for-loop, i obviously changes by increments of 64. The checkCountProgressFunction gives me the value of i at whichever point my client connection to the remote host gets disconnected. So I want to continue writing and sending data to the network from where I left off. I would manually stop my server, change the value of i in the parameter of the calling function, run, update service reference from client side and continue but now I need to automate that because I now have to include multiple connections to the host. When I look at some examples, it usually refers to passing a parameter from one function, getting its value and using it in another method (How to pass value from one method to another? ) which is entirely different to what I want to do. How can I achieve this?
You mean using settings to store the value at which the loop was stopped?
If so, here's an example of how to use them
In your project's Properties, in the Settings tab add a new setting of you desired value type and set the scope to User. For my example I created one named ValueToResume of type Int and initial value of 0.
static void Main(string[] args)
{
int initialLoopValue = Properties.Settings.Default.ValueToResume;
for (int i = initialLoopValue; i <= 2000; i += 64)
{
//do work
checkCountProgress(i, 2000);
}
Properties.Settings.Default.Reset(); //Loop was completed, we can reset the setting to 0
}
public static void checkCountProgress(int countProgress, int totalDataSize)
{
if (countProgress > 600)
{
Properties.Settings.Default.ValueToResume = countProgress;
Properties.Settings.Default.Save();
Environment.Exit(0); //force application exit
}
}
}
On the second run, the loop will be initialized at value 640
I've created a small application that does a small conversion. At the end of the program I've created a method that allows the user to make another calculation if they press 'r'. All I want it to do is if they press r, take them back to the beginning of Main, else terminate program. I do not want to use goto. This is what I've got so far, and the error I'm getting.
http://puu.sh/juBWP/c7c3f7be61.png
I recommend you use another function instead of Main(). Please refer to the code below:
static void Main(string[] args)
{
doSomething();
}
public static void WouldYouLikeToRestart()
{
Console.WriteLine("Press r to restart");
ConsoleKeyInfo input = Console.ReadKey();
Console.WriteLine();
if (input.KeyChar == 'r')
{
doSomething();
}
}
public static void doSomething()
{
Console.WriteLine("Do Something");
WouldYouLikeToRestart();
}
A while loop would be a good fit, but since you say the program should run and then give the user the option to run again, an even better loop would be a Do While. The difference between while and Do While is that Do While will always run at least once.
string inputStr;
do
{
RunProgram();
Console.WriteLine("Run again?");
inputStr = Console.ReadLine();
} while (inputStr == "y");
TerminateProgram();
In your case, you want to repeat something so of course you should use a while loop. Use a while loop to wrap all your code up like this:
while (true) {
//all your code in the main method.
}
And then you prompt the user to enter 'r' at the end of the loop:
if (Console.ReadLine () != "r") {//this is just an example, you can use whatever method to get the input
break;
}
If the user enters r then the loop continues to do the work. break means to stop executing the stuff in the loop.
I have a program that is completely functional, and I am now refactoring it. I am just in the process of learning c# so the original code was pretty terrible despite the fact that it ran just fine. One of the requirements of the program is that the user be able to return to the main menu at any point. I accomplished this as follows:
static bool bouncer = false
static void Exit(string input)
{
if (input == "\t")
{
bouncer = true
}
}
static string Prompt(string msg)
{
// takes input and passes it to Exit() then returns the input
}
static string FunctionA()
{
while(true)
{
if (bouncer == true)
{
break;
}
Prompt("whatever")
if (bouncer == true)
{
break;
}
Prompt("whatever")
if (bouncer == true)
{
break;
}
// return some stuff
}
}
static void Main()
{
bouncer = false
// writes the menu to console and handles UI
// FunctionA
{
The variable bouncer gets set to true if the user enters the "tab" character at any input point. The proliferation of break statement conditionals provides the structure that actually breaks out back to Main(). This is obviously not a very good solution and it makes the code hard to read.
Other attempts that I considered to accomplish the same task are:
Goto statement that jumps straight back to Main(). I scrapped this because goto has a very limited scope in c# and I don't think there is any good way to make it workable in this situation.
Calling Main() directly from Exit(). This is probably a bad idea, and I can't do it anyway because apparently Main() is "protected" in some way.
Using an event to react to TAB or ESC being pressed. It's unclear to me how I could use an event to do this since I still wouldn't be able to break right out of the event. My understanding is that the break statement has to actually be contained in the loop that needs to be broken as opposed to being written into a different function that is called from within the loop.
Any suggestions are greatly appreciated. I'm hoping there's something to be done with event handling or that I've overlooked something more simple. Thanks!
As a matter of coding style, the way it is works, but is seen as ugly. Unfortunately, if you need to break out immediately between sections of work, there is not a lot of ways around that.
You can change your current format of using breaks to using "if( bContinue ) { /* do next section of work */ }" control style. It changes the code from break out of the while loop to this:
static string FunctionA()
{
bool bContinue = true;
while( true == bContinue )
{
// Do initital work.
//
// Initial work can set bContinue to false if any error condition
// occurs.
if( true == bContinue )
{
// Do more work.
int returnCheck = MakeACall(); // Presume MakeACall returns negative interger values for error, 0 or positive values for success or success with condition/extra information.
if( 0 < returnCheck )
{
bContinue = false;
}
}
if( true == bContinue )
{
Prompt("whatever")
// Do more work.
bContinue = MakeASecondCall(); // Presume that MakeASecondCall returns true for success, false for error/failure
}
if( true == bContinue )
{
Prompt("whatever")
// Do more work.
// If error encountered, set bContinue to false.
}
if( true == bContinue )
{
Prompt("whatever else")
// Do more work.
// If error encountered, set bContinue to false.
}
// Done with loop, so drop out.
bContinue = false;
// return some stuff
}
}
Looking at your pseudo code, it reads like you only do a single pass through your work loop. If so, you can switch to a Do-While(false) format, and use the break to just drop to the bottom. Or, if you are only doing a single pass through your FunctionA, just do away with the While or Do-While control structure, and just use the if(true==bContinue){ /* Do more work */ }. It is not the cleanest of code, but when you perform long periods of serial work, you end up with such structures if you are not going to use a while or do-while for controlling the flow.
The disadvantage to using the if(bContinue){} style is that when an error condition occurs during the early stages of the process, the code does not exit out as quickly from the function as a break out of the while() or do-while() structure if the error occurs near the top of the work, as there will be the series of if statements that the code will test and then skip over. But it is readable, and if you use a descriptive name for your control variable (ie, nContinue or bContinue or workLoopControl) it should be fairly obvious that it is the master control flag for the function's work flow to whoever works or reviews the code after you.
Instead of an infinite loop and break statements, try using a conditional flag instead.
static void FunctionA()
{
bool done = false;
string response = string.Empty;
while (!done)
{
response = Prompt("whatever");
if(response == '\t')
{
done = true;
}
}
}
As a side note, I'm not sure why you have 'string' as the return type of several methods (e.g., 'FunctionA') when you aren't using the return value. That's why the code I gave above has it as 'void'.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been studying Deitel's Visual C# 2010. I'm stuck at an exercise in the chapter about arrays. It's been bugging me for days now, and I've written the code several times now and each times something goes wrong.
The exercise is asking to develop a new reservation system for a small airline company. The capacity of an airplane is 10 seats. So you ask the customer to input 1 for First Class and 2 for Economy. Seats from 1 to 5 are for first class. Seats from 6 to 10 are for economy.
I must use a one-dimensional array of type bool to represent the seating char of the plane. Initialize all elements of the array to false to represent vacant seats (Luckily bool initializes to false anyway, because I do not know how to initialize an array). As each seat is assigned, set the corresponding element in the plane to true.
The app should never assign a seat that's already been seated. When the economy class is full, the app should ask the customer if he wants to fly in first class (and vice versa). If the customer responds with yes, assign him in the economy class (if there's an empty seat there). If there is no empty seats in economy or the customer refuses to fly in first class, then just display to him that "The next flight is after three hours!).
I'm self-studying the book. This is not an assignment or homework. I really do not wish to post the code I've written because I want a completely fresh way to solve the problem, but I'm pretty sure that I will be asked about the code, so here it is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Craps_Game
{
class AirlineReservation
{
private static bool[] seats = new bool[10];
private static void FirstClass(ref bool[] seats)
{
for(int i = 0; i < 5; i++)
{
if (seats[i] == false)
{
seats[i] = true;
Console.WriteLine("Your seat number is " + i);
break;
}
else
{
Console.WriteLine("First Class is full. Would you like to fly Economy?");
if (Console.ReadLine().ToLower() == "y")
Economy(ref seats);
else
Console.WriteLine("The next flight is in three hours!. Good bye");
}
}
}
private static void Economy(ref bool[] seats)
{
for (int i = 5; i < 10; i++)
if (seats[i] == false)
seats[i] = true;
else
{
Console.WriteLine("Economy class is full. Would you like to fly First Class");
if (Console.ReadLine().ToLower() == "y")
FirstClass(ref seats);
else
Console.WriteLine("The next flight is in three hours!. Good Bye");
}
}
public static void Reservation()
{
do
{
Console.WriteLine("Enter 1 to fly First Class");
Console.WriteLine("Enter 2 to fly Economy Class");
if (Convert.ToInt32(Console.ReadLine()) == 1)
FirstClass(ref seats);
else
Economy(ref seats);
} while (true);
}
}
}
Bear in mind that I would prefer a completely different way of solving the problem, instead of fixing this one :)
I don't want to solve the entire problem in code since you are learning, but I will show you the major things I saw in your code that is a bug.
Your Economy method was not exiting the loop if it found that a
seat was available. It needed to break.
Your else when you did not find a seat was not checking if all of the seats were taken. Checking if i == 9 will make it so it will only go to FirstClass if there are no more seats, not before.
private static void Economy(ref bool[] seats)
{
for (int i = 5; i < 10; i++)
{ // <---- Added the brackets
if (seats[i] == false)
{
seats[i] = true;
break; // <----- You forgot to break when you reserved a seat.
}
else if (i == 9) // <---- You weren't checking if all seats are taken.
{
Console.WriteLine("Economy class is full. Would you like to fly First Class");
if (Console.ReadLine().ToLower() == "y")
FirstClass(ref seats);
else
Console.WriteLine("The next flight is in three hours!. Good Bye");
}
}
}
I like the way you approach programming and your task and this site!
Therefore I would hate to write out the code for you - all the fun is getting it done by yourself. But since you are stuck let me give you a few hints:
Starting at the bottom, the first thing that comes to mind is that you are always offering both classes even when one or both are full. Here is a function header that could help to break things down even further than you already have done:
public int getFirstVacantSeatIn(int classType)
// returns 1-5 for classType=1, 6-10 for classType=2, -1 if classType is full
You can use this function to make the prompt dynamic like this:
Console.WriteLine( ( getFirstVacantSeatIn(1) >= 0 ?
"Enter 1 to fly First Class") : "First Class is full");
And you can reuse it when you try to assign the new seats..:
Another point is that you offer switching between classes when one is full without checking if the other one actually isn't full, too. I suspect that is the problem you are facing?
So you should check before offering to up- or downgrade.. The above function will help here as well. If you can re-use something, chances are that it was right to create that thing..
The secret is ever so often to break your problem down further and further until it goes away, always using/creating useful names for the sub-problems..
"I must use a one-dimensional array of type bool to represent the seating char of the plane"
"I want a completely fresh way to solve the problem"
"Bear in mind that I would prefer a completely different way of solving the problem, instead of fixing this one"
So be it! Others have given you really good advice already, but here's "fresh" way to do it.
using System;
namespace FunnyConsoleApplication
{
public class Program
{
static void Main(string[] args)
{
Airplane plane = new Airplane();
bool reserve = true;
while (reserve)
{
Console.Clear();
Console.WriteLine("Enter [1] to fly First Class ({0} vacant)", plane.VacantFirstClassSeats());
Console.WriteLine("Enter [2] to fly Economy Class ({0} vacant)", plane.VacantEconomySeats());
string input = Console.ReadLine();
switch (input)
{
case "1":
if (plane.HasFirstClassSeats)
{
plane.ReserveFirstClassSeat();
}
else if (plane.HasEconomySeats)
{
if (IsOk("No vacancy, enter [y] to fly Economy instead?"))
plane.ReserveEconomySeat();
else
reserve = false;
}
else
{
reserve = false;
}
break;
case "2":
if (plane.HasEconomySeats)
{
plane.ReserveEconomySeat();
}
else if (plane.HasFirstClassSeats)
{
if (IsOk("No vacancy, enter [y] to fly First Class instead?"))
plane.ReserveFirstClassSeat();
else
reserve = false;
}
else
{
reserve = false;
}
break;
}
Console.WriteLine();
}
Console.WriteLine("No can do, good bye!");
Console.ReadLine();
}
private static bool IsOk(string question)
{
Console.WriteLine(question);
return string.Compare(Console.ReadLine(), "y", StringComparison.OrdinalIgnoreCase) == 0;
}
}
public class Airplane
{
private readonly bool[] _seats = new bool[10];
public bool HasFirstClassSeats
{
get { return HasSeats(0); }
}
public bool HasEconomySeats
{
get { return HasSeats(5); }
}
public int VacantFirstClassSeats()
{
return GetVacant(0);
}
public int VacantEconomySeats()
{
return GetVacant(5);
}
public void ReserveFirstClassSeat()
{
Reserve(0);
}
public void ReserveEconomySeat()
{
Reserve(5);
}
private bool HasSeats(int index)
{
for (int i = index; i < index + 5; i++)
{
if (!_seats[i])
return true;
}
return false;
}
private int GetVacant(int index)
{
int count = 0;
for (int i = index; i < index + 5; i++)
{
if (!_seats[i])
count++;
}
return count;
}
private void Reserve(int index)
{
for (int i = index; i < index + 5; i++)
{
if (!_seats[i])
{
_seats[i] = true;
break;
}
}
}
}
}
Which gives you