2016-09-28 61 views
0

我在JavaFX中計劃了一個新的遊戲「數字形狀系統」。基本上它是一個小的記憶遊戲,圖片與數字相關聯。所以'2'='天鵝','5'='手(手指)'等等。所以玩家看到練習'Swan + Fingers =?'。用遞歸創建具有預定義定義的基本數學運算

我要的是所有可能的規則如下數學運算:

/* 
* Generate all possible mathematical operations to the console with the numbers 
* 0-12, where every result is (>= 0 && <= 12). 
* - Mathematical operations are '+', '-', '*' and '/'. 
* - The rule 'dot before line' shouldn't be used, instead the operations will 
* be executed from left to right. 
* - Every among result must be between (>= 0 && <= 12) and a whole number. 
* - Only different numbers are allowed for the operations (an operation have 
* 2 numbers). For example 2+3 is allowed, 3*3 not. 
* 
* A solution with recursive methods would be preferred. I want the output for 
* the length 2-10. 
* 
* Example output with different length: 
* - Length 3: 2+3(=5)*2(=10) 
* - Length 5: 2+3(=5)*2(=10)+2(=12)/4(=3) 
*/ 

我已經準備了一個示例實現,但我不知道如何將它轉換成一個遞歸功能。

import java.util.ArrayList; 
import java.util.List; 

public class Generator { 

    private static final List<Double> numbers = new ArrayList<>(); 
    private static final List<String> operations = new ArrayList<>(); 

    static { 
     numbers.add(0.0); 
     numbers.add(1.0); 
     numbers.add(2.0); 
     numbers.add(3.0); 
     numbers.add(4.0); 
     numbers.add(5.0); 
     numbers.add(6.0); 
     numbers.add(7.0); 
     numbers.add(8.0); 
     numbers.add(9.0); 
     numbers.add(10.0); 
     numbers.add(11.0); 
     numbers.add(12.0); 

     operations.add("+"); 
     operations.add("-"); 
     operations.add("*"); 
     operations.add("/"); 
    } 

    private int lineCounter = 0; 

    public Generator() { 
     this.init(); 
    } 

    private void init() { 

    } 

    public void generate() { 
     // Length 2 ########################################################### 
     boolean okay = false; 
     int lineCounter = 0; 
     StringBuilder sbDouble = new StringBuilder(); 
     for (Double first : numbers) { 
      for (Double second : numbers) { 
       for (String operation : operations) { 
        if (first == second) { 
         continue; 
        } 

        if (operation.equals("/") && (first == 0.0 || second == 0.0)) { 
         continue; 
        } 

        double result = perform(first, operation, second); 
        okay = this.check(result, operation); 
        if (okay) { 
         ++lineCounter; 

         sbDouble = new StringBuilder(); 
         this.computeResultAsString(sbDouble, first, operation, second, result); 
         System.out.println(sbDouble.toString()); 
        } 
       } 
      } 
     } 

     System.out.println("Compute with length 2: " + lineCounter + " lines"); 
     // Length 2 ########################################################### 

     // Length 3 ########################################################### 
    okay = false; 
     lineCounter = 0; 
     sbDouble = new StringBuilder(); 
     for (Double first : numbers) { 
      for (Double second : numbers) { 
       for (String operation1 : operations) { 
        if (first == second) { 
         continue; 
        } 
        if (operation1.equals("/") && (first == 0.0 || second == 0.0)) { 
         continue; 
        } 

        double result1 = perform(first, operation1, second); 
        okay = this.check(result1, operation1); 
        if (okay) { 
         for (Double third : numbers) { 
          for (String operation2 : operations) { 
           if (second == third) { 
            continue; 
           } 
           if (operation2.equals("/") && third == 0.0) { 
            continue; 
           } 

           double result2 = perform(result1, operation2, third); 
           okay = this.check(result2, operation2); 
           if (okay) { 
            ++lineCounter; 

            sbDouble = new StringBuilder(); 
            this.computeResultAsString(sbDouble, first, operation1, second, result1); 
            this.computeResultAsString(sbDouble, operation2, third, result2); 
            System.out.println(sbDouble.toString()); 
           } 
          } 
         } 
        } 
       } 
      } 
     } 

     System.out.println("Compute with length 3: " + lineCounter + " lines"); 
     // Length 3 ########################################################### 

     // Length 4 ########################################################### 
     okay = false; 
     lineCounter = 0; 
     sbDouble = new StringBuilder(); 
     for (Double first : numbers) { 
      for (Double second : numbers) { 
       for (String operation1 : operations) { 
        if (first == second) { 
         continue; 
        } 
        if (operation1.equals("/") && (first == 0.0 || second == 0.0)) { 
         continue; 
        } 

        double result1 = perform(first, operation1, second); 
        okay = this.check(result1, operation1); 
        if (okay) { 
         for (Double third : numbers) { 
          for (String operation2 : operations) { 
           if (second == third) { 
            continue; 
           } 
           if (operation2.equals("/") && third == 0.0) { 
            continue; 
           } 

           double result2 = perform(result1, operation2, third); 
           okay = this.check(result2, operation2); 
           if (okay) { 
            for (Double forth : numbers) { 
             for (String operation3 : operations) { 
              if (third == forth) { 
               continue; 
              } 
              if (operation3.equals("/") && forth == 0.0) { 
               continue; 
              } 

              double result3 = perform(result2, operation3, forth); 
              okay = this.check(result3, operation3); 
              if (okay) { 
               ++lineCounter; 

               sbDouble = new StringBuilder(); 
               this.computeResultAsString(sbDouble, first, operation1, second, result1); 
               this.computeResultAsString(sbDouble, operation2, third, result2); 
               this.computeResultAsString(sbDouble, operation3, forth, result3); 
               System.out.println(sbDouble.toString()); 
              } 
             } 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 

     System.out.println("Compute with length 4: " + lineCounter + " lines"); 
     // Length 4 ########################################################### 
    } 

    private boolean check(double result, String operation) { 
     switch (operation) { 
      case "+": 
      case "-": 
      case "*": { 
       if (result > 0 && result <= 12) { 
        return true; 
       } 
       break; 
      } 
      case "/": { 
       if (
         (Math.floor(result) == result) 
         && (result >= 0 && result <= 12) 
       ) { 
        return true; 
       } 
       break; 
      } 
     } 

     return false; 
    } 

    private double perform(double first, String operation, double second) { 
     double result = 0.0; 
     switch (operation) { 
      case "+": { result = first + second; break; } 
      case "-": { result = first - second; break; } 
      case "*": { result = first * second; break; } 
      case "/": { result = first/second; break; } 
     } 

     return result; 
    } 

    private void computeResultAsString(StringBuilder sbDouble, String operation, double second, double result) { 
     sbDouble.append(operation); 
     sbDouble.append(second); 
     sbDouble.append("(="); 
     sbDouble.append(result); 
     sbDouble.append(")"); 
    } 

    private void computeResultAsString(StringBuilder sbDouble, double first, String operation, double second, double result) { 
     sbDouble.append(first); 
     sbDouble.append(operation); 
     sbDouble.append(second); 
     sbDouble.append("(="); 
     sbDouble.append(result); 
     sbDouble.append(")"); 
    } 

    public static void main(String[] args) { 
     final Generator generator = new Generator(); 
     generator.generate(); 
    } 
} 

回答

1

正如你可以在你自己的代碼中看到的,對於每個「長度」的增加,你必須嵌套另一個相同代碼塊。有了動態長度值,你不能這樣做。

因此,您將代碼塊移入一個方法中,並傳入一個參數,該參數有多少次要嵌套,即remainingLength。然後該方法可以調用自己的遞減值remainingLength,直到您達到0.

下面是一個示例,使用運算符enum

public static void generate(int length) { 
    if (length <= 0) 
     throw new IllegalArgumentException(); 
    StringBuilder expr = new StringBuilder(); 
    for (int number = 0; number <= 12; number++) { 
     expr.append(number); 
     generate(expr, number, length - 1); 
     expr.setLength(0); 
    } 
} 
private static void generate(StringBuilder expr, int exprTotal, int remainingLength) { 
    if (remainingLength == 0) { 
     System.out.println(expr); 
     return; 
    } 
    final int exprLength = expr.length(); 
    for (int number = 0; number <= 12; number++) { 
     if (number != exprTotal) { 
      for (Operator oper : Operator.values()) { 
       int total = oper.method.applyAsInt(exprTotal, number); 
       if (total >= 0 && total <= 12) { 
        expr.append(oper.symbol).append(number) 
         .append("(=").append(total).append(")"); 
        generate(expr, total, remainingLength - 1); 
        expr.setLength(exprLength); 
       } 
      } 
     } 
    } 
} 
private enum Operator { 
    PLUS ('+', Math::addExact), 
    MINUS ('-', Math::subtractExact), 
    MULTIPLY('*', Math::multiplyExact), 
    DIVIDE ('/', Operator::divide); 

    final char symbol; 
    final IntBinaryOperator method; 
    private Operator(char symbol, IntBinaryOperator method) { 
     this.symbol = symbol; 
     this.method = method; 
    } 
    private static int divide(int left, int right) { 
     if (right == 0 || left % right != 0) 
      return -1/*No exact integer value*/; 
     return left/right; 
    } 
} 

注意,置換的數量增長迅速:

1:   13 
2:   253 
3:   5,206 
4:  113,298 
5:  2,583,682 
6: 61,064,003 
7: 1,480,508,933 
+0

我喜歡在enum.A短的測試功能接口IntBinaryOperator的解決方案顯示,而不是檢查(!數= exprTotal)我可以使用(Math.random()<0.075)從計算結果中減少大量時間以生成計算和大小。 – Naoghuman

+0

@Naoghuman你不能刪除'number!= exprTotal'測試,因爲這是規則4的實現:*操作只允許不同的數字(一個操作有2個數字)。例如允許2 + 3,不允許3 * 3。* ---但是,如果你不需要所有的排列,你可以**添加** 7.5%的抽樣測試。 – Andreas