I couldn't think of a good title name, so feel free to change it.
I am making a C# maths console project where the user answers addition, subtraction, multiplication, division, power and square root questions based on the difficulty they choose!
Here is my code:
using System;
using System.Collections.Generic;
namespace mathstester
{
class Program
{
public enum UserDifficulty
{
Easy,
Normal,
Hard
}
public enum MathOperation
{
Addition = 1,
Subtraction = 2,
Multiplication = 3,
Division = 4,
Power = 5,
SquareRoot = 6
}
public static (int operationMin, int operationMax) GetPossibleOperationsByDifficulty(UserDifficulty userDifficulty)
{
switch (userDifficulty)
{
case UserDifficulty.Easy:
return (1, 4);
case UserDifficulty.Normal:
return (1, 5);
case UserDifficulty.Hard:
return (3, 7);
default:
throw new Exception();
}
}
public static (string message, double correctAnswer) GetMathsEquation(MathOperation mathOperation, UserDifficulty userDifficulty)
{
int number1;
int number2;
Random randomNumber = new Random();
switch (mathOperation)
{
case MathOperation.Addition:
number1 = randomNumber.Next(1000);
number2 = randomNumber.Next(1000);
return ($"{number1} + {number2}", number1 + number2);
case MathOperation.Subtraction:
number1 = randomNumber.Next(1000);
number2 = randomNumber.Next(1000);
return ($"{number1} - {number2}", number1 - number2);
case MathOperation.Multiplication:
number1 = userDifficulty == UserDifficulty.Easy ? randomNumber.Next(13) : randomNumber.Next(1000);
number2 = userDifficulty == UserDifficulty.Easy ? randomNumber.Next(13) : randomNumber.Next(1000);
return ($"{number1} * {number2}", number1 * number2);
case MathOperation.Division:
number1 = randomNumber.Next(10000);
number2 = randomNumber.Next(1000);
return ($"{number1} / {number2}", number1 / (double)number2);
case MathOperation.Power:
number1 = randomNumber.Next(13);
number2 = randomNumber.Next(5);
return ($"{number1} ^ {number2}", Math.Pow(number1, number2));
case MathOperation.SquareRoot:
number1 = randomNumber.Next(1000);
return ($"√{number1}", Math.Sqrt(number1));
default:
throw new Exception();
}
}
public static (int operationQuestion, int operationScore) Score(MathOperation mathOperation)
{
int additionQuestion = 0;
int additionScore = 0;
int subtractionQuestion = 0;
int subtractionScore = 0;
int multiplicationQuestion = 0;
int multiplicationScore = 0;
int divisionQuestion = 0;
int divisionScore = 0;
int powerQuestion = 0;
int powerScore = 0;
int squareRootQuestion = 0;
int squareRootScore = 0;
switch (mathOperation)
{
case MathOperation.Addition:
return (additionQuestion, additionScore);
case MathOperation.Subtraction:
return (subtractionQuestion, subtractionScore);
case MathOperation.Multiplication:
return (multiplicationQuestion, multiplicationScore);
case MathOperation.Division:
return (divisionQuestion, divisionScore);
case MathOperation.Power:
return (powerQuestion, powerScore);
case MathOperation.SquareRoot:
return (squareRootQuestion, squareRootScore);
default:
throw new Exception();
}
}
public static (int, int, int) RunTest(int numberOfQuestionsLeft, UserDifficulty userDifficulty)
{
int totalScore = 0;
Random random = new Random();
var (operationMin, operationMax) = GetPossibleOperationsByDifficulty(userDifficulty);
var (operationQuestion, operationScore) = (0, 0);
while (numberOfQuestionsLeft > 0)
{
int mathRandomOperation = random.Next(operationMin, operationMax);
MathOperation mathOperation = (MathOperation)mathRandomOperation;
(operationQuestion, operationScore) = Score(mathOperation);
var (message, correctAnswer) = GetMathsEquation(mathOperation, userDifficulty);
if (mathRandomOperation == 4 || mathRandomOperation == 6)
{
Console.Write($"To the nearest integer, What is {message} =");
}
else
{
Console.Write($"What is {message} =");
}
double userAnswer = Convert.ToDouble(Console.ReadLine());
if (Math.Round(correctAnswer) == userAnswer)
{
Console.WriteLine("Well Done!");
totalScore++;
operationQuestion++;
operationScore++;
}
else
{
Console.WriteLine("Your answer is incorrect!");
operationQuestion++;
}
numberOfQuestionsLeft--;
}
return (totalScore, operationQuestion, operationScore);
}
public static void Main(string[] args)
{
Dictionary<string, UserDifficulty> dict = new Dictionary<string, UserDifficulty>();
dict.Add("E", UserDifficulty.Easy);
dict.Add("N", UserDifficulty.Normal);
dict.Add("H", UserDifficulty.Hard);
string userInputDifficulty = "";
do
{
Console.WriteLine("What difficulty level would you like to do! Please type E for Easy, N for Normal and H for hard");
userInputDifficulty = Console.ReadLine().ToUpper();
} while (userInputDifficulty != "E" && userInputDifficulty != "N" && userInputDifficulty != "H");
UserDifficulty userDifficulty = dict[userInputDifficulty];
int numberOfQuestions = 0;
do
{
Console.WriteLine("How many questions would you like to answer? Please type a number divisible by 10!");
int.TryParse(Console.ReadLine(), out numberOfQuestions);
} while (numberOfQuestions % 10 != 0);
var (totalScore, operationQuestion, operationScore) = RunTest(numberOfQuestions, userDifficulty);
Console.WriteLine($"You got a score of {totalScore} out of {numberOfQuestions}");
if(userDifficulty == UserDifficulty.Easy)
{
Console.WriteLine($"You got an addittion score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got an addition score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
}
else if (userDifficulty == UserDifficulty.Normal)
{
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
}
else if (userDifficulty == UserDifficulty.Hard)
{
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
Console.WriteLine($"You got a score of {operationScore} out of {operationQuestion}");
}
}
}
}
In my function "Score" I have quite a few variables that I want to use in my function "RunTest".
How do I move the variables without having to write them all again?
Thanks!
As noted by #devNull, Score always returns (0, 0). The function can be re-written as the following:
public static (int operationQuestion, int operationScore) Score(MathOperation mathOperation)
{
switch (mathOperation)
{
case MathOperation.Addition:
case MathOperation.Subtraction:
case MathOperation.Multiplication:
case MathOperation.Division:
case MathOperation.Power:
case MathOperation.SquareRoot:
return (0, 0);
default:
throw new Exception();
}
}
Or if you're sure that you don't need the exception handling for incompatible MathOperator:
// Note: no more parameters as well
public static (int operationQuestion, int operationScore) Score()
{
return (0, 0);
}
This will still have the same functionality in your while loop in RunTest because the variables in Score were locally defined, and are not reference values.
If you're wanting those variables to be returned as well in Score, you can extract them to their own class and return an instance of it.
For example:
public class QuestionScoreModel
{
public int AdditionQuestion {get;set;}
public int AdditionScore {get;set;}
public int SubtractionQuestion {get;set;}
public int SubtractionScore {get;set;}
public int MultiplicationQuestion {get;set;}
public int MultiplicationScore {get;set;}
public int DivisionQuestion {get;set;}
public int DivisionScore {get;set;}
public int PowerQuestion {get;set;}
public int PowerScore {get;set;}
public int SquareRootQuestion {get;set;}
public int SquareRootScore {get;set;}
}
And score can be like so:
public static QuestionScoreModel Score()
{
// Initialize it with any values required
return new QuestionScoreModel();
}
Which can be used like:
var scores = Score();
scores.AdditionQuestion++;
Which would help track what type of questions the user got right.
Related
I am learning to use expression trees/expressions in C#. I have gradually built up a parser, with which I can take a string in "calculator" syntax (like "2 * 3 + 14 * 4 / 7 - 5 * 5") and build and evaluate an abstract syntax tree (AST). It even calculates the correct answer! :-) The AST consists of Expression nodes: arithmethical binary nodes (Add, Subtract, Multiply, Divide) and unary Constant nodes representing the integer values.
Next step: I want to add parameters to the expression to be parsed, like "2 * 3 + myVar1 * 4 / 7 - 5 * myVar2", and supply the actual values for the parameters at runtime (after the AST has been compiled). I can easily add the ParameterExpressions to the tree - but I cannot find out how to correctly compile my tree and supply the values.
The parser is built using Coco/R and an attributed Bachus-Naur grammar, and looks like this:
using System.Linq.Expressions;
using Ex = System.Linq.Expressions.Expression;
using System;
namespace AtgKalk
{
public class Parser
{
public const int _EOF = 0;
public const int _identifikator = 1;
public const int _tall = 2;
public const int _pluss = 3;
public const int _minus = 4;
public const int _ganger = 5;
public const int _deler = 6;
public const int maxT = 7;
const bool T = true;
const bool x = false;
const int minErrDist = 2;
public Scanner scanner;
public Errors errors;
public Token t; // last recognized token
public Token la; // lookahead token
int errDist = minErrDist;
public Parser(Scanner scanner)
{
this.scanner = scanner;
errors = new Errors();
}
void SynErr(int n)
{
if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
errDist = 0;
}
void Get()
{
for (; ; )
{
t = la;
la = scanner.Scan();
if (la.kind <= maxT) { ++errDist; break; }
la = t;
}
}
void Expect(int n)
{
if (la.kind == n) Get(); else { SynErr(n); }
}
void Calculator()
{
Ex n;
CalcExpr(out n);
Console.Write($"AST: {n} = ");
Console.WriteLine(Ex.Lambda<Func<int>>(n).Compile()());
// The above works fine as long as there are no parameter names in the input string
}
void CalcExpr(out Ex n1)
{
Ex n2; Func<Ex, Ex, Ex> f;
Term(out n1);
while (la.kind == 3 || la.kind == 4)
{
AddOp(out f);
Term(out n2);
n1 = f(n1, n2);
}
}
void Term(out Ex n1)
{
n1 = null; Ex n2; Func<Ex, Ex, Ex> f = null;
Fact(out n1);
while (la.kind == 5 || la.kind == 6)
{
MulOp(out f);
Fact(out n2);
n1 = f(n1, n2);
}
}
void AddOp(out Func<Ex, Ex, Ex> f)
{
f = null;
if (la.kind == 3)
{
Get();
f = (l, r) => Ex.Add(l, r);
}
else if (la.kind == 4)
{
Get();
f = (l, r) => Ex.Subtract(l, r);
}
else SynErr(8);
}
void Fact(out Ex n)
{
n = null;
if (la.kind == 2)
{
Number(out n);
}
else if (la.kind == 1)
{
Parameter(out n);
}
else SynErr(9);
}
void MulOp(out Func<Ex, Ex, Ex> f)
{
f = null;
if (la.kind == 5)
{
Get();
f = (l, r) => Ex.Multiply(l, r);
}
else if (la.kind == 6)
{
Get();
f = (l, r) => Ex.Divide(l, r);
}
else SynErr(10);
}
void Number(out Ex n)
{
Expect(2);
n = Ex.Constant(int.Parse(t.val), typeof(int));
}
void Parameter(out Ex n)
{
Expect(1);
n = Ex.Parameter(typeof(int), t.val);
}
public void Parse()
{
la = new Token();
la.val = "";
Get();
Calculator();
Expect(0);
}
static readonly bool[,] set = {
{T,x,x,x, x,x,x,x, x}
};
} // end Parser
public class Errors
{
public int count = 0; // number of errors detected
public System.IO.TextWriter errorStream = Console.Out; // error messages go to this stream
public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
public virtual void SynErr(int line, int col, int n)
{
string s;
switch (n)
{
case 0: s = "EOF expected"; break;
case 1: s = "identifikator expected"; break;
case 2: s = "tall expected"; break;
case 3: s = "pluss expected"; break;
case 4: s = "minus expected"; break;
case 5: s = "ganger expected"; break;
case 6: s = "deler expected"; break;
case 7: s = "??? expected"; break;
case 8: s = "invalid AddOp"; break;
case 9: s = "invalid Fakt"; break;
case 10: s = "invalid MulOp"; break;
default: s = "error " + n; break;
}
errorStream.WriteLine(errMsgFormat, line, col, s);
count++;
}
} // Errors
public class FatalError : Exception
{
public FatalError(string m) : base(m) { }
}
}
My problem lies in line 63, I think:
Console.WriteLine(Ex.Lambda<Func<int>>(n).Compile()());
Invocation:
Scanner scanner = new Scanner(args[0]); // if args[0] contains the input string :-)
Parser parser = new Parser(scanner);
parser.Parse();
I have now solved my problem. Thanks to kaby76 for valuable tips leading me in the right direction. The example now can handle an arbitrary number of parameters (probably max 16, since this is the maximum number of input arguments for Func<...>)
The solution to the problem war threefold:
Collect the parameters and supply this collection of parameters to the Lambda
Remove the explicit type arguments from the Lambda, letting it infer types
Use DynamicInvoke to execute the resulting Delegate
The problematic statement then looks like this, for an expression with two parameters:
Console.WriteLine(Ex.Lambda(n, para).Compile().DynamicInvoke(3, 4));
I am making an app that based on the input of one of player1 it creates a new number based on difficulty.
When I input the number, the app asks for number I entered+ more to display and I don't want that. Example:
If I input 4, the app will ask for 4 other inputs.
https://i.stack.imgur.com/PD2zQ.png
I don't want this to happen can anyone explain why and how to fix this?
Here is my main code.
Console.WriteLine($"Can {user[0]} select a level? If not choosen between either 30 seconds or between 1, 2, 3 it will be automatically choosen.");
Level_Select level = new Level_Select(LevelSelect());
static int LevelSelect()
{
int select;
int.TryParse(Console.ReadLine(), out select);
return select;
}
if (LevelSelect() == 1)
{
Console.WriteLine($"{Level_Select.level1()}");
}
else if (LevelSelect() == 2)
{
Console.WriteLine($"{Level_Select.level2()}");
}
else if (LevelSelect() == 3)
{
Console.WriteLine($"{Level_Select.level3()}");
}
else if ((LevelSelect() != 1) || (LevelSelect() != 2) || (LevelSelect() != 3))
{
Console.WriteLine($"{Level_Select.Default()}");
}
And this is my Level Difficulty Class.
class Level_Select
{
private int level;
public Level_Select(int level)
{
this.Level = level;
}
public int Level
{
get { return level; }
set {
if (value == 1)
{
this.level = value;
}
else if (value == 2)
{
this.level = value;
}
else if (value == 3)
{
this.level = value;
}
}
}
public static int Default()
{
int min = 000;
int max = 999;
Random num = new Random();
return num.Next(min, max);
}
public static int level1()
{
int min = 000;
int max = 99999;
Random num = new Random();
return num.Next(min, max);
}
public static int level2()
{
int min = 00000;
int max = 99999999;
Random num = new Random();
return num.Next(min, max);
}
public static int level3()
{
int min = 000000000;
long ten = 9999999999;
int max = (int)ten;
Random num = new Random();
return num.Next(min, max);
}
}
I think your problem is in your if else chain. When you put:
if (LevelSelect() == 1) // POINT A
{
Console.WriteLine($"{Level_Select.level1()}");
}
else if (LevelSelect() == 2) // POINT B
{
Console.WriteLine($"{Level_Select.level2()}");
}
At POINT A, you call LevelSelect(), which prompts for input. If this returns anything but 1, the if fails, meaning you move on to POINT B, which calls LevelSelect() again and so prompts you again, and so on, every time you call LevelSelect().
What you probably want is:
int selectedLevel = LevelSelect(); // Called only once
Level_Select level = new Level_Select(selectedLevel);
if (selectedLevel == 1)
{
Console.WriteLine($"{Level_Select.level1()}");
}
else if (selectedLevel == 2)
{
Console.WriteLine($"{Level_Select.level2()}");
}
else if (selectedLevel == 3)
{
Console.WriteLine($"{Level_Select.level3()}");
}
else // No need to retest; if it's here it's not 1, 2 or 3
{
Console.WriteLine($"{Level_Select.Default()}");
}
Though in fact, a switch is better in these cases:
int selectedLevel = LevelSelect(); // Called only once
Level_Select level = new Level_Select(selectedLevel);
switch (selectedLevel)
{
case 1:
Console.WriteLine($"{Level_Select.level1()}");
break;
case 2:
Console.WriteLine($"{Level_Select.level2()}");
break;
case 3:
Console.WriteLine($"{Level_Select.level2()}");
break;
default:
Console.WriteLine($"{Level_Select.Default()}");
break;
}
You are calling LevelSelect() on each if statement so it's normal that it will make a Console.ReadLine() each time. You should call that method only once:
var selectedLevel = LevelSelect();
var level = new Level_Select(selectedLevel);
if (selectedLevel == 1)
{
//do some stuff
Level_Select.level1();
}
else if (selectedLevel == 2)
{
// do some other stuff
Level_Select.level2();
}
And so on.
I am making a C# maths project where the user answers an addition, subtraction, multiplication, division, power or square root question based on the difficulty level they choose!
I have just started using Enums but I don't know how to put it in my switch statements so the rest of my code works fine.
Here is my code so far:
using System;
namespace mathstester
{
class Program
{
public enum UserDifficulty
{
Easy,
Normal,
Hard
}
public enum MathOperation
{
Addition = 1,
Subtraction = 2,
Multiplication = 3,
Division = 4,
Power = 5,
SquareRoot = 6
}
public static (int operationMin, int operationMax) GetMathOperationForDifferentDifficulties(UserDifficulty userDifficulty)
{
switch (userDifficulty)
{
case UserDifficulty.Easy:
return (1, 4);
case UserDifficulty.Normal:
return (1, 5);
case UserDifficulty.Hard:
return (3, 7);
default:
throw new Exception();
}
}
public static (string message, double correctAnswer) GetMathsEquation(MathOperation mathOperation, UserDifficulty userDifficulty)
{
int number1;
int number2;
Random random = new Random();
switch (mathOperation)
{
case MathOperation.Addition:
number1 = random.Next(1000);
number2 = random.Next(1000);
return ($"{number1} + {number2}", number1 + number2);
case MathOperation.Subtraction:
number1 = random.Next(1000);
number2 = random.Next(1000);
return ($"{number1} - {number2}", number1 - number2);
case MathOperation.Multiplication:
number1 = userDifficulty == UserDifficulty.Easy ? random.Next(13) : random.Next(1000);
number2 = userDifficulty == UserDifficulty.Easy ? random.Next(13) : random.Next(1000);
return ($"{number1} * {number2}", number1 * number2);
case MathOperation.Division:
number1 = random.Next(10000);
number2 = random.Next(1000);
return ($"{number1} / {number2}", number1 / (double)number2);
case MathOperation.Power:
number1 = random.Next(13);
number2 = random.Next(5);
return ($"{number1} ^ {number2}", Math.Pow(number1, number2));
case MathOperation.SquareRoot:
number1 = random.Next(1000);
return ($"√{number1}", Math.Sqrt(number1));
default:
throw new Exception();
}
}
public static int GetResult(int numberOfQuestionsLeft, string userDifficulty)
{
int score = 0;
Random random = new Random();
var (operationMin, operationMax) = GetMathOperationForDifferentDifficulties(userDifficulty);
while (numberOfQuestionsLeft > 0)
{
int mathOperation = random.Next(operationMin, operationMax);
var (message, correctAnswer) = GetMathsEquation(mathOperation, userDifficulty);
if (mathOperation == 4 || mathOperation == 6)
{
Console.Write($"To the nearest integer, What is {message} =");
}
else
{
Console.Write($"What is {message} =");
}
double userAnswer = Convert.ToDouble(Console.ReadLine());
if (Math.Round(correctAnswer) == userAnswer)
{
Console.WriteLine("Well Done!");
score++;
}
else
{
Console.WriteLine("Your answer is incorrect!");
}
numberOfQuestionsLeft--;
}
return score;
}
public static void Main(string[] args)
{
string userDifficulty = "";
do
{
Console.WriteLine("What difficulty level would you like to do! Please type E for Easy, N for Normal and H for hard");
userDifficulty = Console.ReadLine().ToUpper();
} while (userDifficulty != "E" && userDifficulty != "N" && userDifficulty != "H");
int numberOfQuestions = 0;
do
{
Console.WriteLine("How many questions would you like to answer? Please type a number divisible by 10!");
int.TryParse(Console.ReadLine(), out numberOfQuestions);
} while (numberOfQuestions % 10 != 0);
int score = GetResult(numberOfQuestions, userDifficulty);
Console.WriteLine($"You got a score of {score} out of {numberOfQuestions}");
}
}
}
Your issue seems to lie in the selection of difficulties - in your Main() method, you take an input of E, N, or H for difficulty, which is then passed to GetResult() and onwards to GetMathOperationForDifferentDifficulties()
However, as Enums are underpinned by a numeric type in C#, this will fail and throw an exception.
To fix it, you need to convert the E, N, or H to UserDifficulty.Easy, UserDifficulty.Normal, or UserDifficulty.Hard respectively, and then pass them over that way.
Here's how you could modify Main() to do this:
public static void Main(string[] args)
{
string difficultyInput = "";
UserDifficulty userDifficulty = UserDifficulty.Easy // default to start
do
{
Console.WriteLine("What difficulty level would you like to do! Please type E for Easy, N for Normal and H for hard");
difficultyInput = Console.ReadLine().ToUpper();
} while (difficultyInput != "E" && difficultyInput != "N" && difficultyInput != "H");
switch(difficultyInput) {
case "E":
userDifficulty = UserDifficulty.Easy;
break;
case "N":
userDifficulty = UserDifficulty.Normal;
break;
case "H":
userDifficulty = UserDifficulty.Hard;
break;
}
int numberOfQuestions = 0;
do
{
Console.WriteLine("How many questions would you like to answer? Please type a number divisible by 10!");
int.TryParse(Console.ReadLine(), out numberOfQuestions);
} while (numberOfQuestions % 10 != 0);
int score = GetResult(numberOfQuestions, userDifficulty);
Console.WriteLine($"You got a score of {score} out of {numberOfQuestions}");
}
Bear in mind you'd need to alter GetResult() to take a UserDifficulty input instead of a string, too
I am working on a school project and I have spent 5 hours trying to understand how to go about sorting an Array with an object containing four dimensions. What I set out to do was to sort them by productCode or drinkName. When I read assorted threads people tell OP to use LINQ. I am not supposed to use that and, I get more and more confused as what method to use. I am told by the teacher, to use bubble sort(bad algorithm, I know) and I do that all fine on an Array containing one dimension. I resorted to try Array.Sort but then I get System.InvalidOperationException.
I am going insane and I am stuck even though I read multiple threads on the subject. I might be using ToString in the wrong manner. Any nudge would be appreciated.
class soda
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name()
{
return drinkName;
//set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type()
{
return drinkType;
//set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price()
{
return drinkPrice;
//set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code()
{
return productCode;
//set { productCode = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int _Product_code
{
get { return productCode; }
set { productCode = value; }
}
public override string ToString()
{
return string.Format(drinkName + " " + drinkType + " " + drinkPrice + " " + productCode);
//return string.Format("The beverage {0} is of the type {1} and costs {2} SEK.", drinkName, drinkType, drinkPrice, productCode);
}
}
class Sodacrate
{
private soda[] bottles; //Crate the array bottles from the class soda.
private int antal_flaskor = 0; //Keeps tracks on the amount of bottles. 25 is the maximum allowed.
//Construct
public Sodacrate()
{
bottles = new soda[25];
}
public void sort_sodas()
{
string drinkName = "";
int drinkPrice = 0;
int productCode = 0;
Array.Sort(bottles, delegate (soda bottle1, soda bottle2) { return bottle1._Product_code.CompareTo(bottle2._Product_code); });
foreach (var beverage in bottles)
{
if (beverage != null)
{
drinkName = beverage.Drink_name(); drinkPrice = beverage.Drink_price(); productCode = beverage.Product_code();
Console.Write(drinkName + " " + drinkPrice + " " + productCode);
}
}
}
}
----------------------edit---------------
Thanks for the help I am getting closer to my solution and have to thursday lunch on me to solve my problems.
Still I have problem with my sort;
//Exception error When I try to have .Product_Name the compiler protests. Invalid token
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
Also my Linear search only returns one vallue when I want all those that are true to the product group. I tried a few different things in the Run() for faster experimentation. I will append the current code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Sodacrate
{
//Soda - contains the properties for the bottles that go in to the crate
class Soda : IComparable<Soda>
{
string drinkName;
string drinkType;
int drinkPrice;
int productCode;
//Construct for the beverage
public Soda(string _drinkName, string _drinkType, int _drinkPrice, int _productCode)
{
drinkName = _drinkName;
drinkType = _drinkType;
drinkPrice = _drinkPrice;
productCode = _productCode;
}
//Property for the drink name e.g. Coca Cola, Ramlösa or Pripps lättöl
public string Drink_name
{
get { return drinkName; }
set { drinkName = value; }
}
//Property for the drink type e.g. Soda, fizzy water or beer
public string Drink_type
{
get { return drinkType; }
set { drinkType = value; }
}
//Property for the drink price in SEK
public int Drink_price
{
get { return drinkPrice; }
set { drinkPrice = value; }
}
//Property for the product code e.g. 1, 2 or ...
public int Product_code
{
get { return productCode; }
set { productCode = value; }
}
//Override for ToString to get text instead of info about the object
public override string ToString()
{
return string.Format("{0,0} Type {1,-16} Price {2,-10} Code {3, -5} ", drinkName, drinkType, drinkPrice, productCode);
}
//Compare to solve my issues with sorting
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
static class Screen
{
// Screen - Generic methods for handling in- and output ======================================= >
// Methods for screen handling in this object are:
//
// cls() Clear screen
// cup(row, col) Positions the curser to a position on the console
// inKey() Reads one pressed key (Returned value is : ConsoleKeyInfo)
// inStr() Handles String
// inInt() Handles Int
// inFloat() Handles Float(Singel)
// meny() Menu system , first invariable is Rubrik and 2 to 6 meny choises
// addSodaMenu() The options for adding bottles
// Clear Screen ------------------------------------------
static public void cls()
{
Console.Clear();
}
// Set Curser Position ----------------------------------
static public void cup(int column, int rad)
{
Console.SetCursorPosition(column, rad);
}
// Key Input --------------------------------------------
static public ConsoleKeyInfo inKey()
{
ConsoleKeyInfo in_key; in_key = Console.ReadKey(); return in_key;
}
// String Input -----------------------------------------
static public string inStr()
{
string in_string; in_string = Console.ReadLine(); return in_string;
}
// Int Input -------------------------------------------
static public int inInt()
{
int int_in; try { int_in = Int32.Parse(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); int_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); int_in = 0; }
return int_in;
}
// Float Input -------------------------------------------
static public float inFloat()
{
float float_in; try { float_in = Convert.ToSingle(Console.ReadLine()); }
catch (FormatException) { Console.WriteLine("Input Error \b"); float_in = 0; }
catch (OverflowException) { Console.WriteLine("Input Owerflow\b"); float_in = 0; }
return float_in;
}
// Menu ------------------------------------------------
static public int meny(string rubrik, string m_val1, string m_val2)
{ // Meny med 2 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3)
{ // Meny med 3 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4)
{ // Meny med 4 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5)
{ // Meny med 5 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); menSvar = menyInm();
return menSvar;
}
static public int meny(string rubrik, string m_val1, string m_val2, string m_val3, string m_val4, string m_val5, string m_val6)
{ // Meny med 6 val ---------------------
int menSvar; menyRubrik(rubrik); menyRad(m_val1); menyRad(m_val2); menyRad(m_val3); menyRad(m_val4); menyRad(m_val5); ; menyRad(m_val6); menSvar = menyInm();
return menSvar;
}
static void menyRubrik(string rubrik)
{ // Meny rubrik --------
cls(); Console.WriteLine("\n\t {0}\n----------------------------------------------------\n", rubrik);
}
static void menyRad(string menyVal)
{ // Meny rad --------
Console.WriteLine("\t {0}", menyVal);
}
static int menyInm()
{ // Meny inmating ------
int mVal; Console.Write("\n\t Menyval : "); mVal = inInt(); return mVal;
}
// Menu for adding bottles --------------------------------
static public void addSodaMenu()
{
cls();
Console.WriteLine("\tChoose a beverage please.");
Console.WriteLine("\t1. Coca Cola");
Console.WriteLine("\t2. Champis");
Console.WriteLine("\t3. Grappo");
Console.WriteLine("\t4. Pripps Blå lättöl");
Console.WriteLine("\t5. Spendrups lättöl");
Console.WriteLine("\t6. Ramlösa citron");
Console.WriteLine("\t7. Vichy Nouveu");
Console.WriteLine("\t9. Exit to main menu");
Console.WriteLine("\t--------------------\n");
}
// Screen - Slut <========================================
} // screen <----
class Sodacrate
{
// Sodacrate - Methods for handling arrays and lists of Soda-objects ======================================= >
// Methods for Soda handling in this object are:
//
// cls() Clear screen
//
//
private Soda[] bottles; //Create they array where we store the up to 25 bottles
private int antal_flaskor = 0; //Keep track of the number of bottles in the crate
//Inte Klart saknar flera träffar samt exception
public int find_Soda(string drinkname)
{
//Betyg C
//Beskrivs i läroboken på sidan 147 och framåt (kodexempel på sidan 149)
//Man ska kunna söka efter ett namn
//Man kan använda string-metoderna ToLower() eller ToUpper()
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Drink_name == drinkname)
return i;
}
return -1;
}
//Exception error
public void sort_Sodas()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Product_code > bottles[j + 1].Product_code)
{
int temp = bottles[j].Product_code;
bottles[j] = bottles[j + 1];
bottles[j + 1].Product_code = temp;
}
}
}
}
/*
//Exception error
public void sort_Sodas_name()
{
int max = bottles.Length;
//Outer loop for complete [bottles]
for (int i = 1; i < max; i++)
{
//Inner loop for row by row
int nrLeft = max - i;
for (int j = 0; j < (max - i); j++)
{
if (bottles[j].Drink_name > bottles[j + 1].Drink_name)
{
int temp = bottles[j].Drink_name;
bottles[j] = bottles[j + 1];
bottles[j + 1].Drink_name = temp;
}
}
}
}
*/
//Search for Product code
public int LinearSearch(int key)
{
for (int i = 0; i < bottles.Length; i++)
{
if (bottles[i].Product_code == key)
return i;
}
return -1;
}
//Contains the menu to choose from the crates methods
public void Run()
{
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "beer", 6, 2);
bottles[4] = new Soda("Spendrups", "beer", 6, 2);
bottles[5] = new Soda("Ramlösa", "water", 4, 3);
bottles[6] = new Soda("Loka", "water", 4, 3);
bottles[7] = new Soda("Coca Cola", "Soda", 5, 1);
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:\n\n", bottleCount());
Console.WriteLine("\nTotal value of the crate\n");
int total = 0;
for (int i = 0; i < bottleCount(); i++)
{
total = total + (bottles[i].Drink_price);
}
/* int price = 0; //Causes exception error
foreach(var bottle in bottles)
{
price = price + bottle.Drink_price;
}
*/
Console.WriteLine("\tThe total value of the crate is {0} SEK.", total);
// Console.WriteLine("\tThe total value of the crate is {0} SEK.", price);
Screen.inKey();
Screen.cls();
int test = 0;
test = bottles[3].Product_code;
Console.WriteLine("Product code {0} is in slot {1}", test, 3);
Screen.inKey();
Console.WriteLine("Type 1, 2 or 3");
int prodcode = Screen.inInt();
Console.WriteLine(LinearSearch(prodcode));
Console.WriteLine("Product code {0} is in slot {1}", prodcode, (LinearSearch(prodcode)));
Console.WriteLine(bottles[(LinearSearch(prodcode))]);
Screen.inKey();
// sort_Sodas(); //Causes Exception error I want it to sort on either product code or product name
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
}
}
//Print the content of the crate to the console
public void print_crate()
{
foreach (var beverage in bottles)
{
if (beverage != null)
Console.WriteLine(beverage);
//else
//Console.WriteLine("Empty slot");
}
Console.WriteLine("\n\tYou have {0} bottles in your crate:", bottleCount());
}
//Construct, sets the Sodacrate to hold 25 bottles
public Sodacrate()
{
bottles = new Soda[25];
}
// Count the ammounts of bottles in crate
public int bottleCount()
{
int cnt = antal_flaskor;
// Loop though array to get not empty element
foreach (var beverages in bottles)
{
if (beverages != null)
{
cnt++;
}
}
return cnt;
}
//Calculates the total value of the bottles in the crate
public int calc_total()
{
int temp = 0;
for (int i = 0; i < bottleCount(); i++)
{
temp = temp + (bottles[i].Drink_price);
}
return temp;
}
//Adds bottles in the crate.
public void add_Soda()
{
/*Metod för att lägga till en läskflaska
Om ni har information om både pris, läsktyp och namn
kan det vara läge att presentera en meny här där man kan
välja på förutbestämda läskflaskor. Då kan man också rätt enkelt
göra ett val för att fylla läskbacken med slumpade flaskor
*/
//I start of with adding 7 bottles to avoid having to add so many bottles testing functions. Remove block before release
bottles[0] = new Soda("Coca Cola", "Soda", 5, 1);
bottles[1] = new Soda("Champis", "Soda", 6, 1);
bottles[2] = new Soda("Grappo", "Soda", 4, 1);
bottles[3] = new Soda("Pripps Blå", "lättöl", 6, 2);
bottles[4] = new Soda("Spendrups", "lättöl", 6, 2);
bottles[5] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
bottles[6] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
//<======================================================================================================= End block
int beverageIn = 0; //Creates the menu choice-variable
while (beverageIn != 9) //Exit this menu by typing 9 - This value should be different if we add more bottle types to add.
{
Screen.addSodaMenu(); //Calls the menu in the Screen-class
Console.WriteLine("You have {0} bottles in the crate.\n\nChoose :", bottleCount());
Screen.cup(8, 13);
int i = bottleCount(); //Keeps track of how many bottles we have in the crate. If the crate is full we get expelled out of this method
if (i == 25)
{ beverageIn = 9; }
else beverageIn = Screen.inInt(); //end
switch (beverageIn) //Loop for adding bottles to the crate exit by pressing 9
{
case 1:
i = bottleCount();
bottles[i] = new Soda("Coca Cola", "Soda", 5, 1);
i++;
break;
case 2:
i = bottleCount();
bottles[i] = new Soda("Champis", "Soda", 6, 1);
i++;
break;
case 3:
i = bottleCount();
bottles[i] = new Soda("Grappo", "Soda", 4, 1);
i++;
break;
case 4:
i = bottleCount();
bottles[i] = new Soda("Pripps Blå lättöl", "lättöl", 6, 2);
i++;
break;
case 5:
i = bottleCount();
bottles[i] = new Soda("Spendrups lättöl", "lättöl", 6, 2);
i++;
break;
case 6:
i = bottleCount();
bottles[i] = new Soda("Ramlösa citron", "mineralvatten", 4, 3);
i++;
break;
case 7:
i = bottleCount();
bottles[i] = new Soda("Vichy Nouveu", "mineralvatten", 4, 3);
i++;
break;
case 9:
i = bottleCount();
if (i == 25)
{
Console.WriteLine("\tThe crate is full\n\tGoing back to main menu. Press a key: ");
}
Console.WriteLine("Going back to main menu. Press a key: ");
break;
default: //Default will never kick in as I have error handling in Screen.inInt()
Console.WriteLine("Error, pick a number between 1 and 7 or 9 to end.");
break;
}
}
}
// Sodacrate - End <========================================
class Program
{
public static void Main(string[] args)
{
//Skapar ett objekt av klassen Sodacrate som heter Sodacrate
var Sodacrate = new Sodacrate();
Sodacrate.Run();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
}
In order to sort objects of a given kind you need to know how to compare two objects to begin with. You can sort an array of numbers because you know how to comparte 1 with 2 and 2 with -10 and so on.
Nowhere in your code are you defining how two sodas (that should be Soda by the way) compare to each other. One way to do this in c# (and .NET in general) is making your class implement a very specific interface named IComparable<T>:
public interface IComparable<T>
{
int CompareTo(T other);
}
CompareTo is what sorting algorithms like Array.Sort or Linq's OrderBy use (if not told otherwise). You need to do the same. T is a generic type, in your case you are interested in comparing sodas with sodas, so T would be Soda.
The CompareTo convention in .NET is as follows:
If this equals other return 0.
If this is less than other return -1.
If this is greater than other return 1.
null is considered to be smaller than any non null value.
Your implementation must follow this convention in order for built in sorting algorithms to work.
So first off, you need to define how you want your soda's to compare. By name? By price? All seem logical choices. If your problem specifies how sodas should compare then implement the comparison logic accordingly, otherwise choose a reasonable option.
I'll go with ordering by name, so I'd do the following:
public class Soda: IComparable<Soda>
{
....
public int CompareTo(Soda other)
{
if (ReferenceEquals(other, null))
return 1;
return drinkName.CompareTo(other.drinkName);
}
}
Because string implements IComparable<string>, implementing my own comparison logic is pretty straightforward.
Ok, now sodas know how to compare to each other and things like Array.Sort will work perfectly fine. Your own bubble sort algorithm should work well too, now that you know how to compare your softdrinks.
Another option would be to implement a IComparer<T> which is basically an object that knows how to compare two Sodas. Look into it, although in your case I think implementing IComparable<T> is a cleaner solution.
On another page, there are a few things about your code that can and should be improved:
soda should be named Soda. Classes should start with a capital letter (except maybe private nested ones).
Use properties instead of methods for Drink_name, Drink_price, Drink_type etc. and better yet, use autoimplemented properties to reduce boilerplate code.
Remove Drink form property names, the class is named Soda, so Drink is pretty much redundant not adding any useful information; its just making property names longer for no reason.
If you insist on keeping Drink use camel casing and remove _: DrinkName, DrinkType, etc.
I'm having trouble with the counter variable. Every time I leave each method, count is re-initialized to 0. I haven't completed the Stay() method the Hit() method is killing. After every Hit I need to display all of the user's cards. I do not know how to do this. There has to be a more efficient way. I think all my problems arise from the problem with the Count variable.
Thanks for any help.
Below is my main class. Below that is my Deck class.
I left out the Card, Suit and Rank class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlkJack
{
class Program
{
static void Main(string[] args)
{
string name;
int Chips = 500;
int Wage;
int count = 0;
string HS;
Card pCard1, dCard1, pCard2, dCard2;
int playerHand, dealerHand;
//int chipsWon;
Console.WriteLine("Welcome to Johnny's BlackJack!");
Console.WriteLine("You are given $500 to play with.");
Console.WriteLine("Table Limit is $250 per hand. <Enter a 0 to quit>");
name = GetName("Enter name: ");
Console.WriteLine("Hello {0}, you are ${1} ahead.", name, Chips);
Wage = getWager("What is your wager?: ", 1, 250, "?Value must be an integer.", "Max bet is 250!");
Deck d = new Deck();
startingHand(count, d, out pCard1, out dCard1, out pCard2, out dCard2, out playerHand, out dealerHand);
Console.WriteLine("Your hand: {0}, {1} <{2}> ", pCard1, pCard2, playerHand);
Console.WriteLine("<Dealer's show card is {0}>", dCard1);
count = count + 4;
HS = HitorStay("Do you want to <H>it or <S>tay?: ", count, playerHand, d);
while (HS == "H" || HS == "HIT")
{
HS = HitorStay("Do you want to <H>it or <S>tay?: ", count, playerHand, d);
Console.WriteLine("Your cards: {0} {1} <{2}>", pCard1, pCard2, playerHand);
//Console.WriteLine("{0}", count);
}
}
static string GetString(string prompt, string[] valid, string error)
{
string response;
bool OK = false;
do
{
Console.Write(prompt);
response = Console.ReadLine().ToUpper();
foreach (string s in valid) if (response == s) OK = true;
if (!OK) Console.WriteLine(error);
}
while (!OK);
return response;
}
static string GetName(string prompt)
{
string response;
Console.Write(prompt);
response = Console.ReadLine();
while (response == "0")
{
Environment.Exit(0);
}
return response;
}
static bool GetYesNo(string prompt)
{
string[] valid = { "YES", "Y", "NO", "N" };
string ans = GetString(prompt, valid, "Invalid response. Please reenter.");
return (ans == "YES" || ans == "Y");
}
static int getWager(string prompt, int low, int high, string errorInt, string errorRange)
{
int Wager;
string userInput;
bool OKInt = false, OKRange = false;
do
{
Console.Write(prompt);
userInput = Console.ReadLine();
OKInt = Int32.TryParse(userInput, out Wager);
if (OKInt)
{
OKRange = low <= Wager && Wager <= high;
if (!OKRange) Console.WriteLine(errorRange);
}
else
Console.WriteLine(errorInt);
}
while (!OKInt || !OKRange);
return Wager;
}
public static int startingHand(int count, Deck d, out Card pCard1, out Card dCard1, out Card pCard2, out Card dCard2, out int playerHand, out int dealerHand)
{
playerHand = 0; dealerHand = 0;
if (count == 0 || count >= 42) d.Shuffle();
for (int i = 0; i < 52; i++)
Console.Write("{0},", d.GetCard(i));
pCard1 = d.GetCard(count);
count++;
dCard1 = d.GetCard(count);
count++;
pCard2 = d.GetCard(count);
count++;
dCard2 = d.GetCard(count);
count++;
playerHand = pCard1.GetValue() + pCard2.GetValue();
dealerHand = dCard1.GetValue() + dCard2.GetValue();
return count;
}
static string HitorStay(string prompt, int count, int playerHand, Deck d)
{
string[] valid = { "HIT", "H", "STAY", "S" };
string HS = GetString(prompt, valid, "?Invalid Response. (H)it or (S)tay?");
if (HS == "HIT" || HS == "H")
{
Hit(count, playerHand, d);
}
//else if (HS == "STAY" || HS == "S")
//{
//Stay(count, playerHand, dealerHand, out chipStay);
//}
else Environment.Exit(0);
return HS;
}
public static int Hit(int count, int playerHand, Deck d)
{
count += 1;
playerHand += d.GetCard(count).GetValue();
return playerHand;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlkJack
{
class Deck
{
private Card[] cards = new Card[52];
public Deck()
{
for (int suitVal=0; suitVal<4; suitVal++)
{
for (int rankVal = 0; rankVal < 13; rankVal++)
{
cards[suitVal * 13 + rankVal] =
new Card((Suit)suitVal, (Rank)(rankVal));
cards[suitVal * 13 + rankVal].SetValue(rankVal);
if (rankVal > 9) cards[suitVal * 13 + rankVal].SetValue(10);
if (rankVal == 1) cards[suitVal * 13 + rankVal].SetValue(11);
if (rankVal == 0) cards[suitVal * 13 + rankVal].SetValue(10);
}
}
}
public Card GetCard(int cardNum)
{
return cards[cardNum];
}
public void Shuffle()
{
Card[] newDeck = new Card[52]; // cards randomly assigned to locs in newDeck
bool[] assigned = new bool[52]; // keep track of what locs used in newDeck
int seed = 0;
Console.Write("Enter seed: ");
seed = Convert.ToInt32(Console.ReadLine()); // yes, stupid user can break
Random rGen = new Random(seed);
for (int i=0; i<52; i++)
{
int destCard = 0; // where card is going to be put
bool foundCard = false;
while (foundCard == false)
{
destCard = rGen.Next(52);
if (assigned[destCard] == false)
foundCard = true;
}
assigned[destCard] = true;
newDeck[destCard] = cards[i];
}
newDeck.CopyTo(cards, 0); //.CopyTo(destination, start index)
}
}
}
Look at this code
public static int Hit(int count, int playerHand, Deck d)
{
count += 1;
You are passing in a copy of count and incrementing that copy. The original value you passed in is never affected. Straightforward fixes include
Pass count by reference ref int count.
Make count a static class field rather than a local variable in Main()
A much better way would be to encapsulate your logic in a class and make count a field or property of that class, so that class methods can see and change it.