【问题标题】:Is it possible to reduce repetitive permutation-based if-statements?是否可以减少重复的基于排列的 if 语句?
【发布时间】:2023-03-07 16:06:01
【问题描述】:

您好,我正在做这个数学游戏,在我的最后一个场景中,我做了很多重复的代码,但我不确定是否有办法简化它,我已经在下面链接了,所以可能会更老练程序员可能有一些更优雅的解决方案! 例如,我试图生成 (a[]b)²[]c[]d 之类的所有排列,其中括号将替换为 +、-、* 或 /。我一直在做的只是创建随机百分比 if 语句来选择特定版本,如“(a+b)²/cd” 是否有比我一直在做的更“蛮力”和可读性的方法?

if(UnityEngine.Random.Range(0,101)>50){
        // 50% of being (a+b)²(c)+d
    if(UnityEngine.Random.Range(0,101)>50){
        ans = ((int) Mathf.Pow((float) a+ (float) b, 2))*c+d;
        input.text = "("+a+"+"+b+")"+"²"+"("+c+")"+"+"+d+"=";
        Debug.Log("Problem ID: 78");
        // 50% of being (a+b)²(c)-d
    } else {
        ans = ((int) Mathf.Pow((float) a+ (float) b, 2))*c-d;
        input.text = "("+a+"+"+b+")"+"²"+"("+c+")"+"-"+d+"=";
        Debug.Log("Problem ID: 79");
    }
    // 50% of being (a-b)²(c)[]d
} else {
    // 50% of being (a-b)²(c)+d
    if(UnityEngine.Random.Range(0,101)>50){
        ans = ((int) Mathf.Pow((float) a- (float) b, 2))*c+d;
        input.text = "("+a+"-"+b+")"+"²"+"("+c+")"+"+"+d+"=";
        Debug.Log("Problem ID: 80");
        // 50% of being (a-b)²(c)-d
    } else {
        ans = ((int) Mathf.Pow((float) a- (float) b, 2))*c-d;
        input.text = "("+a+"-"+b+")"+"²"+"("+c+")"+"-"+d+"=";
        Debug.Log("Problem ID: 81");
    }

(下面的Pastebin以获得更多上下文) https://pastebin.pl/view/d1bfb99e

【问题讨论】:

    标签: c# math optimization permutation dry


    【解决方案1】:

    我赞赏您希望使您的代码更具可读性。基本思想是将 (a) 定义、(b) 选择和 (c) 应用运算符分开。

    • 第 1 步:定义Operators。每个Operator 都结合了一个数学运算(例如Add 将是(a, b) => a + b)和一个符号(例如Add 将是"+")。

      class Operator
      {
          public Func<int, int, int> Calculate { get; }
          public string Symbol { get; }
      
          public Operator(Func<int, int, int> calculate, string symbol)
          {
              Calculate = calculate;
              Symbol = symbol;
          }
      }
      
      private Operator Add = new Operator((a, b) => (a + b), "+");
      private Operator Subtract = new Operator((a, b) => (a - b), "-");
      
    • 第 2 步:然后随机选择运算符(我使用 System.Random,因为我对 Unity 不熟悉,但请随意将其替换为您选择的随机数生成器):

      var rnd = new Random();
      
      private (Operator op1, Operator op2, int problemId) RandomlyChooseProblem()
      {
          switch (rnd.Next(4))
          {
              case 0: return (Add, Add, 78);
              case 1: return (Add, Subtract, 79);
              case 2: return (Subtract, Add, 80);
              case 3: return (Subtract, Subtract, 81);
              default: throw new InvalidOperationException("This should not happen.");
          }
      }
      
    • 第 3 步:应用它们:

      var (op1, op2, problemId) = RandomlyChooseProblem();
      
      ans = op2.Calculate((int)Math.Pow(op1.Calculate(a, b), 2) * c, d);
      input.text = $"(a{op1.Symbol}b)²*c{op2.Symbol}d");
      Debug.Log($"Problem ID: {problemId}");
      

    现在只需一行代码即可添加新的运算符(例如Multiply)或新的问题变体(例如(Add, Multiply, 82))。

    【讨论】:

      【解决方案2】:

      将计算分成几部分 - a±bsquare * c±d。分别计算,乘以得到最终结果。对于文本,可以使用字符串插值

      float ans;
      string operator1;
      string operator2;
      if (UnityEngine.Random.Range(0,101)>50) {
          ans = (float) a + (float) b;
          operator1 = "+";
      } else {
          ans = (float) a - (float) b;
          operator1 = "-";
      }
      ans = (int)(ans * ans) * c;
      if (UnityEngine.Random.Range(0,101)>50) {
          ans += d;
          operator2 = "+";
      } else {
          ans -= d;
          operator2 = "-";
      }
      input.text = $"(a{operator1}b)²(c){operator2}d";
      

      还要注意UnityEngine.Random.Range(0,101) &gt; 50 的概率并不完全是 50%。您可能指的是UnityEngine.Random.Range(1,101) &gt; 50,但我只会使用UnityEngine.Random.Range(0,2) == 0

      可以通过生成 2 个随机位并将由这些位编码的 2 位数字添加到 78 来展平问题 ID:

      float ans;
      string operator1;
      string operator2;
      int random1 = UnityEngine.Random.Range(0,2);
      int random2 = UnityEngine.Random.Range(0,2);
      if (random1 == 0) {
          ans = (float) a + (float) b;
          operator1 = "+";
      } else {
          ans = (float) a - (float) b;
          operator1 = "-";
      }
      ans = (int)(ans * ans) * c;
      if (random2 == 0) {
          ans += d;
          operator2 = "+";
      } else {
          ans -= d;
          operator2 = "-";
      }
      int problemID = 78 + random1 + random2 * 2;
      Debug.Log($"Problem ID: {problemID}");
      input.text = $"(a{operator1}b)²(c){operator2}d";
      

      不过,这个技巧在 IMO 中的可读性并不高。

      【讨论】:

      • 所以如果我想简化它听起来像什么我应该使用像 (a[]b)²[]c[]d 这样的模型,然后为这部分代码生成 a[+, -,*,/]b 并为每个变量交互执行此操作。并可能将其抽象化为。一种 switch case 方法,因此当我执行 a[]b[]c[]d 或 a[]b[](c[]d) 之类的操作时,我可以重复它
      • @BriceBrown 如果您有这么多运算符,您可能应该尝试 Heinzi 的答案。
      猜你喜欢
      • 2012-02-08
      • 1970-01-01
      • 2020-08-15
      • 2016-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      相关资源
      最近更新 更多