Make ConditionExpression use counts.

This commit is contained in:
atlimit8
2017-02-05 21:13:50 -06:00
parent d83dae5587
commit 65725efd04
5 changed files with 29 additions and 29 deletions

View File

@@ -222,21 +222,21 @@ namespace OpenRA.Support
return new VariableToken(start, expression.Substring(start)); return new VariableToken(start, expression.Substring(start));
} }
static bool ParseSymbol(VariableToken t, IReadOnlyDictionary<string, bool> symbols) static int ParseSymbol(VariableToken t, IReadOnlyDictionary<string, int> symbols)
{ {
bool value; int value;
symbols.TryGetValue(t.Symbol, out value); symbols.TryGetValue(t.Symbol, out value);
return value; return value;
} }
static void ApplyBinaryOperation(Stack<bool> s, Func<bool, bool, bool> f) static void ApplyBinaryOperation(Stack<int> s, Func<int, int, int> f)
{ {
var x = s.Pop(); var x = s.Pop();
var y = s.Pop(); var y = s.Pop();
s.Push(f(x, y)); s.Push(f(x, y));
} }
static void ApplyUnaryOperation(Stack<bool> s, Func<bool, bool> f) static void ApplyUnaryOperation(Stack<int> s, Func<int, int> f)
{ {
var x = s.Pop(); var x = s.Pop();
s.Push(f(x)); s.Push(f(x));
@@ -271,21 +271,21 @@ namespace OpenRA.Support
yield return s.Pop(); yield return s.Pop();
} }
public bool Evaluate(IReadOnlyDictionary<string, bool> symbols) public int Evaluate(IReadOnlyDictionary<string, int> symbols)
{ {
var s = new Stack<bool>(); var s = new Stack<int>();
foreach (var t in postfix) foreach (var t in postfix)
{ {
if (t is AndToken) if (t is AndToken)
ApplyBinaryOperation(s, (x, y) => y & x); ApplyBinaryOperation(s, (x, y) => y > 0 ? x : y);
else if (t is NotEqualsToken) else if (t is NotEqualsToken)
ApplyBinaryOperation(s, (x, y) => y ^ x); ApplyBinaryOperation(s, (x, y) => (y != x) ? 1 : 0);
else if (t is OrToken) else if (t is OrToken)
ApplyBinaryOperation(s, (x, y) => y | x); ApplyBinaryOperation(s, (x, y) => y > 0 ? y : x);
else if (t is EqualsToken) else if (t is EqualsToken)
ApplyBinaryOperation(s, (x, y) => y == x); ApplyBinaryOperation(s, (x, y) => (y == x) ? 1 : 0);
else if (t is NotToken) else if (t is NotToken)
ApplyUnaryOperation(s, x => !x); ApplyUnaryOperation(s, x => (x > 0) ? 0 : 1);
else if (t is VariableToken) else if (t is VariableToken)
s.Push(ParseSymbol((VariableToken)t, symbols)); s.Push(ParseSymbol((VariableToken)t, symbols));
} }

View File

@@ -72,15 +72,15 @@ namespace OpenRA.Mods.Common.Traits
int nextToken = 1; int nextToken = 1;
/// <summary>Cache of condition -> enabled state for quick evaluation of boolean conditions.</summary> /// <summary>Cache of condition -> enabled state for quick evaluation of boolean conditions.</summary>
readonly Dictionary<string, bool> conditionCache = new Dictionary<string, bool>(); readonly Dictionary<string, int> conditionCache = new Dictionary<string, int>();
/// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary> /// <summary>Read-only version of conditionCache that is passed to IConditionConsumers.</summary>
IReadOnlyDictionary<string, bool> readOnlyConditionCache; IReadOnlyDictionary<string, int> readOnlyConditionCache;
void INotifyCreated.Created(Actor self) void INotifyCreated.Created(Actor self)
{ {
state = new Dictionary<string, ConditionState>(); state = new Dictionary<string, ConditionState>();
readOnlyConditionCache = new ReadOnlyDictionary<string, bool>(conditionCache); readOnlyConditionCache = new ReadOnlyDictionary<string, int>(conditionCache);
var allConsumers = new HashSet<IConditionConsumer>(); var allConsumers = new HashSet<IConditionConsumer>();
var allWatchers = self.TraitsImplementing<IConditionTimerWatcher>().ToList(); var allWatchers = self.TraitsImplementing<IConditionTimerWatcher>().ToList();
@@ -96,7 +96,7 @@ namespace OpenRA.Mods.Common.Traits
if (w.Condition == condition) if (w.Condition == condition)
cs.Watchers.Add(w); cs.Watchers.Add(w);
conditionCache[condition] = false; conditionCache[condition] = 0;
} }
} }
@@ -108,7 +108,7 @@ namespace OpenRA.Mods.Common.Traits
continue; continue;
conditionState.Tokens.Add(kv.Key); conditionState.Tokens.Add(kv.Key);
conditionCache[kv.Value] = conditionState.Tokens.Count > 0; conditionCache[kv.Value] = conditionState.Tokens.Count;
} }
foreach (var sc in self.Info.TraitInfos<StackedConditionInfo>()) foreach (var sc in self.Info.TraitInfos<StackedConditionInfo>())
@@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Traits
else else
conditionState.Tokens.Add(token); conditionState.Tokens.Add(token);
conditionCache[condition] = conditionState.Tokens.Count > 0; conditionCache[condition] = conditionState.Tokens.Count;
foreach (var t in conditionState.Consumers) foreach (var t in conditionState.Consumers)
t.ConditionsChanged(self, readOnlyConditionCache); t.ConditionsChanged(self, readOnlyConditionCache);

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits
/// <summary>Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.)</summary> /// <summary>Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.)</summary>
public abstract class ConditionalTraitInfo : IConditionConsumerInfo, IRulesetLoaded public abstract class ConditionalTraitInfo : IConditionConsumerInfo, IRulesetLoaded
{ {
static readonly IReadOnlyDictionary<string, bool> NoConditions = new ReadOnlyDictionary<string, bool>(new Dictionary<string, bool>()); static readonly IReadOnlyDictionary<string, int> NoConditions = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>());
[ConsumedConditionReference] [ConsumedConditionReference]
[Desc("Boolean expression defining the condition to enable this trait.")] [Desc("Boolean expression defining the condition to enable this trait.")]
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits
public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai) public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai)
{ {
EnabledByDefault = RequiresCondition != null ? RequiresCondition.Evaluate(NoConditions) : true; EnabledByDefault = RequiresCondition != null ? RequiresCondition.Evaluate(NoConditions) > 0 : true;
} }
} }
@@ -77,13 +77,13 @@ namespace OpenRA.Mods.Common.Traits
void INotifyCreated.Created(Actor self) { Created(self); } void INotifyCreated.Created(Actor self) { Created(self); }
void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary<string, bool> conditions) void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions)
{ {
if (Info.RequiresCondition == null) if (Info.RequiresCondition == null)
return; return;
var wasDisabled = IsTraitDisabled; var wasDisabled = IsTraitDisabled;
IsTraitDisabled = !Info.RequiresCondition.Evaluate(conditions); IsTraitDisabled = Info.RequiresCondition.Evaluate(conditions) <= 0;
if (IsTraitDisabled != wasDisabled) if (IsTraitDisabled != wasDisabled)
{ {

View File

@@ -110,7 +110,7 @@ namespace OpenRA.Mods.Common.Traits
public interface IConditionConsumer public interface IConditionConsumer
{ {
IEnumerable<string> Conditions { get; } IEnumerable<string> Conditions { get; }
void ConditionsChanged(Actor self, IReadOnlyDictionary<string, bool> conditions); void ConditionsChanged(Actor self, IReadOnlyDictionary<string, int> conditions);
} }
public interface INotifyHarvesterAction public interface INotifyHarvesterAction

View File

@@ -21,20 +21,20 @@ namespace OpenRA.Test
[TestFixture] [TestFixture]
public class ConditionExpressionTest public class ConditionExpressionTest
{ {
IReadOnlyDictionary<string, bool> testValues = new ReadOnlyDictionary<string, bool>(new Dictionary<string, bool>() IReadOnlyDictionary<string, int> testValues = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>()
{ {
{ "true", true }, { "true", 1 },
{ "false", false } { "false", 0 }
}); });
void AssertFalse(string expression) void AssertFalse(string expression)
{ {
Assert.False(new ConditionExpression(expression).Evaluate(testValues), expression); Assert.False(new ConditionExpression(expression).Evaluate(testValues) > 0, expression);
} }
void AssertTrue(string expression) void AssertTrue(string expression)
{ {
Assert.True(new ConditionExpression(expression).Evaluate(testValues), expression); Assert.True(new ConditionExpression(expression).Evaluate(testValues) > 0, expression);
} }
void AssertParseFailure(string expression) void AssertParseFailure(string expression)
@@ -69,7 +69,7 @@ namespace OpenRA.Test
AssertFalse("false == true"); AssertFalse("false == true");
} }
[TestCase(TestName = "Not-equals (XOR) operation")] [TestCase(TestName = "Not-equals operation")]
public void TestNotEquals() public void TestNotEquals()
{ {
AssertFalse("true != true"); AssertFalse("true != true");
@@ -141,7 +141,7 @@ namespace OpenRA.Test
AssertParseFailure("false ||"); AssertParseFailure("false ||");
} }
[TestCase(TestName = "Undefined symbols are treated as `false` values")] [TestCase(TestName = "Undefined symbols are treated as `false` (0) values")]
public void TestUndefinedSymbols() public void TestUndefinedSymbols()
{ {
AssertFalse("undef1 || undef2"); AssertFalse("undef1 || undef2");