Alternative to goto statement - c#

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();
}

Related

Made a guessing game, but I think my code is weirdly put

The code works perfectly, but I am not sure if this is good practice or not. I think it could be improved and made easier, but I don't know how. Maybe I could have used more variables to make it simpler. Or is it fine as long as it works? I also need to work on tidying my code up.
using System;
namespace Lesson_number_16_Building_a_guessing_game
{
class Program
{
static void Main(string[] args)
{
string secretWord = "monkey";
string guess = "";
int count = 3;
Console.WriteLine("Please type an animal name that starts with the letter M, you have 3 guesses: ");
guess = Console.ReadLine();
if (guess == secretWord)
{
Console.WriteLine("Nice, you got it right.");
} else if (guess != secretWord)
{
while (guess != secretWord && count > 1)
{
count--;
Console.WriteLine("Nope, try again! you have " + count + " guesses left");
guess = Console.ReadLine();
if (guess == secretWord)
{
Console.WriteLine("Nice, you got it right.");
} else if (count == 1)
{
Console.WriteLine("You have failed to guess it. It was " + secretWord);
break;
}
}
}
}
}
}
1.Instead of initializing the string guess="", you can always prefer string guess=string.Empty.
2.Try to align the curly braces using keys like Ctrl + K.(It depends on Visual Studio version).
Here's a couple of things I would change:
Get rid of the magic number '1' breaking out of the loop. Declare it
as a const with a meaningful name.
since you're breaking out of the while loop within the while loop when validating the retrycount, there is no point to put the
condition in the while loop as well.
Combine the initial question within the loop as well and break out of the loop when correct.
Combine counter substraction and lowerbound check in one call.
Use the equals method for string comparison with the right culture.
using System;
namespace Lesson_number_16_Building_a_guessing_game
{
internal class Program
{
private static void Main(string[] args)
{
const string secretWord = "monkey";
int count = 3;
const int lowerGuessBound = 0;
Console.WriteLine("Please type an animal name that starts with the letter M, you have 3 guesses: ");
while (true)
{
if (Console.ReadLine().Equals(secretWord, StringComparison.CurrentCulture))
{
Console.WriteLine("Nice, you got it right.");
break;
}
else if (--count == lowerGuessBound)
{
Console.WriteLine($"You have failed to guess it. It was {secretWord}");
break;
}
Console.WriteLine($"Nope, try again! you have {count} guesses left");
}
}
}
}
I think that you can shorten and tidy-up your code to something like:
const string secretWord = "monkey";
string guess = "";
const int count = 3;
Console.WriteLine($"Please type an animal name that starts with the letter M, you have {count} guesses: ");
while(count>0)
{
guess = Console.ReadLine();
count--;
if(guess != secretWord )
{
Console.WriteLine($"Nope, try again! you have {count} guesses left");
}
else
{
count=0;
}
}
if(guess != secretWord )
{
Console.WriteLine($"You have failed to guess it. It was {secretWord}");
}
else
{
Console.WriteLine("Nice, you got it right.");}
}
Using const declaration helps to protect against a code error that changes a value that shouldn't. It can also be used on variable input for functions/methods.
I try not to use == where possible as its easy to type = by mistake.
The string interpolation character $ makes for easier understanding of strings that include parameter values when reading code.

Trouble with integrating loop within my program

I am fairly new to OO programming, I have created a simple "Guess the number" game, it functions correctly. However, when attempting to implement a loop errors occur. More specifically, I want the user to restart the program through a console [not compiling and running the game again].
I need help with the static void ExitGame() method. At this moment in time, I am working on "RepL.it" and the generated errors are as followed:
main.cs (10,10): warning CS0649: Field GuessTheNumber.Game.replay' is never assigned to, and will always have its default valuenull'
Compilation succeeded - 1 warning (s)
Welcome to the guessing game. Please press enter.
using System;
namespace GuessTheNumber
{
class Game
{
static int UserGuess;
static int Answer;
string replay;
static string EndProg = "No";
static void Main (string[] args)
{
Console.Title = "Guess the number.";
EntryMessage();
GenerateRandom();
while (EndProg == "No") {
askData();
}
}
static void EntryMessage()
{
Console.WriteLine("Welcome to the guessing game. Please press enter.");
Console.ReadLine();
}
public static void askData()
{
while (EndProg == "No")
{
Console.WriteLine(Answer);
Console.WriteLine("Guess a number between 1 and 100.");
UserGuess = Convert.ToInt32(Console.ReadLine());
WinLose();
}
askData();
}
public void askData(bool endProg)
{
Console.WriteLine("Does you want to play again");
if (replay == "y")//; Remove this semicolon
{
Console.WriteLine("\nOkay, guess again");
askData(EndProg == "No");
}
else if (replay == "n")//; Remove this semicolon
{
askData(EndProg == "Yes");
}
else
{
Console.ReadLine();
}
}
static void GenerateRandom()
{
Random random = new Random();
Answer = random.Next(0,101);
}
static void WinLose()
{
if (UserGuess == Answer)
{
Console.WriteLine("Correct number!");
EndProg="Yes";
}
else if (UserGuess > Answer)
{
Console.WriteLine("Too high.");
EndProg="No";
}
else if (UserGuess < Answer)
{
Console.WriteLine("Too Low.");
EndProg="No";
}
else
{
Console.WriteLine("Invalid answer.");
EndProg="No";
}
}
}
}
There's a number of syntactical errors in your code:
If statement parentheses shouldn't be suffixed with a semicolon
else if (replay == "n");
should be
else if (replay == "n")
Your askData() method is sometimes being called with a bool argument but doesn't take one
void askData()
should be
void askData(bool endProg)
You are mixing and matching static and non-static methods and need to decide whether to implement this logic in a static or instance context
I believe the culprit here is the semicolons you have after your if/else statements:
static void ExitGame()
{
Console.WriteLine("Does you want to play again");
if (replay == "y")//; Remove this semicolon
{
Console.WriteLine("\nOkay, guess again");
askData(EndProg == "No");
}
else if (replay == "n")//; Remove this semicolon
{
askData(EndProg == "Yes");
}
else
{
Console.ReadLine();
}
}
Those semicolons are terminating the statement, which would then make the Else If/Else blocks not follow an IF block, which is syntactically invalid.
This also explains the empty statement warnings the compiler is generating.

Beginner C# Good Practices

I'm just beginning in c# and I made a little program here. I'm just wondering if goto is a valid way of returning to certain sections of my code or if there is a more appropriate and practical way of doing it.
namespace Section5Tests
{
class Program
{
static void Main(string[] args)
{
Start:
var number = new Random().Next(1, 10);
int secret = number;
Console.WriteLine("Secret Number is between 1 and 10. ");
for (var i = 0; i < 10; i++)
{
Console.WriteLine("Guess the secret number you only have 3 attempts!");
Middle:
var guess = Convert.ToInt32(Console.ReadLine());
if (guess == secret)
{
Console.WriteLine("WoW! You got it! Well done!");
goto Playagain;
}
else
{
Console.WriteLine("Incorrect! Try again");
goto Middle;
}
}
Console.WriteLine("Sorry you lost =(");
Playagain:
Console.WriteLine("Try Again? Y/N");
var answer = Console.ReadLine();
if (answer.ToLower() == "y")
{
goto Start;
}
else
{
Console.WriteLine("Thankyou for playing =)");
}
}
}
}
In C#, a better way of doing things like this would be to refactor the program into individual methods which have unique and descriptive names. This is a much better solution than using goto in 99.9% of cases.
You generally never want all of your code to be in a single main method. Instead, I would refactor the game itself into its own method. Then, in the main loop, you can only check if the user is playing.
static void Main (string[] args)
{
var isPlaying = true;
while (isPlaying)
{
isPlaying = PlayGame();
}
Console.WriteLine("Thankyou for playing =)");
}
That way, you can have the PlayGame method return a bool to specify if the user is still playing. Instead of using goto, you can control the program's flow using check variables and smart coding:
static bool PlayGame ()
{
int number = new Random().Next(1, 10);
var userWon = false;
Console.WriteLine("Secret Number is between 1 and 10. ");
for (var numOfAttempts = 10; numOfAttempts > 0; numOfAttempts--)
{
Console.WriteLine($"Guess the secret number you only have {numOfAttempts} attempts!");
var guess = Convert.ToInt32(Console.ReadLine());
if (guess == number)
{
userWon = true;
break;
}
Console.WriteLine("Incorrect! Try again");
}
if (userWon)
Console.WriteLine("WoW! You got it! Well done!");
else
Console.WriteLine("Sorry you lost =(");
Console.WriteLine("Try Again? Y/N");
var answer = Console.ReadLine();
return answer.ToLower() == "y";
}
If you have to ask, you're not ready for GOTO. Don't use it. Use loops and functions instead.
To get you started, instead of Start:, use this:
string answer = "y";
while (answer = "y")
{
Of course you'll need to close that loop up down near your goto Start; statement, but this looks like coursework so I'll stop here. This should get you going.
wondering if goto is a valid way of returning to certain sections
of my code
No, it never is.
Only jumping forward out of deeply nested loops where a break won't go far enough, is valid. (And even that is frowned upon by many..)
All other uses are way too hard to understand when reading and debugging the code.
Instead write meaningful conditions in your loops! And try to concentrate on what you want to achieve, not how..
Breaking down your goals top down into small and simple chunks of work will help avoid coming even close to think about 'program flow' and helps thinking about 'solving problems' instead.
I wanted to be a bit different from the other answers. So, I have added if else statements inside your if statements to replace the goto() function. It's a bit of a long way of doing it but I hope it is easy enough to understand.
static void Main(string[] args)
{
var number = new Random().Next(1, 10);
int secret = number;
bool playAgain = true;
while (playAgain == true)
{
Console.WriteLine("Secret Number is between 1 and 10. ");
for (var i = 10; i > 0; i--)
{
Console.WriteLine("Guess the secret number you only have " + i + " attempts!");
var guess = Convert.ToInt32(Console.ReadLine());
if (guess == secret)
{
Console.WriteLine("WoW! You got it! Well done!");
Console.WriteLine("Would you like Play Again ? Y/N");
var play = Console.ReadLine();
if (play == "Y")
{
break;
}
else
{
playAgain = false;
break;
}
}
else if(i == 1)
{
Console.WriteLine("Sorry you lost =(");
Console.WriteLine("Try Again? Y/N");
var play = Console.ReadLine();
if (play == "Y")
{
break;
}
else
{
Console.WriteLine("Thankyou for playing =)");
playAgain = false;
}
}
}
}
}

Methods and Loops. Way over my head

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

How to allow user to try again or quit console program in C#?

I have created a game that gives a player 5 chances to play after which I would like to ask the player if they would like to play again or quit. I have seen it done in Python, but I do not know python. My code works perfectly fine, but I would like to add these two additional functions
How can I achieve these functionality in C#?
For reference this is what my code main class code looks like.
namespace NumBaseBall
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("\t\t\t*************************************");
Console.WriteLine("\t\t\t* Let's Have Some Fun *");
Console.WriteLine("\t\t\t* Welcome To The *");
Console.WriteLine("\t\t\t* Number Baseball Game *");
Console.WriteLine("\t\t\t*************************************\n");
GameResults gameresults = new GameResults();
for (int trysCounter = 1; trysCounter <= 5; trysCounter++)
{
gameresults.Strikes = 0;
Random r = new Random();
var myRange = Enumerable.Range(1, 9);
var computerNumbers = myRange.OrderBy(i => r.Next()).Take(3).ToList();
Console.WriteLine("The Game's Three Random Integers Are: (Hidden from user)");
foreach (int integer in computerNumbers)
{
Console.WriteLine("{0}", integer);
}
List<int> playerNumbers = new List<int>();
Console.WriteLine("Please Enter Three Unique Single Digit Integers and Press ENTER after each:");
for (int i = 0; i < 3; i++)
{
Console.Write("");
int number = Convert.ToInt32(Console.ReadLine());
playerNumbers.Add(number);
}
gameresults.StrikesOrBalls(computerNumbers,playerNumbers);
Console.WriteLine("---> Computer's Numbers = {0}{1}{2}", computerNumbers[0], computerNumbers[1], computerNumbers[2]);
Console.WriteLine("---> Player's Numbers = {0}{1}{2}", playerNumbers[0], playerNumbers[1], playerNumbers[2]);
Console.WriteLine("---> Game Results = {0} STRIKES & {1} BALLS\n", gameresults.Strikes, gameresults.Balls);
Console.WriteLine("You have played this games {0} times\n", trysCounter);
gameresults.TotalStrikes = gameresults.TotalStrikes + gameresults.Strikes;
Console.WriteLine("STRIKES = {0} ", gameresults.TotalStrikes);
if (gameresults.TotalStrikes >= 3)
{
gameresults.Wins++;
Console.WriteLine("YOU ARE A WINNER!!!");
break;
}
}
if (gameresults.TotalStrikes <3)
Console.WriteLine("YOU LOSE :( PLEASE TRY AGAIN!");
}
}
}
Insert your code inside an loop which checks if the user wants to continue:
while(true) // Continue the game untill the user does want to anymore...
{
// Your original code or routine.
while(true) // Continue asking until a correct answer is given.
{
Console.Write("Do you want to play again [Y/N]?");
string answer = Console.ReadLine().ToUpper();
if (answer == "Y")
break; // Exit the inner while-loop and continue in the outer while loop.
if (answer == "N")
return; // Exit the Main-method.
}
}
But perhaps it would be better to split one big routine up into seperate routines.
Lets rename your Main-method to PlayTheGame.
Split up my routines into:
static public bool PlayAgain()
{
while(true) // Continue asking until a correct answer is given.
{
Console.Write("Do you want to play again [Y/N]?");
string answer = Console.ReadLine().ToUpper();
if (answer == "Y")
return true;
if (answer == "N")
return false;
}
}
And now the Main-method can be:
static void Main(string[] args)
{
do
{
PlayTheGame();
}
while(PlayAgain());
}
You'de have to move some local variables to the class as static fields. Or you could make an instance of a Game class, but I think that is one step to far right now.
There are two ways you could accomplish this:
https://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill%28v=vs.110%29.aspx
System.Diagnostics.Process.GetCurrentProcess().Kill();
Or
https://msdn.microsoft.com/en-us/library/system.environment.exit(v=vs.110).aspx
int exitCode =1;
System.Environment.Exit(exitCode);
Environment.Exit is the preferred way to exit your program since the Kill command "causes an abnormal process termination and should be used only when necessary."[msdn]
First, take the suggestion of moving the code for the actual game playing into a separate function. It will clean things up a lot.
Something like
private static bool PlayGame()
{
// Win branch returns true.
// Loss branch returns false.
}
This then lets you greatly simplify the Main function allowing it to only handle the menu functionality.
For the actual menu functionality, I tend to prefer do/while loops. You have a bit of an extra stipulation that you only ask after 5 plays, but that's easy enough to deal with.
static void Main(string[] args)
{
int playCount = 0;
string answer = "Y";
bool winner;
do
{
if(playCount < 5)
{
playCount++;
}
else
{
do
{
Console.Write("Play again? (Y/N): ");
answer = Console.ReadLine().ToUpper();
} while(answer != "Y" && answer != "N");
}
winner = PlayGame();
} while(!winner && answer == "Y");
Console.WriteLine("Thanks for playing!");
}
You could simplify it a bit by moving the test for 5 games into the if conditional with the use of an increment operator. The only issue is if someone plays your game a billion or so times, things might get weird.
static void Main(string[] args)
{
int playCount = 0;
string answer = "Y";
bool winner;
do
{
if(playCount++ > 3)
{
do
{
Console.Write("Play again? (Y/N): ");
answer = Console.ReadLine().ToUpper();
} while(answer != "Y" && answer != "N");
}
winner = PlayGame();
} while(!winner && answer == "Y");
Console.WriteLine("Thanks for playing!");
}
Edit: Changed things a bit as it looks like in your original code the game ends after the person wins the game.
Per your question in your comment below, you could make a static instance of your GameResults class in your Program class. Your code would end up looking something like the following
class Program
{
private static GameResults results = new GameResults();
public static void Main(string[] args)
{
// Code
}
private static bool PlayGame()
{
// Code
}
}
In PlayGame you would just use the static results object instead of creating a new one every time PlayGame is called.

Categories