I'm new at C# and am having trouble with nested loops. I'm working on a Grading program with a menu. The first menu asks the user how many grades would they like to enter. Then, the user enters the grades. The Second menu figures out the average and grade. I'm having trouble with a nested loop where it would ask you a given number of time to enter grades.
Once that is done, I'm also having trouble with how I would pass that info to the second menu to get the average. I done something like this better in Java, but there we had a set number of grades; then, we made a variable for each grade. Finally we summed them and divided by a set number.
bool exit = false;
do
{
Console.WriteLine("1. Enter Grades");
Console.WriteLine("2. Get Average");
Console.WriteLine("3. My program");
Console.WriteLine("4. exit");
string input = Console.ReadLine();
Console.WriteLine("");
if (input == "1")
{
int totalGrades = 0;
double grades;
double grade, finalGrade = 0;
//User Input
Console.WriteLine("How many grades do you want to enter? ");
//While loop for TryParse
while(!int.TryParse(Console.ReadLine(),out totalGrades))
{
Console.WriteLine("Please enter a valid number");
}
while (totalGrades < 1)
{
Console.WriteLine("Enter Grade: ");
string input = Console.ReadLine();
for (int i = 0; i<= totalGrades; totalGrades++)
Console.WriteLine(totalGrades);
}
Console.ReadLine();
}
else if (input == "2")
{
double average = 0;
if (average >= 90)
{
Console.WriteLine($"The average is a {average} which is an A.");
}
else if (average >= 80)
{
Console.WriteLine($"The average is a {average} which is an B.");
}
else if (average >= 70)
{
Console.WriteLine($"The average is a {average} which is an C.");
}
else if (average >= 60)
{
Console.WriteLine($"The average is a {average} which is an D.");
}
else
{
Console.WriteLine($"The average is a {average} which is an E.");
}
}
else
{
exit = true;
}
}
while (exit == false);
I've changed a few things in order to make the code easier to understand.
private static void Main(string[] args)
{
ProgramLoop();
}
private static void ProgramLoop()
{
var grades = new List<double>();
double average;
var exit = false;
do
{
System.Console.WriteLine("1. Enter Grades");
System.Console.WriteLine("2. Get Average");
System.Console.WriteLine("3. My program");
System.Console.WriteLine("4. exit");
var input = System.Console.ReadLine();
System.Console.WriteLine("");
switch (input)
{
case "1":
grades = EnterGrades();
break;
case "2":
average = GetAverage(grades);
break;
case "3":
MyProgram();
break;
case "4":
exit = true;
break;
default:
System.Console.WriteLine($"'{input}' is not a valid choice.");
break;
}
}
while (exit == false);
}
private static List<double> EnterGrades()
{
int numberOfGrades = 0;
var grades = new List<double>();
System.Console.WriteLine("How many grades do you want to enter? ");
// Read number of grades
while (!int.TryParse(System.Console.ReadLine(), out numberOfGrades) || numberOfGrades < 1)
{
System.Console.WriteLine("Please enter a valid number");
}
while (grades.Count != numberOfGrades)
{
// Read grade
System.Console.WriteLine("Enter Grade: ");
double grade;
while (!double.TryParse(System.Console.ReadLine(), out grade) || grade < 0 || grade > 100)
{
System.Console.WriteLine("Please enter a valid grade between 0.0 and 100.0");
}
grades.Add(grade);
}
return grades;
}
private static double GetAverage(IList<double> grades)
{
var average = grades.Average();
if (average >= 90)
{
System.Console.WriteLine($"The average is {average}, which is an A.");
}
else if (average >= 80)
{
System.Console.WriteLine($"The average is {average}, which is an B.");
}
else if (average >= 70)
{
System.Console.WriteLine($"The average is {average}, which is an C.");
}
else if (average >= 60)
{
System.Console.WriteLine($"The average is {average}, which is an D.");
}
else
{
System.Console.WriteLine($"The average is {average}, which is an E.");
}
return average;
}
I would recommend you to split your code into methods. The code will be easier to understand, and it's a great practice to not cram too much code together.
If you plan on adding more functionality and write more code, I would also recommend you to look into how you can apply object oriented programming to this, i.e. writing classes like a GradeCard.
So there are a couple things I'd like to highlight and I also added notes to the code. You want to keep 2 variables throughout your program/method to keep track of everything entered. They are the 2 pieces of average (1) Total and (2) Count of input numbers. See the code and read it line by line and see the comments. Hope this helps you. Feel free to ask questions if something doesn't make sense.
bool exit = false;
// added variables outside of loop so they are available everywhere in the method
double grades = 0;
int gradesCount = 0;
do
{
Console.WriteLine("1. Enter Grades");
Console.WriteLine("2. Get Average");
Console.WriteLine("3. exit");
string input = Console.ReadLine();
Console.WriteLine("");
if (input == "1")
{
int totalGrades = 0;
//User Input
Console.WriteLine("How many grades do you want to enter? ");
//While loop for TryParse
while (!int.TryParse(Console.ReadLine(), out totalGrades))
{
Console.WriteLine("Please enter a valid number");
}
// increment the count of grades by the number of grades the user wants to add
gradesCount += totalGrades;
// variable to keep a count and avoid infinite loop
int addedGradesCount = 0;
// while loop works like a for loop using our variable to keep count of grades we add
while (addedGradesCount < totalGrades)
{
Console.WriteLine("Enter Grade: ");
// variable to store entered grade
double newGrade = 0;
//Reusing code from while loop above for TryParse
while (!double.TryParse(Console.ReadLine(), out newGrade))
{
Console.WriteLine("Please enter a valid number");
}
// increment running total of grades with the user input number
grades += newGrade;
// output to user - got rid of loop through totalGrades
Console.WriteLine("You entered: " + newGrade + " - Total: " + grades);
// increment variable to keep count! if this is not here, you will have infinite loop
addedGradesCount++;
}
// Console.ReadLine(); // not needed
}
else if (input == "2")
{
// calculate average using the method variables we initialized at the beginning
double average = (grades / gradesCount);
if (average >= 90)
{
Console.WriteLine($"The average is a {average} which is an A.");
}
else if (average >= 80)
{
Console.WriteLine($"The average is a {average} which is an B.");
}
else if (average >= 70)
{
Console.WriteLine($"The average is a {average} which is an C.");
}
else if (average >= 60)
{
Console.WriteLine($"The average is a {average} which is an D.");
}
else
{
Console.WriteLine($"The average is a {average} which is an E.");
}
}
else
{
exit = true;
}
} while (exit == false);
Console.ReadKey();
this seems to work
static void Main(string[] args)
{
bool exit = false;
List<float> grades = new List<float>();
do
{
Console.WriteLine("1. Enter Grades");
Console.WriteLine("2. Get Average");
Console.WriteLine("3. My program");
Console.WriteLine("4. exit");
Console.WriteLine("");
string input = Console.ReadLine();
Console.WriteLine("");
if (input == "1")
{
int totalGrades = 0;
//User Input
Console.WriteLine("How many grades do you want to enter? ");
while (true)
{
try
{
totalGrades = Convert.ToInt32(Console.ReadLine());
break;
}
catch (FormatException)
{
Console.WriteLine("This is not a valid number");
continue;
}
}
Console.WriteLine("");
while (totalGrades > 0)
{
while (true)
{
try
{
grades.Add(Convert.ToInt32(Console.ReadLine()));
totalGrades--;
break;
}
catch (FormatException)
{
Console.WriteLine("This is not a valid number");
continue;
}
}
}
Console.WriteLine("");
}
else if (input == "2")
{
double average = grades.Average();
if (average >= 90)
{
Console.WriteLine($"The average is a {average} which is an A.");
}
else if (average >= 80)
{
Console.WriteLine($"The average is a {average} which is an B.");
}
else if (average >= 70)
{
Console.WriteLine($"The average is a {average} which is an C.");
}
else if (average >= 60)
{
Console.WriteLine($"The average is a {average} which is an D.");
}
else
{
Console.WriteLine($"The average is a {average} which is an E.");
}
Console.WriteLine("");
}
else if (input == "4")
{
exit = true;
} else
{
Console.WriteLine("This is not an option");
}
}
while (exit == false);
}
Related
why does my code not calculate an average score when entering "-1" into the console? It comes up at 0. It's a part of a loop exercise, so I'm sure there are faster ways to code this. I want to fix it within my current C# comprehension.
Here's the task
using System;
namespace Challenge_Loops1
{
internal class Program
{
static void Main(string[] args)
{
string individualScore = "0";
int scoreCount = 0;
int totalScore = 0;
int individualScoreIntoInt = 0;
while (individualScore != "-1")
{
Console.WriteLine($"Last number was {individualScoreIntoInt}");
Console.WriteLine("Please enter the next score");
Console.WriteLine($"Current amount of entries: {scoreCount}");
Console.WriteLine("Enter '-1' when you're ready to calculaate the average");
individualScore = Console.ReadLine();
if (individualScore.Equals("-1"))
{
Console.WriteLine("--------------------------------------------");
double averageScore = (double)totalScore / (double)scoreCount;
Console.WriteLine($"The average total score is {averageScore}");
if(int.TryParse(individualScore, out individualScoreIntoInt) && individualScoreIntoInt > 0 && individualScoreIntoInt < 21)
{
totalScore += individualScoreIntoInt;
//longer way: totalScore = individualScoreIntoInt + totalScore;
}
else if(individualScoreIntoInt < 0 || individualScoreIntoInt < 20)
{
Console.WriteLine("Enter a score > 0 and < 21");
continue;
}
else
{
Console.WriteLine("Please only enter numbers");
}
}
scoreCount++; // adding the individualscore entered to the count. writing it here so that it's only
//added to the count if it meets the requirements
}
}
}
}
Order of operations was incorrect:
1st validate if it's -1 or not,
2nd parse value and if it's possible perform below operations, if not drop error.
This was logic issue, rather than code itself.
You had added iteration despite exceptions, you didn't include possibility of 21 etc.
namespace Challenge_Loops1
{
internal class Program
{
static void Main(string[] args)
{
string individualScore = "0";
int scoreCount = 0;
int totalScore = 0;
int individualScoreIntoInt = 0;
while (individualScore != "-1")
{
Console.WriteLine($"Last number was {individualScoreIntoInt}");
Console.WriteLine("Please enter the next score");
Console.WriteLine($"Current amount of entries: {scoreCount}");
Console.WriteLine("Enter '-1' when you're ready to calculaate the average");
individualScore = Console.ReadLine();
if (individualScore.Equals("-1"))
{
Console.WriteLine("--------------------------------------------");
double averageScore = (double)totalScore / (double)scoreCount;
Console.WriteLine($"The average total score is {averageScore}");
}
else if (int.TryParse(individualScore, out individualScoreIntoInt))
{
if(individualScoreIntoInt > 0 && individualScoreIntoInt <= 21)
{
totalScore += individualScoreIntoInt;
scoreCount++;
}
//as mentioned in comment else here would also work, it's unnecessary to add any other validation.
else if (individualScoreIntoInt < 0 || individualScoreIntoInt > 21)
{
Console.WriteLine("Enter a score > 0 and < 21");
}
}
else
{
Console.WriteLine("Please only enter numbers");
}
}
}
}
}
Trying to write a simple set of code that converts from fahrenheit into celsius, and there are three set conditions that determines what happens. Either it's too cold, just right or too hot. For some reason no matter the input, it will only reply and say it is too cold. I can't really figure out why.
Here's the code so far;
{
class Program
{
static int FahrenheitToCelsius(int fahrenheit)
{
int celsius = ((fahrenheit - 32) * 5 / 9);
return celsius;
}
static void Main(string[] args)
{
Console.WriteLine("Please enter the desired temperature: ");
int fahrenheit = Convert.ToInt32(Console.ReadLine());
int celsius = FahrenheitToCelsius(fahrenheit);
while (celsius != 75)
if (celsius < 73)
{
Console.WriteLine("Too cold! Please enter a warmer temperature.");
Console.ReadLine();
}
else if (celsius > 77)
{
Console.WriteLine("Too warm! Please enter a colder temperature.");
Console.ReadLine();
}
else if (celsius == 75)
{
Console.WriteLine("Optimal input! Begin heating up.");
break;
}
else
{
Console.WriteLine("Invalid input! Please input a temperature.");
}
}
}
}
maybe You only getting same message because you haven't change value of celsius
static int FahrenheitToCelsius(int fahrenheit)
{
int celsius = ((fahrenheit - 32) * 5 / 9);
return celsius;
}
static void Main(string[] args)
{
Console.WriteLine("Please enter the desired temperature: ");
int fahrenheit = Convert.ToInt32(Console.ReadLine());
int celsius = FahrenheitToCelsius(fahrenheit);
Console.WriteLine("C = " + celsius);
int i = 0;
while (celsius != 75) {
if (i>0)
{
int x = Convert.ToInt32(Console.ReadLine());
celsius = FahrenheitToCelsius(x);
}
if (celsius < 73)
{
Console.WriteLine("Too cold! Please enter a warmer temperature.");
}
else if (celsius > 77)
{
Console.WriteLine("Too warm! Please enter a colder temperature.");
}
else if (celsius == 75)
{
Console.WriteLine("Optimal input! Begin heating up.");
break;
}
else
{
Console.WriteLine("Invalid input! Please input a temperature.");
}
i++;
}
}
}
First, Fix your conversion. When converting from one unit to an other one should not remove the decimal value.
static double FahrenheitToCelsius(double f) => (f - 32) * 5.0 / 9.0;
Now lets talk about your if/else. In your code
T <= 163 is too cold;
T = 164,165,166,169,170 are all invalid Temperature;
T >= 171 is too hot;
There is not reason to have those invalid right in the middle of the range.
And there is no explanation on Invalid temp so just drop it.
Is there a number that can satisfy multiple of those condition?
x < 73, x > 77, x ==75...
We can safely drop all the else.
if (tempC < 73)
{
Console.WriteLine("Too cold! Please enter a warmer temperature.\n");
}
if (tempC > 77)
{
Console.WriteLine("Too warm! Please enter a colder temperature.\n");
}
if (tempC == 75)
{
Console.WriteLine("Optimal input! Begin heating up.\n");
}
Using a Do/While loop we have :
static void Main(string[] args)
{
double tempC , tempF;
do
{
Console.WriteLine("Please enter the desired temperature: ");
tempF = Convert.ToDouble(Console.ReadLine());
tempC = FahrenheitToCelsius(tempF);
Console.WriteLine($"{tempF,4:F}°F, {tempC,4:F}°C");
if (tempC < 73)
{
Console.WriteLine("Too cold! Please enter a warmer temperature.\n");
}
if (tempC > 77)
{
Console.WriteLine("Too warm! Please enter a colder temperature.\n");
}
if (tempC == 75)
{
Console.WriteLine("Optimal input! Begin heating up.\n");
}
}
while (tempC != 75);
}
Nb renamed the variable from Fahrenheit and Celsius to tempF and tempC.
Temperatur unit find is the while are : C, F, K, R, De, N, Re, Ro.
I'm not sure one can write the name of those without google.
I am writing a C# program that prints "true" if number <= 20 and "false" if number > 20 using a while loop but the program keeps on executing.
I want to break the program if it reaches certain number e.g. number > 26.
The code for the program is:
public static void Main()
{
Console.WriteLine("Please enter a number");
int numnber = Convert.ToInt32(Console.ReadLine());
while (numnber <= 20)
{
Console.WriteLine("True");
Console.ReadLine();
int number1 = numnber++;
while (numnber > 20)
{
Console.WriteLine("False");
Console.ReadLine();
}
}
}
you can just use break; Try this:
Console.WriteLine("Please enter a number");
int numnber = Convert.ToInt32(Console.ReadLine());
while (numnber <= 20)
{
Console.WriteLine("True");
Console.ReadLine();
int number1 = numnber++;
while (numnber > 20)
{
Console.WriteLine("False");
Console.ReadLine();
}
break;
}
But this programming is not good at all because you are breaking loop after all for this simply you can use if else like this..
Console.WriteLine("Please enter a number");
int numnber = Convert.ToInt32(Console.ReadLine());
if(numnber <= 20)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False");
}
According to your description, your major issue should be
the program keeps on executing
However, it's not going to reach 26 as #King King mentioned.
It stuck inside the inner while which should be replaced by if condition.
Lastly, if you have to exec the number check at least one time you can use do while
do
{
if (numnber <= 20)
{
Console.WriteLine("True");
}
else if (numnber > 20)
{
Console.WriteLine("False");
}
numnber++;
Console.WriteLine("number: {0}", numnber);
} while (numnber < 26);
Console.ReadLine();
Thank you all but the solution to the problem would be. The code is as follows:
public static void Main()
{
int number;
do
{
Console.WriteLine("Please enter a number");
number = Convert.ToInt32(Console.ReadLine());
do
{
Console.WriteLine("True value. True value is supplied");
Console.ReadLine();
number++;
while (number >= 21 && number < 27)
{
Console.WriteLine("False value. False value is supplied");
Console.ReadLine();
number++;
}
} while (number <= 20);
} while (number > 27);
}
I'm on my first week of studying C#.
I guess there should be some way to use 1 "While()" condition instead of 2 in the code below. Is there any way to make my code more simple:
/* ask the user to guess a number.
any number between 10 and 20 is the RIGHT choice,
any other number outside of that scope is WRONG. */
int num;
Console.WriteLine("[Q] Quit or make your choice");
string answer = Console.ReadLine();
if (answer == "Q" || answer == "q")
Console.WriteLine();
else
{
num = Convert.ToInt32(answer);
while (num < 10)
{
Console.WriteLine("Wrong, try again");
num = Convert.ToInt32(Console.ReadLine());
}
while (num > 20)
{
Console.WriteLine("Wrong, try again");
num = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Your number is {0} and it's RIGHT", num);
Console.ReadKey();
}
You can use the OR operator to combine both conditions:
/* ask the user to guess a number.
any number between 10 and 20 is the RIGHT choice,
any other number outside of that scope is WRONG. */
int num;
Console.WriteLine("[Q] Quit or make your choice");
string answer = Console.ReadLine();
if (answer == "Q" || answer == "q")
Console.WriteLine();
else
{
num = Convert.ToInt32(answer);
while (num < 10 || num > 20)
{
Console.WriteLine("Wrong, try again");
num = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Your number is {0} and it's RIGHT", num);
Console.ReadKey();
}
I'm designing a BTEC grade calculator, for those that are not in the know; BTEC is a type of qualification done in the UK and has a 'different' point grading system mainly based on coursework. There is a number of units (20) and each unit you can get a pass, merit and distinction on each unit. Each pass, merit and distinction add up to so many points and these points add up to the overall grade.
For example, a score of 120 points would map to a PPP grade, 240 points would map to MMM and so on.
I've written a program based on the following Pseudo Code:
Prompt for student name:
Operator enters student name
Operator enters their grade units one at a time (D, M, P, D etc):
Display Message about final grade:
Your final Grade is:
DMM
Below is my current code but it needs to be changed and fixed. At the moment, I need to enter unit grades as numbers (20, 40). I want to be able to enter the grade letter (D,M,P). How do I change my program so that it can interpret letters and map them to the unit score?
I am also having an issue converting from a final score to a final grade. At the moment, if I enter two unit grades of 80, giving a total score of 160, the grade displayed should be MPP, however it is printing 120. What am I doing wrong?
class Program
{
static void Main(string[] args)
{
int counter;
double score;
while (true)
{
counter = 1;
score = 0.0;
Console.WriteLine("Enter Your Name or type 'exit' to quit): ");
// Naming for exiting
string name = Console.ReadLine();
if (name == "exit")
{
Environment.Exit(0);
}
else
{
int numberOfUnits = 20;
Console.WriteLine("Number of Units: ");
numberOfUnits = int.Parse(Console.ReadLine());
while (counter <= numberOfUnits)
{
Console.WriteLine("Final Grade Score {0}", counter);
score += double.Parse(Console.ReadLine());
counter++;
}
// Add up and print letter grade.
score = (score / (counter - 1));
if (score < 120)
{
Console.WriteLine("Letter Grade: PPP");
}
else if (score < 160)
{
Console.WriteLine("Letter Grade: MPP");
}
else if (score < 200)
{
Console.WriteLine("Letter Grade: MMP");
}
else if (score < 240)
{
Console.WriteLine("Letter Grade: MMM");
}
else if (score < 280)
{
Console.WriteLine("Letter Grade: DMM");
}
else if (score < 320)
{
Console.WriteLine("Letter Grade: DDM");
}
else if (score < 360)
{
Console.WriteLine("Letter Grade: DDD");
}
// After DDD it goes up by 20's ..... D* = 20 not 40...
else if (score < 380)
{
Console.WriteLine("Letter Grade: D*DD");
}
else if (score < 400)
{
Console.WriteLine("Letter Grade: D*D*D");
}
else if (score < 420)
{
Console.WriteLine("Letter Grade: D*D*D*");
}
Console.WriteLine("Grade: {0}", (score).ToString("P"));
}
}
}
}
Here is the code with some small edits, and the switch statement to convert letters into numbers.
public class Program
{
static void Main(string[] args)
{
int counter;
double score;
while (true)
{
counter = 1;
score = 0.0;
Console.WriteLine("Enter Your Name or type 'exit' to quit): ");
// Naming for exiting
string name = Console.ReadLine();
if (name == "exit")
{
return;
}
else
{
int numberOfUnits = 20;
Console.WriteLine("Number of Units: ");
numberOfUnits = int.Parse(Console.ReadLine());
while (counter <= numberOfUnits)
{
Console.WriteLine("Final Grade Score {0}", counter);
string s = Console.ReadLine().ToUpper();
double d;
if (double.TryParse(s, out d)) //parsing as a number was successfull, and the result is in d.
score += d;
else //parsing failed.
{
switch (s)
{
case "D":
score += 20;
break;
case "M":
score += 50;
break;
case "P":
score += 70;
break;
default:
counter--; //parsing of a letter failed. reducing counter that will be later incremented, to offset the effect.
Console.WriteLine("Could not parse your grade. Enter a number or a letter");
break;
}
}
counter++;
}
// Add up and print letter grade.
score = (score / (counter - 1));
if (score < 120) Console.WriteLine("Letter Grade: PPP");
else if (score < 160) Console.WriteLine("Letter Grade: MPP");
else if (score < 200) Console.WriteLine("Letter Grade: MMP");
else if (score < 240) Console.WriteLine("Letter Grade: MMM");
else if (score < 280) Console.WriteLine("Letter Grade: DMM");
else if (score < 320) Console.WriteLine("Letter Grade: DDM");
else if (score < 360) Console.WriteLine("Letter Grade: DDD");
// After DDD it goes up by 20's ..... D* = 20 not 40...
else if (score < 380) Console.WriteLine("Letter Grade: D*DD");
else if (score < 400) Console.WriteLine("Letter Grade: D*D*D");
else if (score < 420) Console.WriteLine("Letter Grade: D*D*D*");
Console.WriteLine("Grade: {0}", (score).ToString("P"));
}
}
}
}
Your code has quite a few issues, too many really for a SO question. As I said in my comments, if you need to convert from an arbitrary string to a number, you could use a series of if statements, or a switch or you could use some kind of mapping. As far as your problem converting back from a score to a grade, my impression is still that the issues is this line:
score = (score / (counter - 1));
It doesn't make sense to divide the score by the number of units. If you got 20 points for each unit, dividing by the number of units would give you a final score of 20... that seems very wrong.
Part of the problem that you have is that you've coded up the whole thing in one function. You really need to look at breaking up your code into logical units. The units will be smaller, easier to understand and easier to test. I would strongly recommend not writing very much at all in your main method. Spin up another, relevant class and leave the work to it. Below are some suggestions of an alternate approach to breaking down your program. It's far from polished, but compare the two and see which is easier to understand.
// Main class. This doesn't do anything but spin up a new class
// and tell it to get all student grades.
class Program
{
static void Main(string[] args)
{
var calculator = new BTECGradeCalculator();
calculator.GetAllStudentGrades();
}
}
The new BTECGradeCalculator consists of several functions. The first thing I did was type in an interpretation of your pseudo code above and a new function:
public void GetAllStudentGrades() {
while (true) {
string studentName = PromptStudentAndGetName();
if (studentName.ToUpper() == "EXIT") {
return;
}
List<string> studentGrades = GetStudentGrades();
int score = CalculateScoreFromGrades(studentGrades);
string finalGrade = CalculateGradeFromScore(score);
PrintFinalStatement(studentName, finalGrade);
}
}
You can see that the function itself is almost entirely made of function calls. Each one with a reasonably descriptive name (very subjective) so that the method almost reads like it is pseudo code.
I then implemented each of these methods. Each one has a specific task, that matches its name. This gives you a much better chance of trying to identify errors. You could also make the methods public / move some of them to other classes and unit test them individually using a testing framework like nunit.
private string PromptStudentAndGetName() {
Console.WriteLine("Enter Your Name or type 'exit' to quit): ");
return Console.ReadLine();
}
private List<string> GetStudentGrades() {
List<string> grades = new List<string>();
Console.WriteLine("Number of Units: ");
int numberOfUnits = GetNumberOfUnits();
for (int counter = 1; counter <= numberOfUnits; ) {
Console.WriteLine("What was your grade for unit {0}", counter);
var grade = Console.ReadLine();
if (IsValidGrade(grade)) {
grades.Add(grade);
counter++;
}
else {
Console.WriteLine("That's not a valid grade!");
}
}
return grades;
}
private int CalculateScoreFromGrades(List<string> studentGrades) {
int score = 0;
foreach (var grade in studentGrades) {
score += GetScoreFromGrade(grade);
}
return score;
}
private string CalculateGradeFromScore(int score) {
if (score < 120) return "PPP";
if (score < 160) return "MPP";
if (score < 200) return "MMP";
if (score < 240) return "MMM";
if (score < 280) return "DMM";
if (score < 320) return "DDM";
if (score < 360) return "DDD";
if (score < 380) return "D*DD";
if (score < 400) return "D*D*D";
if (score < 420) return "D*D*D*";
throw new InvalidOperationException(string.Format("Unexpected score {0}", score));
}
private void PrintFinalStatement(string studentName, string finalGrade) {
// Add up and print letter grade.
Console.WriteLine("Student: {0}", studentName);
Console.WriteLine("Grade: {0}", finalGrade);
}
Notice that some of the methods were again broken down, to call out to other smaller methods in order to keep the code size manageable. These methods are below:
private int GetNumberOfUnits() {
int numberOfUnits;
if (!int.TryParse(Console.ReadLine(), out numberOfUnits)) {
Console.WriteLine("Sorry... I didn't understand that. I'm going to assume you have the expected 20 units.");
numberOfUnits = 20;
}
return numberOfUnits;
}
bool IsValidGrade(string grade) {
string [] validGrades = {"D","M","P"};
return validGrades.Contains(grade.ToUpper());
}
private int GetScoreFromGrade(string grade) {
switch (grade.ToUpper()) {
case "P":
return 20;
case "M":
return 40;
case "D":
return 80;
}
throw new InvalidOperationException(string.Format("Tried to get a score from an invalid grade {0}", grade));
}
Notice also, that some of the above methods throw exceptions when they get into unexpected situations that contain information about the error, such as the unexpected score / grade to help identify the cause of issues. As I've said, this is far from an ideal program, but it does hopefully suggest a direction to take in order to help you diagnose your own issues.