0

I've been trying to create a function in GDScript to process and calculate a string using PEMDAS rules. Below is my try on the subject. It can so far only use the MDAS rules:

Is there a better way to achieve such a function?

func _ready() -> void:
    ### USE CASES ###
    print(Compute_String("1+2*3+3="))    # Output = 10
    print(Compute_String("1+2*3*3="))    # Output = 19
    print(Compute_String("1*2*3+3="))    # Output = 9
    print(Compute_String("1+2+3*3="))    # Output = 12
    print(Compute_String("5*2+7-3/2="))  # Output = 15.5
    print(Compute_String("9+5.5*2.25=")) # Output = 21.375
    print(Compute_String("5*2+7-3/2"))   # Output = 1.#QNAN (Missing equals)
    print(Compute_String("5*2+7-/2="))   # Output = 1.#QNAN (Adjacent operators)
    print(Compute_String("*2+7-3/2="))   # Output = 1.#QNAN (Begins with operator)
    print(Compute_String(""))            # Output = 1.#QNAN (Empty)
    print(Compute_String("="))           # Output = 1.#QNAN (Considered as empty)
    print(Compute_String("1 +2="))       # Output = 1.#QNAN (Contains space)
    print(Compute_String("(1+2)*3="))    # Output = 1.#QNAN (Parentheses not supported)

func Compute_String(_string: String) -> float:
    var _result: float = NAN
    var _elements: Array = []
    if not _string.empty() and _string[_string.length() - 1] == "=":
        var _current_element: String = ""
        for _count in _string.length():
            if _string[_count].is_valid_float() or _string[_count] == ".": _current_element += _string[_count]
            else:
                if _string[_count - 1].is_valid_float() and (_string[_count + 1].is_valid_float() if _string[_count] != "=" else true):
                    _elements.append_array([_current_element,_string[_count]]) ; _current_element = ""
                else: return NAN
        if not _elements.empty():
            _elements.resize(_elements.size() - 1)
            while _get_operators_count(_elements) != 0:
                var _id: Array = [0, 0.0, 0.0]
                if "*" in _elements:
                    _id = _add_adjacent(_elements, "*") ; _remove_adjacent(_elements, _id[0]) ; _elements.insert(_id[0] - 1, _id[1] * _id[2])
                elif "/" in _elements:
                    _id = _add_adjacent(_elements, "/") ; _remove_adjacent(_elements, _id[0]) ; _elements.insert(_id[0] - 1, _id[1] / _id[2])
                elif "+" in _elements:
                    _id = _add_adjacent(_elements, "+") ; _remove_adjacent(_elements, _id[0]) ; _elements.insert(_id[0] - 1, _id[1] + _id[2])
                elif "-" in _elements:
                    _id = _add_adjacent(_elements, "-") ; _remove_adjacent(_elements, _id[0]) ; _elements.insert(_id[0] - 1, _id[1] - _id[2])
                else: return NAN
            if _elements.size() == 1: _result = _elements[0]
    return _result

func _get_operators_count(_elements: Array) -> int:
    var _result: int = 0 ; for _element in _elements: if not str(_element).is_valid_float(): _result += 1 ; return _result

func _add_adjacent(_elements: Array, _operator) -> Array:
    return [_elements.find(_operator), float(_elements[_elements.find(_operator) - 1]), float(_elements[_elements.find(_operator) + 1])]

func _remove_adjacent(_elements: Array, _operator_idx: int) -> void:
    _elements.remove(_operator_idx + 1) ; _elements.remove(_operator_idx) ; _elements.remove(_operator_idx - 1)
KanaszM
  • 151
  • 9
  • You could take a look at https://en.wikipedia.org/wiki/Operator-precedence_parser – H. Rittich Jul 28 '21 at 12:06
  • A note, you can evaluate math expressions in GDScript with the Expression class. https://docs.godotengine.org/en/stable/classes/class_expression.html#class-expression-method-parse – Joshua Anderson Oct 03 '21 at 04:08

0 Answers0