-2

This is my homework and I have been working on it for a long time. Honestly, I myself do not understand why 1d20 is 10.5 (in the examples below) and I hope to get them from you. I myself tried to do calculations using a DataTable, but I just don't understand how to calculate an example of the mDn type. I'm trying to implement a standard calculator with special D&D operation.

A string is a valid mathematical expression consisting of unary (+ -) and binary (+ - * /) operators, brackets and operands - numbers and random variables. Numbers can be written both in integer form (2) and as a decimal fraction (1.5). Any number should be considered as a fractional (double), i.e. the expression 3/2 should result in 1.5, not 1.

Random values ​​will be written in standard D&D notation: XdY (for example: 1d20, 2d6, 1d3), where X and Y are positive integers. XdY actually means

Take X Y-sided dice, roll them, and take the sum.

Examples:

2+2*2         == 6
1d20          == 10.5
2d6+(-1d12/5) == 5.7
  • 7
    And your question is...? We're not just going to implement this for you; I'm also not sure how you roll 10.5 on a standard 1d20, or end up with `anything.7` from dividing an integer by 5; if you are asking "where would I start with this?" - personally, I'd implement a modified "[shunting yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm)" to parse the expression into an AST, then I'd evaluate the AST semantically – Marc Gravell Sep 16 '21 at 06:13
  • Some help for the parser: https://stackoverflow.com/q/355062/1838048 – Oliver Sep 16 '21 at 07:05
  • 1
    welcome to stackoverflow. seems like a typical [homework question](https://meta.stackoverflow.com/questions/334822/how-do-i-ask-and-answer-homework-questions) to me. can you please share what you've tried and researched so far? we'll gladly help if you're stuck somewhere, but you should first attempt to solve the task on your own - and be able to describe your efforts. i recommend [taking the tour](https://stackoverflow.com/tour), as well as reading [how to ask a good question](https://stackoverflow.com/help/how-to-ask) and [what's on topic](https://stackoverflow.com/help/on-topic). – Franz Gleichmann Sep 16 '21 at 07:14
  • You still don't ask an explicit, answerable question. The examples seem to (misguidedly) take the *expected value* from dice rolls for computation while presenting results without any indication that they are but expected values, too. – greybeard Sep 18 '21 at 05:03
  • If you don't understand something about an assignment you should ask your professor or TA. – Dour High Arch Oct 15 '21 at 15:39

1 Answers1

1

You can convert (replace) with a help of regular expressions all mDn fragments into its equivalent formula (in determenistic case):

 mDn => m * (1 + n) / 2

If we really want to throw dice, we can use Random:

 private static Random s_Random = new Random();

 ...

 mDn => Enumerable.Range(1, m).Sum(_ => s_Random.Next(1, n + 1)) 

And then compute formula as usual (let it do via DataTable).

Code:

using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

...

// Determenistic case
private static double MyCompute(string formula) {
  formula = Regex.Replace(formula,
    @"(?<m>[0-9]+)\s*[dD]\s*(?<n>[0-9]+)",
     m => $"({m.Groups["m"].Value} * (1 + {m.Groups["n"].Value}) / 2.0)");

  using (DataTable table = new DataTable()) {
    return Convert.ToDouble(table.Compute(formula, null));
  }
}

Probabilistic case (when we throw dice)

// Simple, but not thread safe
private static Random s_Random = new Random();

private static double DandD(int m, int n) => Enumerable
  .Range(1, m).Sum(_ => s_Random.Next(1, n + 1));

private static double MyCompute(string formula) {
  formula = Regex.Replace(
     formula,
    @"(?<m>[0-9]+)\s*[dD]\s*(?<n>[0-9]+)",
     m => $"{DandD(int.Parse(m.Groups["m"].Value), int.Parse(m.Groups["n"].Value))}");

  using (DataTable table = new DataTable()) {
    return Convert.ToDouble(table.Compute(formula, null));
  }
}

Demo:

  string[] tests = new string[] {
    "3/2",
    "2+2*2", 
    "1d20",
    "2d6+(-1d12/5)"
  };

  string report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test,-13} == {MyCompute(test)}"));

  Console.Write(report); 

Outcome: (determenistic case)

3/2           == 1.5
2+2*2         == 6
1d20          == 10.5
2d6+(-1d12/5) == 5.7
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • What a great answer. But what I still don't understand, is why is `1d20 == 10.5`? What should happen with this number, cause as far as I understood, it should come out a *random integer* number between 1 and 20 (inclusive)? – Oliver Sep 16 '21 at 07:58
  • 1
    @Oliver: all examples in the question seem to be determenistic (expectation is used instead of random number). If we want random numbers (i.e. we want to cast dice) we can use the same scheme: match all `mdn`, compute them (now with random numbers) and then compute the rest of the formula. I've edited the question – Dmitry Bychenko Sep 16 '21 at 09:02
  • u saved my life!!! – Alexander Chernykh Sep 18 '21 at 04:52