diff --git a/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs b/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs index 3f6786bb5c..59f1ef4781 100644 --- a/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs +++ b/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2012 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, @@ -10,64 +10,65 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using AI.Fuzzy.Library; using OpenRA.Mods.RA.Move; using OpenRA.Traits; -using AI.Fuzzy.Library; namespace OpenRA.Mods.RA.AI { class AttackOrFleeFuzzy { - protected MamdaniFuzzySystem fuzzyEngine; - protected Dictionary result; - - public bool CanAttack - { - get - { - //not sure that this will happen (NaN), it's for the safety of - if (result[fuzzyEngine.OutputByName("AttackOrFlee")].ToString() != "NaN") - return result[fuzzyEngine.OutputByName("AttackOrFlee")] < 30.0; - return false; - } - } + MamdaniFuzzySystem fuzzyEngine; + Dictionary result; public AttackOrFleeFuzzy() { InitializateFuzzyVariables(); } + public bool CanAttack + { + get + { + var attackChance = result[fuzzyEngine.OutputByName("AttackOrFlee")]; + return !double.IsNaN(attackChance) && attackChance < 30.0; + } + } + + protected void AddFuzzyRule(string rule) + { + fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule(rule)); + } + protected void InitializateFuzzyVariables() { fuzzyEngine = new MamdaniFuzzySystem(); - FuzzyVariable playerHealthFuzzy = new FuzzyVariable("OwnHealth", 0.0, 100.0); + var playerHealthFuzzy = new FuzzyVariable("OwnHealth", 0.0, 100.0); playerHealthFuzzy.Terms.Add(new FuzzyTerm("NearDead", new TrapezoidMembershipFunction(0, 0, 20, 40))); playerHealthFuzzy.Terms.Add(new FuzzyTerm("Injured", new TrapezoidMembershipFunction(30, 50, 50, 70))); playerHealthFuzzy.Terms.Add(new FuzzyTerm("Normal", new TrapezoidMembershipFunction(50, 80, 100, 100))); fuzzyEngine.Input.Add(playerHealthFuzzy); - FuzzyVariable enemyHealthFuzzy = new FuzzyVariable("EnemyHealth", 0.0, 100.0); + var enemyHealthFuzzy = new FuzzyVariable("EnemyHealth", 0.0, 100.0); enemyHealthFuzzy.Terms.Add(new FuzzyTerm("NearDead", new TrapezoidMembershipFunction(0, 0, 20, 40))); enemyHealthFuzzy.Terms.Add(new FuzzyTerm("Injured", new TrapezoidMembershipFunction(30, 50, 50, 70))); enemyHealthFuzzy.Terms.Add(new FuzzyTerm("Normal", new TrapezoidMembershipFunction(50, 80, 100, 100))); fuzzyEngine.Input.Add(enemyHealthFuzzy); - FuzzyVariable relativeAttackPowerFuzzy = new FuzzyVariable("RelativeAttackPower", 0.0, 1000.0); + var relativeAttackPowerFuzzy = new FuzzyVariable("RelativeAttackPower", 0.0, 1000.0); relativeAttackPowerFuzzy.Terms.Add(new FuzzyTerm("Weak", new TrapezoidMembershipFunction(0, 0, 70, 90))); relativeAttackPowerFuzzy.Terms.Add(new FuzzyTerm("Equal", new TrapezoidMembershipFunction(85, 100, 100, 115))); relativeAttackPowerFuzzy.Terms.Add(new FuzzyTerm("Strong", new TrapezoidMembershipFunction(110, 150, 150, 1000))); fuzzyEngine.Input.Add(relativeAttackPowerFuzzy); - FuzzyVariable relativeSpeedFuzzy = new FuzzyVariable("RelativeSpeed", 0.0, 1000.0); + var relativeSpeedFuzzy = new FuzzyVariable("RelativeSpeed", 0.0, 1000.0); relativeSpeedFuzzy.Terms.Add(new FuzzyTerm("Slow", new TrapezoidMembershipFunction(0, 0, 70, 90))); relativeSpeedFuzzy.Terms.Add(new FuzzyTerm("Equal", new TrapezoidMembershipFunction(85, 100, 100, 115))); relativeSpeedFuzzy.Terms.Add(new FuzzyTerm("Fast", new TrapezoidMembershipFunction(110, 150, 150, 1000))); fuzzyEngine.Input.Add(relativeSpeedFuzzy); - FuzzyVariable attackOrFleeFuzzy = new FuzzyVariable("AttackOrFlee", 0.0, 50.0); + var attackOrFleeFuzzy = new FuzzyVariable("AttackOrFlee", 0.0, 50.0); attackOrFleeFuzzy.Terms.Add(new FuzzyTerm("Attack", new TrapezoidMembershipFunction(0, 15, 15, 30))); attackOrFleeFuzzy.Terms.Add(new FuzzyTerm("Flee", new TrapezoidMembershipFunction(25, 35, 35, 50))); fuzzyEngine.Output.Add(attackOrFleeFuzzy); @@ -79,100 +80,94 @@ namespace OpenRA.Mods.RA.AI protected virtual void AddingRulesForNormalOwnHealth() { - //1 OwnHealth is Normal - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Normal) " + - "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Normal) " + + "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Attack"); } protected virtual void AddingRulesForInjuredOwnHealth() { - //OwnHealth is Injured - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Injured) " + - "and (EnemyHealth is NearDead) " + - "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Injured) " + + "and (EnemyHealth is NearDead) " + + "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Attack"); - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Injured) " + - "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and ((RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Injured) " + + "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and ((RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Attack"); - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Injured) " + - "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and (RelativeAttackPower is Weak) " + - "and (RelativeSpeed is Slow)) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Injured) " + + "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and (RelativeAttackPower is Weak) " + + "and (RelativeSpeed is Slow)) " + + "then AttackOrFlee is Attack"); - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Injured) " + - "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and (RelativeAttackPower is Weak) " + - "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is Injured) " + + "and ((EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and (RelativeAttackPower is Weak) " + + "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Flee"); - //2 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Injured) " + - "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + - "and (RelativeSpeed is Slow)) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Injured) " + + "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal) or (RelativeAttackPower is Strong)) " + + "and (RelativeSpeed is Slow)) " + + "then AttackOrFlee is Attack"); } protected virtual void AddingRulesForNearDeadOwnHealth() { - //3 OwnHealth is NearDead - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is NearDead) " + - "and (EnemyHealth is Injured) " + - "and (RelativeAttackPower is Equal) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal))) " + - "then AttackOrFlee is Attack")); - //4 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is NearDead) " + - "and (EnemyHealth is NearDead) " + - "and (RelativeAttackPower is Weak) " + - "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Flee")); - //5 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is NearDead) " + - "and (EnemyHealth is Injured) " + - "and (RelativeAttackPower is Weak) " + - "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is NearDead) " + + "and (EnemyHealth is Injured) " + + "and (RelativeAttackPower is Equal) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal))) " + + "then AttackOrFlee is Attack"); - //6 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is NearDead) " + - "and (EnemyHealth is Normal) " + - "and (RelativeAttackPower is Weak) " + - "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is NearDead) " + + "and (EnemyHealth is NearDead) " + + "and (RelativeAttackPower is Weak) " + + "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Flee"); - //7 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if (OwnHealth is NearDead) " + - "and (EnemyHealth is Normal) " + - "and (RelativeAttackPower is Equal) " + - "and (RelativeSpeed is Fast) " + - "then AttackOrFlee is Flee")); - //8 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if (OwnHealth is NearDead) " + - "and (EnemyHealth is Normal) " + - "and (RelativeAttackPower is Strong) " + - "and (RelativeSpeed is Fast) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is NearDead) " + + "and (EnemyHealth is Injured) " + + "and (RelativeAttackPower is Weak) " + + "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Flee"); - //9 - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if (OwnHealth is NearDead) " + - "and (EnemyHealth is Injured) " + - "and (RelativeAttackPower is Equal) " + - "and (RelativeSpeed is Fast) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is NearDead) " + + "and (EnemyHealth is Normal) " + + "and (RelativeAttackPower is Weak) " + + "and ((RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Flee"); + + AddFuzzyRule("if (OwnHealth is NearDead) " + + "and (EnemyHealth is Normal) " + + "and (RelativeAttackPower is Equal) " + + "and (RelativeSpeed is Fast) " + + "then AttackOrFlee is Flee"); + + AddFuzzyRule("if (OwnHealth is NearDead) " + + "and (EnemyHealth is Normal) " + + "and (RelativeAttackPower is Strong) " + + "and (RelativeSpeed is Fast) " + + "then AttackOrFlee is Flee"); + + AddFuzzyRule("if (OwnHealth is NearDead) " + + "and (EnemyHealth is Injured) " + + "and (RelativeAttackPower is Equal) " + + "and (RelativeSpeed is Fast) " + + "then AttackOrFlee is Flee"); } + public void CalculateFuzzy(List ownUnits, List enemyUnits) { - Dictionary inputValues = new Dictionary(); + var inputValues = new Dictionary(); inputValues.Add(fuzzyEngine.InputByName("OwnHealth"), (double)NormalizedHealth(ownUnits, 100)); inputValues.Add(fuzzyEngine.InputByName("EnemyHealth"), (double)NormalizedHealth(enemyUnits, 100)); inputValues.Add(fuzzyEngine.InputByName("RelativeAttackPower"), (double)RelativePower(ownUnits, enemyUnits)); @@ -183,15 +178,20 @@ namespace OpenRA.Mods.RA.AI protected float NormalizedHealth(List actors, float normalizeByValue) { - int sumOfMaxHp = 0; - int sumOfHp = 0; + var sumOfMaxHp = 0; + var sumOfHp = 0; foreach (var a in actors) + { if (a.HasTrait()) { sumOfMaxHp += a.Trait().MaxHP; sumOfHp += a.Trait().HP; } - if (sumOfMaxHp == 0) return 0.0f; + } + + if (sumOfMaxHp == 0) + return 0.0f; + return (sumOfHp * normalizeByValue) / sumOfMaxHp; } @@ -218,33 +218,40 @@ namespace OpenRA.Mods.RA.AI { if (enemy.Count == 0) return 999.0f; + if (own.Count == 0) return 0.0f; - float relative = (relativeFunc(own, getValue) / relativeFunc(enemy, getValue)) * normalizeByValue; + var relative = (relativeFunc(own, getValue) / relativeFunc(enemy, getValue)) * normalizeByValue; return relative.Clamp(0.0f, 999.0f); } protected float SumOfValues(List actors, Func getValue) { - int sum = 0; + var sum = 0; foreach (var a in actors) if (a.HasTrait()) sum += getValue(a); + return sum; } protected float Average(List actors, Func getValue) { - int sum = 0; - int countActors = 0; + var sum = 0; + var countActors = 0; foreach (var a in actors) + { if (a.HasTrait()) { sum += getValue(a); countActors++; } - if (countActors == 0) return 0.0f; + } + + if (countActors == 0) + return 0.0f; + return sum / countActors; } } diff --git a/OpenRA.Mods.RA/AI/RushFuzzy.cs b/OpenRA.Mods.RA/AI/RushFuzzy.cs index 5d6925763d..afe43e8624 100644 --- a/OpenRA.Mods.RA/AI/RushFuzzy.cs +++ b/OpenRA.Mods.RA/AI/RushFuzzy.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, @@ -8,12 +8,6 @@ */ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using AI.Fuzzy.Library; - namespace OpenRA.Mods.RA.AI { class RushFuzzy : AttackOrFleeFuzzy @@ -22,18 +16,17 @@ namespace OpenRA.Mods.RA.AI protected override void AddingRulesForNormalOwnHealth() { - //1 OwnHealth is Normal - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Normal) " + - "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and (RelativeAttackPower is Strong) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Attack")); + AddFuzzyRule("if ((OwnHealth is Normal) " + + "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and (RelativeAttackPower is Strong) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Attack"); - fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule("if ((OwnHealth is Normal) " + - "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + - "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal)) " + - "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + - "then AttackOrFlee is Flee")); + AddFuzzyRule("if ((OwnHealth is Normal) " + + "and ((EnemyHealth is NearDead) or (EnemyHealth is Injured) or (EnemyHealth is Normal)) " + + "and ((RelativeAttackPower is Weak) or (RelativeAttackPower is Equal)) " + + "and ((RelativeSpeed is Slow) or (RelativeSpeed is Equal) or (RelativeSpeed is Fast))) " + + "then AttackOrFlee is Flee"); } } }