Оценщик формулы игры в кости - PullRequest
1 голос
/ 09 февраля 2020

Я написал пару функций, которые принимают отформатированную строку, определяют количество и размер кубиков, бросают их и добавляют их значения. Например: 3d8 означало бы бросить 3 кубика по 8 сторон каждая и добавить их значения. Значения всегда положительные, поэтому каждый раз, когда я запускаю эту функцию для 3d8 , я могу получить значения от 3 до 24.

    public int calcDice(String diceFormula){
        String[] divided = diceFormula.split("d");
        int cant = Integer.parseInt(divided[0]);
        int dice = Integer.parseInt(divided[1]);
        int result = 0;
        for (int i = 0; i < cant; i++) {
            result += throwDice(dice);
        }
        return result;
    }

    private int throwDice(int diceSize) {
        diceSize = diceSize < 0 ? dice * -1 : diceSize;
        Random r = new Random();
        return r.nextInt((diceSize - 1) + 1) + 1;
    }

Теперь мне нужно сделать математические функции, использующие эти значения, поэтому я мог бы ввести математическую функцию, которая будет вычисляться. Я должен был бы соблюдать порядок разрешения, например, ((3d8) +1) x (2d4) x 3

Одна из идей состояла в том, чтобы взять строку и обработать сначала значения, а затем заменить оценщик javascript, чтобы выяснить, результат, но я не уверен, как я могу "выбрать" значения. (Может быть, регулярное выражение?)

1 Ответ

0 голосов
/ 10 февраля 2020

Чтобы решить эту проблему, я реализовал функцию ShuntingYard, которая могла бы анализировать математические выражения

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ShuttingYard {

    private final Map<String, Integer> operators = new HashMap<>();

    public ShuttingYard(){
        operators.put("-", 0);
        operators.put("+", 0);
        operators.put("/", 1);
        operators.put("*", 1);
        operators.put("^", 2);
    }
    public double doTheShuntingYard(String expression)throws IllegalArgumentException, NumberFormatException, ArithmeticException{
        if(expression == null || expression.trim().length() == 0)
            throw new IllegalArgumentException("Empty expression or null");
        expression = expression.replaceAll("\\s+","");
        expression = expression.replace("(-", "(0-");
        if (expression.startsWith("-")){
            expression = "0" + expression;
        }
        Pattern pattern = Pattern.compile("((([0-9]*[.])?[0-9]+)|([\\+\\-\\*\\/\\(\\)\\^]))");
        Matcher matcher = pattern.matcher(expression);

        int counter = 0;
        List<String> tokens = new ArrayList<>();
        while(matcher.find()){
            if(matcher.start() != counter){
                throw new IllegalArgumentException("Invalid Expression:" + expression + ". Error between " + counter+ " end " + matcher.start());
            }
            tokens.add(matcher.group().trim());
            counter += tokens.get(tokens.size() - 1 ).length();
        }
        if(counter != expression.length()){
            throw new IllegalArgumentException("Invalid end of expression");
        }

        Stack<String> stack = new Stack<>();
        List<String> output = new ArrayList<>();

        for(String token : tokens){
            if(operators.containsKey(token)){
                while(!stack.empty() &&
                        operators.containsKey(stack.peek())&&
                        ((operators.get(token) <= operators.get(stack.peek()) && !token.equals("^"))||
                                (operators.get(token) < operators.get(stack.peek()) && token.equals("^")))){
                    output.add(stack.pop());
                }
                stack.push(token);

            }
            else if(token.equals("(")){
                stack.push(token);
            }
            else if(token.equals(")")){
                while(!stack.empty()){
                    if(!stack.peek().equals("(")){
                        output.add(stack.pop());
                    }
                    else{
                        break;
                    }
                }
                if(!stack.empty()){
                    stack.pop();
                }
            }
            else{
                output.add(token);
            }
        }

        while(!stack.empty()){
            output.add(stack.pop());
        }

        Stack<Double> doubles = new Stack<>();
        for(String token : output){
            if(!operators.containsKey(token) && token.matches("([0-9]*[.])?[0-9]+")){
                try{
                    doubles.push(Double.parseDouble(token));
                }
                catch(NumberFormatException n){
                    throw n;
                }
            }
            else{
                if(doubles.size() > 1){
                    double op1 = doubles.pop();
                    double op2 = doubles.pop();
                    switch (token) {
                        case "+":
                            doubles.push(op2 + op1);
                            break;
                        case "-":
                            doubles.push(op2 - op1);
                            break;
                        case "*":
                            doubles.push(op2 * op1);
                            break;
                        case "/":
                            if(op1 == 0){
                                throw new ArithmeticException("Division by 0");
                            }
                            doubles.push(Math.floor(op2 / op1));
                            break;
                        case "^":
                            doubles.push(Math.pow(op2, op1));
                            break;
                        default:
                            throw new IllegalArgumentException(token + " is not an operator or is not handled");
                    }
                }
            }
        }
        if(doubles.empty() || doubles.size() > 1){
            throw new IllegalArgumentException("Invalid expression, could not find a result. An operator seems to be absent");
        }
        return doubles.peek();
    }
}

Затем я бы вызвал эту функцию после разрешения операций throwDice

public class DiceThrower{

    private ShuttingYard shuttingYard;

    public DiceThrower(){
        this.shuttingYard = new ShuttingYard();
    }

    public void throwDiceAction(View view){

        TextView result = findViewById(R.id.diceResult);
        try{
            String original = ((EditText)findViewById(R.id.formula)).getText().toString();
            Pattern pattern = Pattern.compile("([0-9]{1,999})d([0-9]{1,999})");
            Matcher matcher = pattern.matcher(original);
            while(matcher.find()){
                original = matcher.replaceFirst(Integer.toString(calcDice(matcher.group(0))));
                matcher = pattern.matcher(original);
            }
            result.setText(evaluateExpression(original).split("\\.")[0]);
        }catch(ArithmeticException e){
            result.setText("This doesn't seem to be a valid mathematical expression");
        }


    }


    public String evaluateExpression(String expression){
        expression = expression.replaceAll("\\)\\(", ")*(");
        expression = expression.replaceAll("x", "*");
        return Double.toString(this.shuttingYard.doTheShuntingYard(expression));
    }

    public int calcDice(String formula){
        String[] divided = formula.split("d");
        int cant = Integer.parseInt(divided[0]);
        int dice = Integer.parseInt(divided[1]);
        int result = 0;
        for (int i = 0; i < cant; i++) {
            result += throwDice(dice);
        }
        return result;
    }

    private int throwDice(int dice) {
        dice = dice < 0 ? dice * -1 : dice;
        Random r = new Random();
        return r.nextInt((dice - 1) + 1) + 1;
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...