简体   繁体   English

通过递归创建具有预定义的基本数学运算

[英]Create with recursion basic mathematical operations with predefined definitions

I plan in JavaFX a new Game 'Number-Shape-System'. 我计划在JavaFX中开发一个新的游戏“数字形状系统”。 Basically its a little memory game where pictures are associated with numbers. 基本上是一个小记忆游戏,图片与数字相关。 So '2'='Swan', '5'='Hand(Fingers)' and so on. 所以'2'='Swan','5'='Hand(Fingers)'等。 So the player see the exercise 'Swan + Fingers = ?'. 因此,玩家看到了练习“天鹅+手指=?”。

What I want is all possible mathematically operations following rules: 我想要的是遵循规则的所有可能的数学运算:

/*
 * 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)
 */

I have prepared a example implementation, but I don't know how to convert it to a recursive functionality. 我已经准备了一个示例实现,但是我不知道如何将其转换为递归功能。

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();
    }
}

As you can see in your own code, for each increase in "length", you have to nest another block of the same code. 正如您在自己的代码中看到的那样,对于“长度”的每次增加,都必须嵌套相同代码的另一个块。 With a dynamic length value, you can't do that. 使用动态长度值,您将无法做到这一点。

Therefore, you move the block of code into a method, and pass in a parameter of how many more times it has to "nest", ie a remainingLength . 因此,您将代码块移到方法中,并传递一个参数,该参数必须将其“嵌套”多少次,即remainingLength长度。 Then the method can call itself with a decreasing value of remainingLength , until you get to 0. 然后,该方法可以使用减少的remainingLength值Length来调用自身,直到达到0。

Here is an example, using an enum for the operator. 这是一个为运算符使用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;
    }
}

Be aware that the number of permutations grow fast: 请注意,排列的数量会快速增长:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM