2

I'm currently teaching myself C# and came up with a program idea as follows:

  1. Program generates random number
  2. Program generates random math operator
  3. Program generates random number
  4. Asks user for the answer to the randomly generated problem
  5. User inputs answer
  6. Program compares result of generated problem against user's input
  7. Program prints whether user was correct or incorrect.

The issue I'm running into is that I can only print the equation in the following format/data types:

(example) 5 + 1 (number, string operator, number)

OR combine the above data types into a single string

From there the problem is that I cannot figure out how to convert all of it into a math equation that can be stored in a variable and then compared against the user's input.

I'm sure I'm making it more difficult than it probably is, but I've been at this program, forums, and tons of posts without being able to piece anything together.

Any insight to my code and where I'm going wrong would be greatly appreciated in my learning C#!

public static void Main(string[] args)
{
    mathProblem();
    int userAnswer = Convert.ToInt32(Console.ReadLine());
}

public static void mathProblem()
{
    Random numberGenerator = new Random();
    Random operatorSelect = new Random();

    //Generates random number for 1st part of problem
    int number1 = numberGenerator.Next(1, 11);
    //Generates random number for 2nd part of problem
    int number2 = numberGenerator.Next(1, 11);
    //int to store/assign random operator
    int mathOperator = 0;
    //newOperator set to empty string that will change and store operator generated
    string newOperator = "";

    // gives value of 1-4
    mathOperator = operatorSelect.Next(5);
    switch (mathOperator)
    {
        case 1:
            newOperator = "+";
            break;
        case 2:
            newOperator = "-";
            break;
        case 3:
            newOperator = "*";
            break;
        case 4:
            newOperator = "/";
            break;
        default:
            newOperator = "+"; 
            break;
    }

    Convert.ToString(number1);
    Convert.ToString(number2);

    Console.WriteLine("What is " + number1 + " " + newOperator + " " + number2 + "?");
}
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
Tonyobyo
  • 61
  • 9
  • 3
    You dont need to store the math equation, you only need to perform the equation and store the _result_. Besides that your switch statement has to actually perform the math, not just assign the `newOperator` variable – maccettura Oct 16 '18 at 21:38
  • 4
    You have a disorder extremely common in developers at all levels, from beginner to expert: **String Happiness Disorder**. That is, you believe that strings are a useful data type for some task that does not actually involve *text*. You're doing *math*, so write code that represents mathematical objects as *mathematical objects*, not as *text*. Try this: make a base class `Expression` and two derived classes, `Addition` and `Number`. Now do you see how to represent 1 + 2 + 3? Now can you implement a method `Evaluate` on `Expression` ? – Eric Lippert Oct 16 '18 at 22:18
  • 1
    Also, **NEVER EVER EVER MAKE TWO RANDOMS LIKE THAT**. Make *one* random and use it for *everything*. When you make two randoms right after each other **they both produce exactly the same sequence of random numbers** which is not at all what you want. – Eric Lippert Oct 16 '18 at 22:19

2 Answers2

3

Arithmetic operations are functions that accept two numbers and return a third number. In general they can be expressed as a function:

int AddOperation(int a, int b)
{
    return a + b;
}

A delegate for this sort of function can be stored in a variable that is typed as a Func<int,int,int>.

Func<int,int,int> functionPointer = AddOperation;

Instead of declaring a whole method just for AddOperation, you can also store it is an anonymous method declared with a lambda expression:

Func<int,int,int> functionPointer = (a,b) => a + b;

And you can store a series of these functions, for example, in a dictionary:

var operators = new Dictionary<string,Func<int,int,int>>
{
    { "+", (a,b) => a + b },
    { "-", (a,b) => a - b },
    { "*", (a,b) => a * b },
    { "/", (a,b) => a / b }
};

Then to execute an operation, you look up the function:

var symbol = "+";
var operation = operators[symbol];

...and use it to compute the result:

var result = operation(arg1,arg2);

Here is an example that performs all four operations on the numbers 10 and 2:

public static void Main()
{
    var operators = new Dictionary<string,Func<int,int,int>>
    {
        { "+", (a,b) => a + b },
        { "-", (a,b) => a - b },
        { "*", (a,b) => a * b },
        { "/", (a,b) => a / b }
    };

    var arg1 = 10;
    var arg2 = 2;

    foreach (var symbol in operators.Keys)
    {
        var func = operators[symbol];
        var result = func(arg1,arg2);
        Console.WriteLine("{0}{1}{2}={3}", arg1, symbol, arg2, result);
    }
}

Output:

10+2=12
10-2=8
10*2=20
10/2=5

Link to working example on DotNetFiddle

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • If this game is for non-programmers you may want to use typographic mathematical symbols + − × ÷. – Dour High Arch Oct 16 '18 at 21:52
  • 1
    Might have a loss of information with a division operation here if everything is an `int`... This also seems a bit advanced for someone new to C# – maccettura Oct 16 '18 at 21:56
0

I think you are going about this in the wrong direction. Why do you need to store the operator as a string? Why have all these separate random instances? At the end of the day you need to randomly generate a math problem right? And you have to determine if the user gets the answer correct or not.

So first things first, use a single static Random field instead of a local variable:

private static Random rnd = new Random();

public static void GenerateRandomMathProblem()
{
    // code
}

See here for some good info on why you dont want to use multiple Random variables like you were.

Also consider a better name than mathProblem(), use something more descriptive (What about a math problem?) also use the proper casing (PascalCase).

Second issue: the variables you track. I think you should only care about these variables:

int number1 = rnd.Next(1, 11);

int number2 = rnd.Next(1, 11);

// Store the answer, has to be a double since you have some division operation
double answer = 0;

// Store the question so you can ask the user
string question = string.Empty;

Now, your switch case has to perform double duty. Perform the actual math and store the result in answer and generate the actual string question and assign to to question

// Case of '-'
case 1:
    answer = number1 - number2; //Gets the answer
    question = $"{number1} - {number2}"; //Syntax is called string interpolation, its a little cleaner than concatenation
    break;

We have already generated the question so we dont need the number variables anymore, but just so you are aware, the Convert calls you do are completely unnecessary. Console.WriteLine() will automatically call ToString() on its arguments. And every single thing in C# can have .ToString() called on it since its a member of object and everything in C# inherits from System.Object:

Now, at the end when you ask your question, instead of using string concatenation you can use the "formatting" capability of Console.WriteLine() to make your code a bit cleaner:

// The {0} will be replaced with the value of 'question' in the console
Console.WriteLine("What is {0}?", question);
maccettura
  • 10,514
  • 3
  • 28
  • 35
  • Ah that makes much more sense...Knew I was making things a lot more complicated than needed so thank you very much! I wasn't aware of using string interpolation, cleared things up much better as well. So then I'd assume to compare the randomly generated problem to the user's answer, another function outside of main that handles this needs called inside main after user enters their answer? – Tonyobyo Oct 17 '18 at 13:58
  • 1
    If you're going to use case statements with a hard-coded set of ints, I recommend using an enumeration. I'd rather see `case 1` forced maccettura to add a comment whereas `case Operator.Minus` is self-explanatory. – Brian Oct 17 '18 at 14:14
  • @Brian OP is a beginner. Didn’t want to introduce a ton of new concepts or potentially move them past where they are in a book/class – maccettura Oct 17 '18 at 14:15
  • @maccettura no book/class on this as it's all just for learning on my own, but sincerely appreciate you taking that into consideration – Tonyobyo Oct 17 '18 at 14:30
  • @maccettura So if I'm thinking about this correctly, and please correct me if wrong, I would create a new EvaluateProblem function that takes 2 arguments (user input and variable holding the generated equation), compare with if/else, and return the correct/incorrect statement back to main? – Tonyobyo Oct 17 '18 at 14:36
  • @Tonyobyo There is a lot more left to do to make this all function end to end. Also, the way someone just starting off should solve this is way different than someone who has been doing this a super long time would. I think its important to try and solve it with the tools you already have first instead of introducing all the higher level concepts. That being said, you would likely want a method that generates a math problem and returns the problem as a string, and the answer as a numerical type (this is where a custom class comes in handy, a class with _two properties_). – maccettura Oct 17 '18 at 14:41
  • @Tonyobyo Then you want a method that asks the user the question, and returns their answer (as an actual number, so you have to _try and parse_ their string input). Now you just need a method that takes their numerical answer and compares it with the numerical answer that was generated earlier. Keep in mind that you are introducing division with your design, and division can get dicey and complicated (what if you generate `9 / 7` randomly? Do you really expect the user to type `1.28571428571`?) – maccettura Oct 17 '18 at 14:44
  • 1
    @maccettura yeah coming from a degree in web dev I'm familiar with basic programming concepts/logic but more so from simple front-end aspects...love web dev but always wanted to be proficient with programming. – Tonyobyo Oct 17 '18 at 14:53
  • @maccettura ah so perhaps it best to remove division for now to keep things simplistic then – Tonyobyo Oct 17 '18 at 14:54
  • @Tonyobyo Yes, stick with whole numbers. Then you can use `int` instead of `double`. – maccettura Oct 17 '18 at 14:55
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182041/discussion-between-tonyobyo-and-maccettura). – Tonyobyo Oct 17 '18 at 18:46
  • @maccettura thanks for all the help in chat...apparently I can't add any more comments due to my rep being too low. Didn't want you to think all your help and insight wasn't appreciated! – Tonyobyo Oct 17 '18 at 20:51