changeset 465:7b9ff7b1df24

Re #394: Make requirements (or factory) more closely match Rollcall methods * Make UnitRequiresAtLeastNUnitsRequirementFactory handle "alternatives" (Rollcall's "-1,X|Y" notation) * Make RequiresAtLeastNUnitsRequirement handle alternatives/multiple unit types in one limit * Move some useful code up the classes
author IBBoard <dev@ibboard.co.uk>
date Sat, 24 Mar 2012 20:33:11 +0000
parents 59e1fb8a476a
children bdfa314789cc
files API/Factories/Requirement/UnitRequiresAtLeastNUnitsRequirementFactory.cs API/Objects/Requirement/AbstractUnitRequirement.cs API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs API/Objects/Requirement/RequiresNUnitsForMObjectsRequirement.cs
diffstat 4 files changed, 96 insertions(+), 51 deletions(-) [+]
line diff
     1.1 --- a/API/Factories/Requirement/UnitRequiresAtLeastNUnitsRequirementFactory.cs	Sat Mar 24 16:40:01 2012 +0000
     1.2 +++ b/API/Factories/Requirement/UnitRequiresAtLeastNUnitsRequirementFactory.cs	Sat Mar 24 20:33:11 2012 +0000
     1.3 @@ -4,6 +4,7 @@
     1.4  using System;
     1.5  using IBBoard.WarFoundry.API.Objects;
     1.6  using IBBoard.WarFoundry.API.Objects.Requirement;
     1.7 +using System.Collections.Generic;
     1.8  
     1.9  namespace IBBoard.WarFoundry.API.Factories.Requirement
    1.10  {
    1.11 @@ -28,8 +29,10 @@
    1.12  			//Do nothing special
    1.13  		}
    1.14  
    1.15 -		public string AppliesToID {
    1.16 -			get {
    1.17 +		public string AppliesToID
    1.18 +		{
    1.19 +			get
    1.20 +			{
    1.21  				return UnitRequiresAtLeastNUnitsRequirement.REQUIREMENT_ID;
    1.22  			}
    1.23  		}
    1.24 @@ -47,13 +50,8 @@
    1.25  			foreach (string requirement in data.Split('|'))
    1.26  			{
    1.27  				string[] requirementParts = requirement.Split(':');
    1.28 -				string unitID = requirementParts[0];
    1.29 -				UnitType unitType = raceFactory.GetUnitType(unitID, race);
    1.30 -
    1.31 -				if (unitType == null)
    1.32 -				{
    1.33 -					throw new InvalidRequirementException(String.Format("Invalid unit type '{0}' for 'Requires at least N units' requirement", unitID));
    1.34 -				}
    1.35 +				string unitIDs = requirementParts[0];
    1.36 +				UnitType[] unitTypes = GetUnitTypes(unitIDs, race, raceFactory);
    1.37  
    1.38  				if (requirementParts.Length == 2)
    1.39  				{
    1.40 @@ -61,19 +59,38 @@
    1.41  
    1.42  					try
    1.43  					{
    1.44 -						req.AddUnitTypeRequirement(unitType, Int32.Parse(amount));
    1.45 +						req.AddUnitTypeRequirement(Int32.Parse(amount), unitTypes);
    1.46  					}
    1.47  					catch (FormatException)
    1.48  					{
    1.49 -						throw new InvalidRequirementException(String.Format("Invalid amount '{0}' for unit type '{1}' for 'Requires at least N units' requirement", amount, unitID));
    1.50 +						throw new InvalidRequirementException(String.Format("Invalid amount '{0}' for unit types '{1}' for 'Requires at least N units' requirement", amount, unitIDs));
    1.51  					}
    1.52  				}
    1.53  				else
    1.54  				{
    1.55 -					req.AddUnitTypeRequirement(unitType);
    1.56 +					req.AddUnitTypeRequirement(unitTypes);
    1.57  				}
    1.58  			}
    1.59  		}
    1.60 +
    1.61 +		private UnitType[] GetUnitTypes<SOURCE_FILE_TYPE, ENTRY_TYPE>(string data, Race race, IRaceFactory<SOURCE_FILE_TYPE, ENTRY_TYPE> raceFactory)
    1.62 +		{
    1.63 +			List<UnitType> unitTypes = new List<UnitType>();
    1.64 +
    1.65 +			foreach (string unitID in data.Split(';'))
    1.66 +			{
    1.67 +				UnitType unitType = raceFactory.GetUnitType(unitID, race);
    1.68 +	
    1.69 +				if (unitType == null)
    1.70 +				{
    1.71 +					throw new InvalidRequirementException(String.Format("Invalid unit type '{0}' for 'Requires at least N units' requirement", unitID));
    1.72 +				}
    1.73 +
    1.74 +				unitTypes.Add(unitType);
    1.75 +			}
    1.76 +
    1.77 +			return unitTypes.ToArray();
    1.78 +		}
    1.79  	}
    1.80  }
    1.81  
     2.1 --- a/API/Objects/Requirement/AbstractUnitRequirement.cs	Sat Mar 24 16:40:01 2012 +0000
     2.2 +++ b/API/Objects/Requirement/AbstractUnitRequirement.cs	Sat Mar 24 20:33:11 2012 +0000
     2.3 @@ -157,6 +157,23 @@
     2.4  			return toArmy.GetUnitTypeCount(unitType) + GetCountFromObject(wfObject, unitType);
     2.5  		}
     2.6  
     2.7 +		protected int GetUnitTypesCount(Army army, UnitType[] unitTypes)
     2.8 +		{
     2.9 +			return GetUnitTypesCount(army, unitTypes, null);
    2.10 +		}
    2.11 +
    2.12 +		protected int GetUnitTypesCount(Army toArmy, UnitType[] unitTypes, IWarFoundryObject wfObject)
    2.13 +		{
    2.14 +			int count = 0;
    2.15 +
    2.16 +			foreach (UnitType unitType in unitTypes)
    2.17 +			{
    2.18 +				count += GetUnitTypeCount(toArmy, unitType, wfObject);
    2.19 +			}
    2.20 +
    2.21 +			return count;
    2.22 +		}
    2.23 +
    2.24  		protected int GetCountFromObject(IWarFoundryObject wfObject, UnitType limitedType)
    2.25  		{
    2.26  			return (limitedType.Equals(wfObject) || (wfObject is Unit && ((Unit)wfObject).UnitType.Equals(limitedType))) ? 1 : 0;
    2.27 @@ -177,6 +194,19 @@
    2.28  		}
    2.29  
    2.30  		public OBJECT_TYPE AllowedObject { get { return allowedObject; } }
    2.31 +
    2.32 +		protected string GetUnitTypeList(UnitCountRequirementData limit)
    2.33 +		{
    2.34 +			List<String> namesList = new List<String>();
    2.35 +
    2.36 +			foreach (UnitType unitType in limit.UnitTypes)
    2.37 +			{
    2.38 +				namesList.Add(unitType.Name);
    2.39 +			}
    2.40 +
    2.41 +			string[] names = namesList.ToArray();
    2.42 +			return String.Join(" or ", names);
    2.43 +		}
    2.44  	}
    2.45  }
    2.46  
     3.1 --- a/API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs	Sat Mar 24 16:40:01 2012 +0000
     3.2 +++ b/API/Objects/Requirement/RequiresAtLeastNUnitsRequirement.cs	Sat Mar 24 20:33:11 2012 +0000
     3.3 @@ -85,7 +85,7 @@
     3.4  			
     3.5  			foreach (UnitCountRequirementData requirement in ConstraintTypes)
     3.6  			{
     3.7 -				if (GetUnitTypeCount(toArmy, requirement.UnitType, wfObject) < requirement.Count)
     3.8 +				if (GetUnitTypesCount(toArmy, requirement.UnitTypes, wfObject) < requirement.Count)
     3.9  				{
    3.10  					isValid = Validation.Failed;
    3.11  					break;
    3.12 @@ -96,7 +96,7 @@
    3.13  		}
    3.14  
    3.15  		/// <summary>
    3.16 -		/// Adds a requirement for there to be at least minCount of a given UnitType
    3.17 +		/// Adds a requirement for there to be at least minCount of a given UnitType, allowing any number of of this UnitType.
    3.18  		/// </summary>
    3.19  		/// <param name='unitType'>
    3.20  		/// The unit type to require.
    3.21 @@ -106,11 +106,11 @@
    3.22  		/// </param>
    3.23  		public void AddUnitTypeRequirement(UnitType unitType, int minCount)
    3.24  		{
    3.25 -			ConstraintTypes.Add(new UnitCountRequirementData(unitType, minCount));
    3.26 +			AddUnitTypeRequirement(minCount, unitType);
    3.27  		}
    3.28  
    3.29  		/// <summary>
    3.30 -		/// Adds a requirement for there to be one or more of a given UnitType
    3.31 +		/// Adds a requirement for there to be one or more of a given UnitType, allowing any number of of this UnitType.
    3.32  		/// </summary>
    3.33  		/// <param name='unitType'>
    3.34  		/// The unit type to require.
    3.35 @@ -121,6 +121,34 @@
    3.36  		}
    3.37  
    3.38  		/// <summary>
    3.39 +		/// Adds a requirement for there to be one or more of the given UnitTypes, allowing any number of of this UnitType. If multiple unit types
    3.40 +		/// are supplied here then they are treated as alternatives (so "unitType1, unitType2" requires one of either type).
    3.41 +		/// </summary>
    3.42 +		/// <param name='unitType'>
    3.43 +		/// The unit type or types to require.
    3.44 +		/// </param>
    3.45 +		public void AddUnitTypeRequirement(params UnitType[] unitTypes)
    3.46 +		{
    3.47 +			AddUnitTypeRequirement(1, unitTypes);
    3.48 +		}
    3.49 +
    3.50 +		/// <summary>
    3.51 +		/// Adds a requirement for there to be minCount or more of the given UnitTypes, allowing any number of of this UnitType. If multiple unit types
    3.52 +		/// are supplied here then they are treated as alternatives (so "unitType1, unitType2" requires one of either type).
    3.53 +		/// </summary>
    3.54 +		/// <param name="minCount">
    3.55 +		/// The number of units to be allowed for each 1 of unitType
    3.56 +		/// </param>
    3.57 +		/// <param name='unitType'>
    3.58 +		/// The unit type or types to require.
    3.59 +		/// </param>
    3.60 +		public void AddUnitTypeRequirement(int minCount, params UnitType[] unitTypes)
    3.61 +		{
    3.62 +			ConstraintTypes.Add(new UnitCountRequirementData(unitTypes, minCount));
    3.63 +		}
    3.64 +
    3.65 +
    3.66 +		/// <summary>
    3.67  		/// Checks whether the supplied army is currently valid according to this requirement.
    3.68  		/// </summary>
    3.69  		/// <returns>
    3.70 @@ -140,7 +168,7 @@
    3.71  
    3.72  				foreach (UnitCountRequirementData requirement in ConstraintTypes)
    3.73  				{
    3.74 -					if (toValidate.GetUnitTypeCount(requirement.UnitType) < requirement.Count)
    3.75 +					if (GetUnitTypesCount(toValidate, requirement.UnitTypes) < requirement.Count)
    3.76  					{
    3.77  						isValid = Validation.Failed;
    3.78  						break;
    3.79 @@ -166,11 +194,11 @@
    3.80  
    3.81  			foreach (UnitCountRequirementData requirement in ConstraintTypes)
    3.82  			{
    3.83 -				int unitCount = army.GetUnitTypeCount(requirement.UnitType);
    3.84 +				int unitCount = GetUnitTypesCount(army, requirement.UnitTypes);
    3.85  
    3.86  				if (unitCount < requirement.Count)
    3.87  				{
    3.88 -					failures.Add(requirement.Count + " × " + requirement.UnitType.Name + " (have " + unitCount + ")");
    3.89 +					failures.Add(requirement.Count + " × " + GetUnitTypeList(requirement) + " (have " + unitCount + ")");
    3.90  				}
    3.91  			}
    3.92  
    3.93 @@ -188,11 +216,11 @@
    3.94  
    3.95  			foreach (UnitCountRequirementData requirement in ConstraintTypes)
    3.96  			{
    3.97 -				int unitCount = GetUnitTypeCount(army, requirement.UnitType, toAdd);
    3.98 +				int unitCount = GetUnitTypesCount(army, requirement.UnitTypes, toAdd);
    3.99  
   3.100  				if (unitCount < requirement.Count)
   3.101  				{
   3.102 -					failures.Add(requirement.Count + " × " + requirement.UnitType.Name + " (would have " + unitCount + ")");
   3.103 +					failures.Add(requirement.Count + " × " + GetUnitTypeList(requirement) + " (would have " + unitCount + ")");
   3.104  				}
   3.105  			}
   3.106  
     4.1 --- a/API/Objects/Requirement/RequiresNUnitsForMObjectsRequirement.cs	Sat Mar 24 16:40:01 2012 +0000
     4.2 +++ b/API/Objects/Requirement/RequiresNUnitsForMObjectsRequirement.cs	Sat Mar 24 20:33:11 2012 +0000
     4.3 @@ -50,19 +50,6 @@
     4.4  			return failures;
     4.5  		}
     4.6  
     4.7 -		private string GetUnitTypeList(UnitCountRequirementData limit)
     4.8 -		{
     4.9 -			List<String> namesList = new List<String>();
    4.10 -
    4.11 -			foreach (UnitType unitType in limit.UnitTypes)
    4.12 -			{
    4.13 -				namesList.Add(unitType.Name);
    4.14 -			}
    4.15 -
    4.16 -			string[] names = namesList.ToArray();
    4.17 -			return String.Join(" or ", names);
    4.18 -		}
    4.19 -
    4.20  		private bool IsValidByRequirement(IWarFoundryObject wfObject, Army toArmy, UnitCountRequirementData limit, int allowedTypeCount)
    4.21  		{
    4.22  			int limitedTypeCount = GetUnitTypesCount(toArmy, limit.UnitTypes, wfObject);
    4.23 @@ -101,18 +88,6 @@
    4.24  			return canAdd;
    4.25  		}
    4.26  
    4.27 -		private int GetUnitTypesCount(Army toArmy, UnitType[] unitTypes, IWarFoundryObject wfObject)
    4.28 -		{
    4.29 -			int count = 0;
    4.30 -
    4.31 -			foreach (UnitType unitType in unitTypes)
    4.32 -			{
    4.33 -				count += GetUnitTypeCount(toArmy, unitType, wfObject);
    4.34 -			}
    4.35 -
    4.36 -			return count;
    4.37 -		}
    4.38 -
    4.39  		private int GetAllowedObjectCount(Army toArmy, OBJECT_TYPE obj, IWarFoundryObject wfObject)
    4.40  		{
    4.41  			return GetObjectCountFromArmy(toArmy, obj) + GetCountFromObject(wfObject, obj);
    4.42 @@ -177,11 +152,6 @@
    4.43  
    4.44  		protected abstract int GetAllowedObjectCount(Army army);
    4.45  
    4.46 -		private int GetUnitTypesCount(Army army, UnitType[] unitTypes)
    4.47 -		{
    4.48 -			return GetUnitTypesCount(army, unitTypes, null);
    4.49 -		}
    4.50 -
    4.51  		/// <summary>
    4.52  		/// Adds a requirement for there to be at least minCount of a given UnitType, allowing allowedCount of this UnitType
    4.53  		/// </summary>