Mercurial > repos > IBDev-IBBoard.WarFoundry.API
view API/Objects/Requirement/RequiresNUnitsForMUnitsRequirement.cs @ 446:ca1e8f7c8b73
Re: #350: Add requirement to allow N of unit for specific other units
* Update army validation to support required amounts other than 1
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Tue, 20 Dec 2011 20:26:54 +0000 |
parents | 2d1bdd679f82 |
children | 4fbb7f205f7e |
line wrap: on
line source
// This file(RequiresNUnitsForMUnitsRequirement.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2011 IBBoard // // The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or(at your option) any later version. Please see COPYING for more information and the full license. using System; using System.Collections.Generic; using System.Text; namespace IBBoard.WarFoundry.API.Objects.Requirement { public class RequiresNUnitsForMUnitsRequirement : AbstractRequirement { public static readonly string REQUIREMENT_ID = "RequiresNUnitsForMUnits"; private List<UnitCountRequirementData> requiredTypes; private UnitType allowedType; public RequiresNUnitsForMUnitsRequirement(UnitType allowedType, params UnitType[] requiredUnitTypes) { this.allowedType = allowedType; FailureStringPrefix = "Army must contain: "; requiredTypes = new List<UnitCountRequirementData>(); foreach (UnitType unitType in requiredUnitTypes) { AddUnitTypeRequirement(unitType); } } public override int GetHashCode() { int hash = 0; foreach (UnitCountRequirementData req in requiredTypes) { hash += req.UnitType.GetHashCode(); } return hash; } protected override bool TypeEquals(object obj) { RequiresNUnitsForMUnitsRequirement otherReq = (RequiresNUnitsForMUnitsRequirement)obj; if (!Collections.Collections.AreEqual(requiredTypes, otherReq.requiredTypes)) { return false; } else { return true; } } protected string FailureStringPrefix { get; set; } protected override string GetAllowsAddingFailedMessage(UnitType toAdd, Army toArmy) { StringBuilder sb = new StringBuilder(); sb.Append(FailureStringPrefix); sb.Append(String.Join("; ", GetFailedAddingRequirements(toAdd, toArmy).ToArray())); sb.Append("."); return sb.ToString(); } private List<string> GetFailedAddingRequirements(UnitType unitType, Army toArmy) { List<string> failures = new List<string>(); int allowedTypeCount = GetUnitTypeCount(toArmy, allowedType, unitType); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = GetUnitTypesCount(toArmy, limit.UnitTypes, unitType); if (!IsValidByRequirement(unitType, toArmy, limit, allowedTypeCount)) { string unitTypeList = GetUnitTypeList(limit); failures.Add(String.Format("{0} {1} for every {2} {3} (would have {4} for {5})", limit.Count, unitTypeList, limit.AllowsCount, allowedType.Name, limitedTypeCount, allowedTypeCount)); } } return failures; } private string GetUnitTypeList(UnitCountRequirementData limit) { List<String> namesList = new List<String>(); foreach (UnitType unitType in limit.UnitTypes) { namesList.Add(unitType.Name); } string[] names = namesList.ToArray(); return String.Join(" or ", names); } private bool IsValidByRequirement(WarFoundryObject wfObject, Army toArmy, UnitCountRequirementData limit, int allowedTypeCount) { int limitedTypeCount = GetUnitTypesCount(toArmy, limit.UnitTypes, wfObject); return IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount); } private bool IsValidByRequirement(UnitCountRequirementData limit, int allowedTypeCount, int limitedTypeCount) { double limitedTypeMultiplier = limitedTypeCount / (limit.Count * 1.0); double allowedTypeMultiplier = allowedTypeCount / (limit.AllowsCount * 1.0); return allowedTypeMultiplier <= limitedTypeMultiplier; } public override Validation AllowsAdding(WarFoundryObject wfObject, Army toArmy) { Validation canAdd = Validation.NotApplicable; UnitType addedUnitType = (wfObject is Unit) ? ((Unit)wfObject).UnitType : wfObject as UnitType; bool typeFound = (addedUnitType == allowedType); int allowedTypeCount = GetUnitTypeCount(toArmy, allowedType, wfObject); foreach (UnitCountRequirementData limit in requiredTypes) { typeFound |= (addedUnitType == limit.UnitType); if (!IsValidByRequirement(wfObject, toArmy, limit, allowedTypeCount)) { canAdd = Validation.Failed; break; } } if (typeFound && canAdd == Validation.NotApplicable) { canAdd = Validation.Passed; } return canAdd; } private int GetUnitTypesCount(Army toArmy, UnitType[] unitTypes, WarFoundryObject wfObject) { int count = 0; foreach (UnitType unitType in unitTypes) { count += GetUnitTypeCount(toArmy, unitType, wfObject); } return count; } private int GetUnitTypeCount(Army toArmy, UnitType unitType, WarFoundryObject wfObject) { return toArmy.GetUnitTypeCount(unitType) + GetCountFromObject(wfObject, unitType); } private int GetCountFromObject(WarFoundryObject wfObject, UnitType limitedType) { return (limitedType.Equals(wfObject) || (wfObject is Unit && ((Unit)wfObject).UnitType.Equals(limitedType))) ? 1 : 0; } public override Validation ValidatesArmy(Army army) { Validation canAdd = Validation.NotApplicable; int allowedTypeCount = army.GetUnitTypeCount(allowedType); bool typeFound = (allowedTypeCount > 0); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = GetUnitTypesCount(army, limit.UnitTypes); typeFound |= (limitedTypeCount > 0); if (!IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount)) { canAdd = Validation.Failed; break; } } if (typeFound && canAdd == Validation.NotApplicable) { canAdd = Validation.Passed; } return canAdd; } protected override string GetValidationFailedMessage(Army army) { StringBuilder sb = new StringBuilder(); sb.Append(FailureStringPrefix); sb.Append(String.Join("; ", GetFailedValidationRequirements(army).ToArray())); sb.Append("."); return sb.ToString(); } private List<string> GetFailedValidationRequirements(Army army) { List<string> failures = new List<string>(); int allowedTypeCount = army.GetUnitTypeCount(allowedType); foreach (UnitCountRequirementData limit in requiredTypes) { int limitedTypeCount = GetUnitTypesCount(army, limit.UnitTypes); if (!IsValidByRequirement(limit, allowedTypeCount, limitedTypeCount)) { string unitTypeList = GetUnitTypeList(limit); failures.Add(String.Format("{0} {1} for every {2} {3} (have {4} for {5})", limit.Count, unitTypeList, limit.AllowsCount, allowedType.Name, limitedTypeCount, allowedTypeCount)); } } return failures; } private int GetUnitTypesCount(Army army, UnitType[] unitTypes) { return GetUnitTypesCount(army, unitTypes, null); } public override string RequirementID { get { return REQUIREMENT_ID; } } /// <summary> /// Adds a requirement for there to be at least minCount of a given UnitType, allowing allowedCount of this UnitType /// </summary> /// <param name='unitType'> /// The unit type to require. /// </param> /// <param name='minCount'> /// The minimum number of that type that must exist. /// </param> /// <param name='allowedCount'> /// The number of units allowed for every minCount units of the supplied unit type. /// </param> public void AddUnitTypeRequirement(UnitType unitType, int minCount, int allowedCount) { requiredTypes.Add(new UnitCountRequirementData(unitType, minCount, allowedCount)); } /// <summary> /// Adds a requirement for there to be at least one of a given UnitType, allowing allowedCount of this UnitType /// </summary> /// <param name='unitType'> /// The unit type to require. /// </param> /// <param name='allowedCount'> /// The number of units allowed for each unit of the supplied unit type. /// </param> public void AddUnitTypeRequirement(UnitType unitType, int allowedCount) { AddUnitTypeRequirement(allowedCount, unitType); } /// <summary> /// Adds a requirement for there to be one or more of the given UnitTypes, allowing one of this UnitType. If multiple unit types /// are supplied here then the number is additive (so 1 x unitType1 and 1 x unitType2 allows two of this UnitType). /// </summary> /// <param name='unitType'> /// The unit type or types to require. /// </param> public void AddUnitTypeRequirement(params UnitType[] unitTypes) { AddUnitTypeRequirement(1, unitTypes); } /// <summary> /// Adds a requirement for there to be one or more of the given UnitTypes, allowing allowsAmount of this UnitType. If multiple unit types /// are supplied here then the number is additive (so 1 x unitType1 and 1 x unitType2 allows two of this UnitType). /// </summary> /// <param name="allowsAmount"> /// The number of units to be allowed for each 1 of unitType /// </param> /// <param name='unitType'> /// The unit type or types to require. /// </param> public void AddUnitTypeRequirement(int allowsAmount, params UnitType[] unitTypes) { requiredTypes.Add(new UnitCountRequirementData(unitTypes, 1, allowsAmount)); } } }