Preventing duplicate numbers and asking for user to reenter - c#

Everything I have runs fine, but I am looking for a way to prompt the user if duplicate order number is entered and have them reenter a new order number. Right now it just accepts duplicates and does not display the error message I wanted. I created two classes Order the base, and ShippedOrder. Here is the equals method I have within the Order class.
public override bool Equals(Object e)
{
bool equal;
Order temp = (Order)e;
if (orderNumber == temp.orderNumber)
equal = true;
else
equal = false;
return equal;
Here is what I have within the main method. I can post everything if it would help. Again I am looking for help finding a way to prevent the user form imputing the same two order numbers.
static void Main(string[] args)
{
double sum = 0;
ShippedOrder[] orderArray = new ShippedOrder[5];
ShippedOrder[] check = new ShippedOrder[5];
bool wrong = true;
for (int x = 0; x < orderArray.Length; ++x)
{
orderArray[x] = new ShippedOrder();
Console.Write("Enter order number: ");
orderArray[x].orderNumber = Convert.ToInt32(Console.ReadLine());
for (int y = 0; y < x; ++y)
{
check[y] = new ShippedOrder();
if (orderArray[x].Equals(check[y]))
wrong = false;
while (!wrong)
{
Console.WriteLine("Sorry, the order number {0} is a duplicate. \nPlease reenter {1}",
orderArray[x], check[y]);
for (y = 0; y < x; ++y)
{
if (orderArray[x].Equals(check[y]))
wrong = false;
}
check[y] = orderArray[x];
}
}
Console.Write("Enter cusomer name: ");
orderArray[x].customerName = Console.ReadLine();
Console.Write("Enter quanity: ");
orderArray[x].quanityOrdered = Convert.ToInt32(Console.ReadLine());

I would do this with LINQ, this is where it actually shines (if this code is not called thousand times per second)
var arrayExpectedCount = 5;
var orderArray = new List<ShippedOrder>(); //define array of orders to generate
var check = new List<ShippedOrder>(); //array of orders already shipped,already present
......
//infinit interation
while(true) {
var orderNumber = Convert.ToInt32(Console.ReadLine());
if(!check.Exist(o=>o.orderNumber == orderNumber)
{
//create a new order and push it to the orderArray
}
//break condition of the infinit loop
if(orderArray.Count == arrayExpectedCount)
break;
}
If this is not what you're asking for, please clarify.

List<ShippedOrder> orderArray = new List<ShippedOrder>();
do {
int newOrderNum = 0;
// Retrieve first attempt
Console.Write("Enter order number: ");
newOrderNUm = Conver.ToInt32(ConsoleReadLine());
// Check if any of the orders in orderArray have the same order number
while(orderArray.Any(a=>a.orderNumber == newOrderNum) {
Console.Write("Sorry, the order number is a duplicate. Please enter re-enter the order number: ");
newOrderNum = Conver.ToInt32(ConsoleReadLine());
};
orderArray.Add(new ShippedOrder() {
orderNumber = newOrderNum,
};
} while(orderArray.Length < 5);

Related

How to find a way of output the number of attempts for each question of the quiz?

I am making the quiz application on C# in Console version. I have almost done all things, but I don't know how to show the number of attempts for each question, after when the quiz is finished. If you know something, let me know.
I can not add more lines of the code, as the website doesn't allow to do it
if (keys[index] == answer) // Answer is correct
{
Console.WriteLine();
Console.WriteLine("Congratulations. That's correct!");
Console.WriteLine();
totalScore += markPerQuestion;
index++;
Console.WriteLine("The total score is: {0}", totalScore);
Console.WriteLine("Used attempt(s): {0}", attempt);
attempt = 1;
count = attempt;
markPerQuestion = 20;
}
else // Answer is incorrect
{
attempt++;
count++;
if (attempt <= 3)
{
markPerQuestion /= 2;
}
else if (attempt > 3 && attempt < 5) // The fourth attempt gives zero points
{
markPerQuestion = 0;
totalScore += markPerQuestion;
}
else if(attempt >= 5) // Move to the next question
{
Console.WriteLine("Sorry, you used all attempts for that question. Moving to the next question");
index++;
markPerQuestion = 20;
attempt = 1;
count = attempt;
continue;
}
Console.WriteLine("Oops, try again");
}
if ((index > keys.Length - 1 && index > questions.Length - 1)) // Questions and answer keys are finished
{
for (int i = 0; i < questions.Length; i++)
{
Console.WriteLine("Question {0} was answered after {1} attempt(s)", (i + 1), count);
}
break;
}
Consider this solution:
Create a public class that will allow you to store the results.
public class QuizMark
{
public int Attempts;
public int Mark;
}
For the Console app create a method to control the Quiz. Call the method Quiz() from the Main method.
private const int MAX_ATTEMPTS = 5;
private static void Quiz()
{
var quizResults = new List<QuizMark>();
var questionAnswers = new List<int>() { 1, 3, 5, 2, 3, 6 };
foreach(var a in questionAnswers)
{
var v = QuizQuestion(a);
quizResults.Add(v);
}
int i = 0;
quizResults.ForEach(e => Console.WriteLine($"Question: {++i} Attempts: {e.Attempts} Mark: {e.Mark}"));
var total = quizResults.Sum(s => s.Mark);
Console.WriteLine($"Total Points: {total}");
}
Notice the List collection that stores an object of the class QuizMark. This is where the results of each question are stored: attempts and points.
The List questionAnswers simply contains the expected answer to each of the questions.
Now create the method that is going to control how each question in the quiz will be handled:
private static QuizMark QuizQuestion(int answer)
{
var quizMark = new QuizMark();
int guess = 0; //Store ReadLine in this variable
int mark = 20;
for (int attempt = 1; attempt < MAX_ATTEMPTS + 1; attempt++)
{
guess++; //remove when adding Console.ReadLine
if (guess.Equals(answer))
{
quizMark.Attempts = attempt;
quizMark.Mark = mark;
break;
}
else
{
mark = attempt <= 3 ? mark/2 : 0;
quizMark.Attempts = attempt;
quizMark.Mark = mark;
}
}
return quizMark;
}
You will need to replace the incrementor guess++ with the actual guess the user makes. This code is designed to go though automatically just as a demonstration.
IMPORTANT NOTE:
You will want to do some error handling any time you allow users to enter data. They might enter non-integer values. Probably using a loop around a Console.ReadLine where you check the value of the input with a Int32.TryParse().

Passing a value to a class keeps returning 0

this might be a simple/dumb question but I'm trying to figure out why my code keeps returning 0. I don't think my syntax for passing the value is correct but I cant figure out the proper way of doing it.
class ICESMARK
{
static int ICECount = 0;
public double average = 0;
public double[] ICES = new double[8];
public ICESMARK(double Mark)
{
Mark = ICES[ICECount];
if (ICECount == (ICES.Length - 1))
{
for (int x = 0; x < ICES.Length; x++)
{
average += ICES[x];
}
average /= ICES.Length;
}
ICECount++;
}
}
class Program
{
static void Main(string[] args)
{
ICESMARK[] ICE = new ICESMARK[8];
//LABSMARK[] LAB = new LABSMARK[6];
double userInput;
for (int counter = 0; counter < ICE.Length ; counter++)
{
Console.Write("Please enter your mark for ICE{0}: ", counter + 1 );
bool ifInt = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = new ICESMARK(userInput);
}
Console.WriteLine(ICE[1].average);
Console.ReadLine();
}
}
ICE[1].average - Displays 0
Also if anyone has a more efficient way of doing this, feel free to let me know. Except for the average, is gotta be a calculation, cant use the built in method.
Simplest code to get your work done:
void Main()
{
double[] ICE = new double[8];
double userInput = 0.0;
for (int counter = 0; counter < ICE.Length; counter++)
{
Console.WriteLine($"Please enter your mark for ICE {counter}: ");
bool isNumerical = false;
while(!isNumerical)
isNumerical = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = userInput;
}
Console.WriteLine("Average : " + ICE.Average());
Console.ReadLine();
}
How it works:
Removed all the frills, you don't need an extra class just for this purpose
Made it mandatory for code to enter valid double value to fill all the slots
Finally used Linq Average to calculate Average value
I want to clarify that yes there are easier ways to solve this, but the entire point of the project was to use a class and it specifically says I cant use built in methods such as "array.average".
Sorry that my code was super messy, I was honestly all over the place and very confused. Having that said I finally arrived to this solution. Thanks to everyone who tried to help! really appreciate it, some tips here were very helpful in solving and cleaning up my code.
class ICESMARK
{
public static int ICECount = 0;
public static double average = 0;
public ICESMARK(double Mark)
{
average += Mark;
if (ICECount < 8) { ICECount++; }
if (ICECount == 8) { average /= ICECount;}
}
}
class Program
{
static void Main(string[] args)
{
ICESMARK[] ICE = new ICESMARK[8];
double userInput;
for (int counter = 0; counter < ICE.Length ; counter++)
{
Console.Write("Please enter your mark for ICE{0}: ", counter + 1 );
bool ifInt = double.TryParse(Console.ReadLine(), out userInput);
ICE[counter] = new ICESMARK(userInput);
Console.WriteLine(ICESMARK.ICECount);
}
Console.WriteLine(ICESMARK.average);
Console.WriteLine(ICESMARK.ICECount);
Console.ReadLine();
}
}

Noob needing help on breaking out of loop

I'm very sorry this is such an easy question, I'm just starting out. I've created code that allows a user to enter a number of random dice rolls, and outputs the sum of those rolls. I've now been asked to create a loop that repeats these steps, including the prompt, until the user types 'quit'. My issue is that my code converts the string to an integer, so typing anything kills the code. Any tips of how to insert the loop and break? My code is:
static void Main(string[] args)
{
Random random = new Random();
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
int numberDice = Convert.ToInt32(numberDiceString);
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.ReadKey();
}
I wouldn't use a "while(true)" statement. As someone pointed out in the comments i would prefer using the right condition in there.
That being said i would do it this way:
static void Main(string[] args)
{
Random random = new Random();
string numberDiceString;
int numberDice;
Console.WriteLine("Enter a number of dice to roll:");
while ((numberDiceString = Console.ReadLine()) != "quit")
{
bool parsed = int.TryParse(numberDiceString, out numberDice);
if (!parsed)
{
//Handle the error. The user input was not a number or "quit" word
break;
}
int total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
Console.WriteLine(total);
Console.WriteLine("Enter a number of dice to roll:");
}
}
I have to say that i prefer this way because you can easily see when the loop will stop. Also i added an error handling that you should be doing (What happen if the user enters any words that are not numbers?).
Hope this helps.
This change should be fairly simple. What you need to do is to create a while loop, and then a check before you actually parse for an int. The psuedocode for this would be something like.
while(true) {
//Ask for input
//Check if it equals "quit"
//If so -> break;
//If not convert to int
//For Loop for dice rolls
//Print Total
}
I'm sure it could be a little more elegant than this, and you would want to put some more checks to make sure that invalid input doesn't crash the program, but it should get the job done.
This is a very simple solution that shows how to parse the user input.
using System;
namespace Simpleton
{
class Program
{
static public int GetChoice()
{
int choice = 0;
while (true)
{
Console.Write("Enter number of rolls or \"quit\" to finish: ");
var answer = Console.ReadLine();
if (String.Compare(answer, "quit", true) == 0)
{
return 0; // Done
}
if (Int32.TryParse(answer, out choice))
{
return choice;
}
}
}
static void Main(string[] args)
{
var choice = 0;
while ((choice = GetChoice()) > 0)
{
Console.WriteLine($"You'll be looping {choice} times.");
for (int tries = 0; tries < choice; tries++)
{
// Looping
}
}
}
}
}
Try this code:
static void Main(string[] args)
{
Random random = new Random();
while(true)
{
String numberDiceString = "";
int numberDice = 0;
Console.WriteLine("Enter a number of dice to roll:");
numberDiceString = Console.ReadLine();
if (numberDiceString == "quit") { return; }
int total = 0;
if (Int32.TryParse(numberDiceString, out numberDice))
{
total = 0;
for (int index = 0; index < numberDice; index++)
{
int DieRoll = random.Next(6) + 1;
total += DieRoll;
}
}
Console.WriteLine(total);
}
}
I'm not a C# programmer, but you can test for "quit" explicitly and use a goto
BeginLoop:
Console.WriteLine("Enter a number of dice to roll:");
string numberDiceString = Console.ReadLine();
if (numberDiceString == "quit")
{
goto EndLoop;
}
int numberDice = Convert.ToInt32(numberDiceString);
/* Rest of code you want to do per iteration */
goto BeginLoop;
EndLoop:

How do I find a value in an array in the specific situation?

I am creating an array that stores a name and a bowling score from the same line and then using Split() to split the name and score into two separate arrays. Then I need to find the highest score along with the name with the highest score and write it to the console using a method somehow.
Here is what i have so far. Thanks.
const int SIZE = 10;
string[] arrayNames = new string[SIZE];
int[] arrayScores = new int[SIZE];
for (int i = 0; i < SIZE; i++){
Write("Enter the name and score of a player on one line seperated by a space or press Enter to stop ");
string input = ReadLine();
if (input == ""){
break;
}
string[] scoreInfo = input.Split();
arrayNames[i] = scoreInfo[0];
bool valid = false;
do{
if (input == ""){
break;
}
valid = int.TryParse(scoreInfo[1], out arrayScores[i]);
valid = valid && (arrayScores[i] <= 300);
} while (!valid);
}
int max = bowling.CalcHighest(arrayScores);
int min = bowling.CalcLowest(arrayScores);
int average = bowling.CalcAverage(arrayScores);
Your problem is that you aren't maintaining a reference between the name and the score.
When you read in a line you are separating the values into arrayNames[i] and arrayScores[i].
Consider using a Dictionary maybe instead of two separate arrays.
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add(name, score);
Then do your calculations using the dictionary as a parameter rather than the array. If you're using System.Linq you can do all the calculations on the dictionary real easy:
var orderedDict = dict.OrderByDescending(d => d.Value); //This orders the dictionary by the scor
var first = orderedDict.First(); //This gets the highest score
var last = orderedDict.Last(); //This gets the lowest score
var average = dict.Sum(s => s.Value)/dict.Count(); //This is the average
var firstName = first.Key; //Name of winner
var lastName = last.Key; //Name of loser
In your for loop, you already have the highest score, you just need to keep track of it. arrayScores[i]
Here's what I'd do:
const int SIZE = 10;
string[] arrayNames = new string[SIZE];
int[] arrayScores = new int[SIZE];
int highScore = 0;
string winner = "";
for (int i = 0; i < SIZE; i++){
Write("Enter the name and score of a player on one line seperated by a space or press Enter to stop ");
string input = ReadLine();
if (input == ""){
break;
}
string[] scoreInfo = input.Split();
arrayNames[i] = scoreInfo[0];
bool valid = false;
do{
if (input == ""){
break;
}
valid = int.TryParse(scoreInfo[1], out arrayScores[i]);
valid = valid && (arrayScores[i] <= 300);
if(valid && arrayScores[i] > highScore){
highScore = arrayScores[i];
winner = arrayNames[i];
}
} while (!valid);
}
Then just grab the winner and highScore after the completion of the for loop.

Use looped array to take in string inputs

I am looking to find a way to take assign the value of user inputs to the variables I have, but to use a loop to take this entry and position it on the screen. Is there a way to do this?
Below is my non-working code but hopefully it should provide an idea of what I am trying to achieve.
public void StudentDetailInput()
{
const int startpoint = 2;
string[] takeinput = new string[] {FirstName, Surname, MiddleName, StudentId, Subject, AddressLine1, AddressLine2, Town, Postcode, Telephone, Email };
for (int x = 0; x < takeinput.Length; x++)
{
Console.SetCursorPosition(30, startpoint + x);
[x] = Console.ReadLine();
}
}
You might want to use a Dictionary:
private Dictionary<string, string> _answers = new Dictionary<string, string>();
public void StudentDetailInput()
{
string[] takeinput = new string[] {
"FirstName",
"Surname",
"MiddleName",
"StudentId",
"Subject",
"AddressLine1",
"AddressLine2",
"Town",
"Postcode",
"Telephone",
"Email"
};
_answers.Clear();
for (int x = 0; x < takeinput.Length; x++)
{
Console.Write(takeinput[x] + ": ");
var answer = Console.ReadLine();
_answers.Add(takeinput[x], answer);
}
}
So you can display the answers like this:
for(var i = 0; i < _answers.Count; i++)
{
Console.WriteLine("{0}: {1}", _answers.Keys[i], _answers.Values[i]);
}
If your concern is that you do not want to use this many lines on the console you could keep track of the length of the answers and try to put the cursor right behind the answers so far. The problem with this is that you'll need to take the screen's width (which can be adjusted by the user) into account to calculate the correct line and position.
Another issue with this construction will be that users will expect the cursor to go one line down (that is what enter does) so the user experience might suffer.
An alternative would be to clear the screen after each input, display all answers so far starting at line 2 of the console and positioning the next question on line one:
for (int x = 0; x < takeinput.Length; x++)
{
Console.Clear();
for(y = 0; y < x; y++)
{
Console.SetCursorPosition(0, y + 1);
Console.WriteLine("{0}: {1}", _answers.Keys[y], _answers.Values[y]);
}
Console.SetCursorPosition(0, 0);
Console.Write(takeinput[x] + ": ");
var answer = Console.ReadLine();
_answers.Add(takeinput[x], answer);
}
This might go horribly wrong when the number of questions is more than the number of lines on the console.
Your string array definition is not clear, but I think you are looking for something like this:
public void StudentDetailInput()
{
const int startpoint = 2;
string[] takeinput = new string[11];
for (int x = 0; x < takeinput.Length; x++)
{
Console.SetCursorPosition(30, startpoint + x);
takeinput[x] = Console.ReadLine();
}
}
Now
// FirstName = takeinput[0]
// Surname = takeinput[1]
// ...
This line is wrong.
[x] = Console.ReadLine();
If you want to assign to your elements of array, what you read with ReadLine() method, you should use
takeinput[x] = Console.ReadLine();
If you just want to assign the counter what you read, you should use;
x = Convert.Int32(Console.ReadLine());
EDIT: If I understand your question clearly, you just want to this;
List<string> list = new List<string>();
string input = "";
do
{
input = Console.ReadLine();
list.Add(input);
}
while (input != "exit");
list.Remove("exit");
foreach (var item in list)
{
Console.WriteLine(item);
}

Categories