using System; using System.Collections.Generic; using System.Numerics; using UnityEngine; public class ProgrammerCalculator : MonoBehaviour { public int CurrentBase { get; private set; } = 10; public void SetBase(int b) { CurrentBase = b; } // ===== PUBLIC API ===== public string Evaluate(string expression) { var tokens = Tokenize(expression); print(tokens); foreach (var token in tokens) print(token); var rpn = ToRPN(tokens); print(rpn); foreach (var rpnn in rpn) print(rpnn); BigInteger result = EvalRPN(rpn); print(result); return ToBaseString(result, CurrentBase); } // ===== TOKENIZER ===== private List Tokenize(string expr) { List tokens = new List(); string num = ""; foreach (char c in expr.ToUpper()) { if (char.IsLetterOrDigit(c)) { num += c; } else if ("+-*/()".Contains(c)) { if (num != "") { tokens.Add(num); num = ""; } tokens.Add(c.ToString()); } } if (num != "") tokens.Add(num); return tokens; } // ===== SHUNTING YARD ===== private int Precedence(string op) { return (op == "+" || op == "-") ? 1 : (op == "*" || op == "/") ? 2 : 0; } private List ToRPN(List tokens) { List output = new List(); Stack ops = new Stack(); foreach (var t in tokens) { if (IsNumber(t)) { output.Add(t); } else if ("+-*/".Contains(t)) { while (ops.Count > 0 && Precedence(ops.Peek()) >= Precedence(t)) output.Add(ops.Pop()); ops.Push(t); } else if (t == "(") { ops.Push(t); } else if (t == ")") { while (ops.Peek() != "(") output.Add(ops.Pop()); ops.Pop(); } } while (ops.Count > 0) output.Add(ops.Pop()); return output; } // ===== RPN EVALUATION ===== private BigInteger EvalRPN(List rpn) { Stack stack = new Stack(); foreach (var t in rpn) { if (IsNumber(t)) { stack.Push(ParseNumber(t)); } else { BigInteger b = stack.Pop(); BigInteger a = stack.Pop(); stack.Push(ApplyOp(a, b, t)); } } return stack.Pop(); } private BigInteger ApplyOp(BigInteger a, BigInteger b, string op) { return op switch { "+" => a + b, "-" => a - b, "*" => a * b, "/" => b == 0 ? 0 : a / b, _ => 0 }; } // ===== NUMBER UTILS ===== private bool IsNumber(string s) { foreach (char c in s) { if (!char.IsDigit(c) && !(c >= 'A' && c <= 'F')) return false; } return true; } private BigInteger ParseNumber(string s) { switch (CurrentBase) { case 16: return BigInteger.Parse(s, System.Globalization.NumberStyles.HexNumber); case 10: return BigInteger.Parse(s); case 8: return ParseBase(s, 8); case 2: return ParseBase(s, 2); default: throw new Exception("Unsupported base"); } } // Вспомогательный метод для base 2 и 8 private BigInteger ParseBase(string s, int b) { BigInteger result = 0; foreach (char c in s) { int digit = c - '0'; if (digit >= b) throw new Exception("Invalid digit for base " + b); result = result * b + digit; } return result; } private string ToBaseString(BigInteger val, int b) { if (b == 10) return val.ToString(); if (val == 0) return "0"; bool neg = val < 0; if (neg) val = BigInteger.Abs(val); string digits = "0123456789ABCDEF"; string result = ""; while (val > 0) { int d = (int)(val % b); result = digits[d] + result; val /= b; } return neg ? "-" + result : result; } }