2

I am making a C# maths console-project where the user answers an addition, subtraction, multiplication, division, power or 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 RunTest(int numberOfQuestionsLeft, UserDifficulty userDifficulty)
        {
            int score = 0;
            Random random = new Random();
            var (operationMin, operationMax) = GetPossibleOperationsByDifficulty(userDifficulty);
            while (numberOfQuestionsLeft > 0)
            {
                int mathRandomOperation = random.Next(operationMin, operationMax);
                MathOperation mathOperation = (MathOperation)mathRandomOperation;
                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!");
                    score++;
                }
                else
                {
                    Console.WriteLine("Your answer is incorrect!");
                }
                numberOfQuestionsLeft--;
            }

            return score;
        }

        public static void Main(string[] args)
        {
            string userInputDifficulty = "";
            UserDifficulty userDifficulty = (UserDifficulty)0;
            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");

            switch (userInputDifficulty)
            {
                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 = RunTest(numberOfQuestions, userDifficulty);
            Console.WriteLine($"You got a score of {score} out of {numberOfQuestions}");
        }
    }
}

I am trying to simplify my code so I don't need the userInputDifficulty switch-statement. But when I remove the switch-statements and I run the code, the questions are always easy difficulty questions.

To fix this I need to cast my int to an enum, but I am not sure how to.

Can someone show me how it's done! Thanks!

qqqqqkks
  • 62
  • 16
  • `I am trying to simplify my code so I don't need the userInputDifficulty switch-statement or the mathRandomOperation switch-statement.` I'd suggest asking *one* of those two questions at a time. https://meta.stackexchange.com/questions/39223/one-post-with-multiple-questions-or-multiple-posts – mjwills Mar 27 '20 at 00:05
  • In the meantime, have a read of https://codereview.stackexchange.com/questions/124733/switch-vs-dictionary-logic https://codereview.stackexchange.com/questions/29664/how-to-avoid-switch-case http://nelsonwells.net/2015/02/replace-switch-statements-with-dictionaries/ . – mjwills Mar 27 '20 at 00:06
  • You are already casting integer to enum by doing `MathOperation mathOperation = (MathOperation)0` – Chetan Mar 27 '20 at 00:10
  • 2
    This is a neat project, may I suggest in division `number2 = randomNumber.Next(1, 1000);` – rfmodulator Mar 27 '20 at 00:55
  • 1
    C# 8 switch expression `public static UserDifficulty GetUserDifficulty(string input) => input switch { "E" => UserDifficulty.Easy, "N" => UserDifficulty.Normal, "H" => UserDifficulty.Hard, _ => throw new ArgumentOutOfRangeException() };` – TheGeneral Mar 27 '20 at 01:01

3 Answers3

2

For mathOperation, all you need to do is cast int to MathOperation. However, I suggest you add definition 0 as "Undefined" in MathOperation for readability.

For userInputDifficulty, the easiest way could be using Dictionary.

Set up your dictionary somewhere ( mostly when class is instantiated)

Dictionary<string, UserDifficulty> dict = new Dictionary<string, UserDifficulty>();
dict.Add( "E", UserDifficulty.Easy );
dict.Add( "N", UserDifficulty.Normal );
dict.Add( "H", UserDifficulty.Hard );

Replace your switch case with dictionary:

// This is an example.
string userInputDifficulty = "E";
UserDifficulty diff = dict[ userInputDifficulty ];
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Louis Go
  • 2,213
  • 2
  • 16
  • 29
1

For the mathRandomOperation switch statement just use something like the following:

MathOperation operation = (MathOperation)mathRandomOperation;

For the other one you really can't do anything about it, since you are using some sort of abbreviations. Anyhow if you really want to avoid this and shorten your code down, you can use a package of mine.

You will need to tell StringyEnums which string values map to which enum member:

public enum UserDifficulty
{
    [StringRepresentation("E")]
    Easy,
    [StringRepresentation("N")]
    Normal,
    [StringRepresentation("H")]
    Hard
}

After you get the user input you can pass it to the GetEnumFromRepresentation extension method. There is also a Try version of it, which would allow you to check if the entered string can be converted to an enum member.

UserDifficulty difficulty = userInputDifficulty.GetEnumFromRepresentation<UserDifficulty>();

Also you will need to Initialize StringyEnums:

EnumCore.Init();

Just put this line at the very beginning of your Main method or somewhere before calling any of the packages extension methods.

Note

This will not perform as fast as your switch statement, but is still optimized for such scenarios.

Twenty
  • 5,234
  • 4
  • 32
  • 67
1

Here is another solution using LinQ.

    // First, load all difficulty level names into an array
    string[] userDifficultyLevelNames = Enum.GetNames(typeof(UserDifficulty));

    // Then load the initials (first characters) of the difficulty level values into a list
    List<string> userDifficultyLevelInitials = userDifficultyLevelNames.Select(a => a.Substring(0, 1)).ToList();

    string userInputDifficulty = "";
    UserDifficulty userDifficulty = (UserDifficulty)0;

    // Check if the entered character is one of the difficulty level initials.
    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 (!userDifficultyLevelInitials.Contains(userInputDifficulty));

    // Then, parse the difficulty level from the name
    // Please note that if any two enumaration values start with the same character
    // this approach will fail
    userDifficulty = (UserDifficulty)Enum.Parse
    (
        typeof(UserDifficulty),
        userDifficultyLevelNames.First(a => a.StartsWith(userInputDifficulty))
    );
Oguz Ozgul
  • 6,809
  • 1
  • 14
  • 26