ProjectDDD/Assets/_Datas/SLShared/SLSystem/Evaluator.cs
2025-06-17 20:47:57 +09:00

135 lines
4.1 KiB (Stored with Git LFS)
C#

using System.Collections.Generic;
using System.Text.RegularExpressions;
using Superlazy;
public class Evaluator
{
public static string Evaluate(SLEntity player, string desc)
{
if (desc.StartsWith('$') == false) return desc;
// 변수 대체: {name} 패턴을 찾아 Global.Get으로 변환
var replacedDesc = Regex.Replace(desc.Substring(1), @"\{(\w+)\}", match =>
{
var varName = match.Groups[1].Value;
var ret = player["EventValues"].Get(varName); // 그냥 글로벌로 하면 변수 길어질듯해서
if (ret.IsValue && ret.IsNumeric == false) return $"\"{ret}\"";
return ret;
});
return EvaluateExpression(replacedDesc);
}
private static SLEntity EvaluateExpression(string expression)
{
var values = new Stack<SLEntity>(); // 값을 저장하는 스택 (숫자 또는 문자열)
var operators = new Stack<char>(); // 연산자를 저장하는 스택
var i = 0;
while (i < expression.Length)
{
if (char.IsDigit(expression[i])) // 숫자 처리
{
var number = "";
while (i < expression.Length && (char.IsDigit(expression[i]) || expression[i] == '.'))
{
number += expression[i];
i++;
}
values.Push(float.Parse(number));
}
else if (expression[i] == '"') // 문자열 처리
{
// 문자열 리터럴 처리 (큰 따옴표로 감싸진 문자열)
i++;
var str = "";
while (i < expression.Length && expression[i] != '"')
{
str += expression[i];
i++;
}
i++; // 닫는 따옴표 넘기기
values.Push(str);
}
else if (expression[i] == '(')
{
operators.Push('(');
i++;
}
else if (expression[i] == ')')
{
while (operators.Peek() != '(')
{
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
}
operators.Pop(); // '(' 제거
i++;
}
else if (IsOperator(expression[i]))
{
// 연산자 처리
while (operators.Count > 0 && GetPrecedence(operators.Peek()) >= GetPrecedence(expression[i]))
{
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
}
operators.Push(expression[i]);
i++;
}
else
{
// 공백 등 기타 문자는 그냥 넘김
i++;
}
}
while (operators.Count > 0)
{
values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop()));
}
return values.Pop();
}
// 연산자 우선순위
private static int GetPrecedence(char op)
{
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
// 연산자 확인
private static bool IsOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/';
}
// 연산자 적용
private static SLEntity ApplyOperator(SLEntity right, SLEntity left, char op)
{
return op switch
{
'+' => left + right,
'-' => left - right,
'*' => left * right,
'/' => left / right,
_ => SLEntity.Empty,
};
}
public static void ApplyEvaluate(SLEntity player, SLEntity current)
{
foreach (var c in current)
{
if (c.IsValue && c.IsNumeric == false)
{
current[c.ID] = Evaluate(player, c);
}
else if (c.IsValue == false)
{
ApplyEvaluate(player, c);
}
}
}
}