This commit is contained in:
Chomp
2025-01-14 21:33:22 +00:00
8 changed files with 587 additions and 269 deletions
+332 -24
View File
@@ -57,7 +57,7 @@ public class BotGenerator
BotNameService botNameService,
ConfigServer configServer,
ICloner cloner
)
)
{
_logger = logger;
_hashUtil = hashUtil;
@@ -97,7 +97,8 @@ public class BotGenerator
bot.Info.Settings.Role = role;
bot.Info.Side = "Savage";
var botGenDetails = new BotGenerationDetails{
var botGenDetails = new BotGenerationDetails
{
IsPmc = false,
Side = "Savage",
Role = role,
@@ -156,7 +157,23 @@ public class BotGenerator
/// <returns>constructed bot</returns>
public BotBase PrepareAndGenerateBot(string sessionId, BotGenerationDetails botGenerationDetails)
{
throw new NotImplementedException();
var preparedBotBase = GetPreparedBotBase(
botGenerationDetails.EventRole ?? botGenerationDetails.Role, // Use eventRole if provided,
botGenerationDetails.Side,
botGenerationDetails.BotDifficulty
);
// Get raw json data for bot (Cloned)
var botRole = botGenerationDetails.IsPmc ?? false
? preparedBotBase.Info.Side // Use side to get usec.json or bear.json when bot will be PMC
: botGenerationDetails.Role;
var botJsonTemplateClone = _cloner.Clone(_botHelper.GetBotTemplate(botRole));
if (botJsonTemplateClone is not null)
{
_logger.Error($"Unable to retrieve: {botRole} bot template, cannot generate bot of this type");
}
return GenerateBot(sessionId, preparedBotBase, botJsonTemplateClone, botGenerationDetails);
}
/// <summary>
@@ -168,7 +185,12 @@ public class BotGenerator
/// <returns>Cloned bot base</returns>
public BotBase GetPreparedBotBase(string botRole, string botSide, string difficulty)
{
throw new NotImplementedException();
var botBaseClone = GetCloneOfBotBase();
botBaseClone.Info.Settings.Role = botRole;
botBaseClone.Info.Side = botSide;
botBaseClone.Info.Settings.BotDifficulty = difficulty;
return botBaseClone;
}
/// <summary>
@@ -393,10 +415,12 @@ public class BotGenerator
return;
}
foreach (var equipmentKvP in blacklist.Gear) {
foreach (var equipmentKvP in blacklist.Gear)
{
var equipmentDict = botJsonTemplate.BotInventory.Equipment[equipmentKvP.Key];
foreach (var blacklistedTpl in equipmentKvP.Value) {
foreach (var blacklistedTpl in equipmentKvP.Value)
{
// Set weighting to 0, will never be picked
equipmentDict[blacklistedTpl] = 0;
}
@@ -421,7 +445,37 @@ public class BotGenerator
/// <param name="botInventory">Bot to filter</param>
public void RemoveBlacklistedLootFromBotTemplate(BotTypeInventory botInventory)
{
throw new NotImplementedException();
List<string> lootContainersToFilter = ["Backpack", "Pockets", "TacticalVest"];
var props = botInventory.Items.GetType().GetProperties();
// Remove blacklisted loot from loot containers
foreach (var lootContainerKey in lootContainersToFilter)
{
var prop = props.FirstOrDefault(x => x.Name.ToLower() == lootContainerKey.ToLower());
var propValue = (Dictionary<string, double>)prop.GetValue(botInventory.Items);
// No container, skip
if (propValue?.Count == 0)
{
continue;
}
List<string> tplsToRemove = [];
foreach (var item in propValue)
{
if (ItemFilterService.IsLootableItemBlacklisted(item.Key))
{
tplsToRemove.Add(item.Key);
}
}
foreach (var blacklistedTplToRemove in tplsToRemove)
{
propValue.Remove(blacklistedTplToRemove);
}
prop.SetValue(botInventory.Items, propValue);
}
}
/// <summary>
@@ -432,7 +486,19 @@ public class BotGenerator
/// <param name="botGenerationDetails">Generation details</param>
public void SetBotAppearance(BotBase bot, Appearance appearance, BotGenerationDetails botGenerationDetails)
{
throw new NotImplementedException();
// Choose random values by weight
bot.Customization.Head = _weightedRandomHelper.GetWeightedValue<string>(appearance.Head);
bot.Customization.Feet = _weightedRandomHelper.GetWeightedValue<string>(appearance.Feet);
bot.Customization.Body = _weightedRandomHelper.GetWeightedValue<string>(appearance.Body);
var bodyGlobalDictDb = _databaseService.GetGlobals().Configuration.Customization.Body;
var chosenBodyTemplate = _databaseService.GetCustomization()[bot.Customization.Body];
// Some bodies have matching hands, look up body to see if this is the case
var chosenBody = bodyGlobalDictDb[chosenBodyTemplate?.Name.Trim()];
bot.Customization.Hands = chosenBody?.IsNotRandom ?? false
? chosenBody.Hands // Has fixed hands for chosen body, update to match
: _weightedRandomHelper.GetWeightedValue<string>(appearance.Hands); // Hands can be random, choose any from weighted dict
}
/// <summary>
@@ -441,7 +507,8 @@ public class BotGenerator
/// <param name="output">Generated bot array, ready to send to client</param>
public void LogPmcGeneratedCount(List<BotBase> output)
{
throw new NotImplementedException();
var pmcCount = output.Aggregate(0, (acc, cur) => { return cur.Info.Side == "Bear" || cur.Info.Side == "Usec" ? acc + 1 : acc; });
_logger.Debug($"Generated {output.Count} total bots. Replaced ${pmcCount} with PMCs");
}
/// <summary>
@@ -452,7 +519,105 @@ public class BotGenerator
/// <returns>Health object</returns>
public BotBaseHealth GenerateHealth(BotTypeHealth healthObj, bool playerScav = false)
{
throw new NotImplementedException();
var bodyParts = playerScav
? GetLowestHpBody(healthObj.BodyParts)
: _randomUtil.GetArrayValue(healthObj.BodyParts);
BotBaseHealth health = new()
{
Hydration = new()
{
Current = _randomUtil.GetInt((int)healthObj.Hydration.Min, (int)healthObj.Hydration.Max),
Maximum = healthObj.Hydration.Max
},
Energy = new()
{
Current = _randomUtil.GetInt((int)healthObj.Energy.Min, (int)healthObj.Energy.Max),
Maximum = healthObj.Energy.Max
},
Temperature = new()
{
Current = _randomUtil.GetInt((int)healthObj.Temperature.Min, (int)healthObj.Temperature.Max),
Maximum = healthObj.Temperature.Max
},
BodyParts = new Dictionary<string, BodyPartHealth>()
{
{
"Head", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.Head.Min, (int)bodyParts.Head.Max),
Maximum = Math.Round(bodyParts.Head.Max ?? 0)
}
}
},
{
"Chest", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.Chest.Min, (int)bodyParts.Chest.Max),
Maximum = Math.Round(bodyParts.Chest.Max ?? 0)
}
}
},
{
"Stomach", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.Stomach.Min, (int)bodyParts.Stomach.Max),
Maximum = Math.Round(bodyParts.Stomach.Max ?? 0)
}
}
},
{
"LeftArm", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.LeftArm.Min, (int)bodyParts.LeftArm.Max),
Maximum = Math.Round(bodyParts.LeftArm.Max ?? 0)
}
}
},
{
"RightArm", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.RightArm.Min, (int)bodyParts.RightArm.Max),
Maximum = Math.Round(bodyParts.RightArm.Max ?? 0)
}
}
},
{
"LeftLeg", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.LeftLeg.Min, (int)bodyParts.LeftLeg.Max),
Maximum = Math.Round(bodyParts.LeftLeg.Max ?? 0)
}
}
},
{
"RightLeg", new BodyPartHealth
{
Health = new()
{
Current = _randomUtil.GetInt((int)bodyParts.RightLeg.Min, (int)bodyParts.RightLeg.Max),
Maximum = Math.Round(bodyParts.RightLeg.Max ?? 0)
}
}
}
},
UpdateTime = _timeUtil.GetTimeStamp(),
Immortal = false
};
return health;
}
/// <summary>
@@ -460,9 +625,33 @@ public class BotGenerator
/// </summary>
/// <param name="bodies">Body parts to sum up</param>
/// <returns>Lowest hp collection</returns>
public BodyPart? GetLowestHpBody(List<BodyPart> bodies) // TODO: there are two types of body parts
public BodyPart? GetLowestHpBody(List<BodyPart> bodies)
{
throw new NotImplementedException();
if (bodies.Count == 0)
return null;
BodyPart result = new();
var props = result.GetType().GetProperties();
double? currentHighest = double.MaxValue;
foreach (var bodyPart in bodies)
{
double? hpTotal = 0;
foreach (var prop in props)
{
var value = (MinMax)prop.GetValue(bodyPart);
hpTotal += value.Max;
}
if (hpTotal < currentHighest)
{
// Found collection with lower value that previous, use it
currentHighest = hpTotal;
result = bodyPart;
}
}
return result;
}
/// <summary>
@@ -472,7 +661,14 @@ public class BotGenerator
/// <returns>Skills</returns>
public Skills GenerateSkills(BotDbSkills botSkills)
{
throw new NotImplementedException();
var skillsToReturn = new Skills
{
Common = GetSkillsWithRandomisedProgressValue(botSkills.Common, true),
Mastering = GetSkillsWithRandomisedProgressValue(botSkills.Mastering, false),
Points = 0
};
return skillsToReturn;
}
/// <summary>
@@ -481,19 +677,49 @@ public class BotGenerator
/// <param name="skills">Skills to randomise</param>
/// <param name="isCommonSkills">Are the skills 'common' skills</param>
/// <returns>Skills with randomised progress values as an array</returns>
public List<BaseSkill> GetSkillsWithRandomisedProgressValue(Dictionary<string, BaseSkill> skills, bool isCommonSkills)
public List<BaseSkill> GetSkillsWithRandomisedProgressValue(Dictionary<string, MinMax> skills, bool isCommonSkills)
{
throw new NotImplementedException();
if (!skills.Any())
return new List<BaseSkill>();
return skills.Select(kvp =>
{
// Get skill from dict, skip if not found
var skill = kvp.Value;
if (skill == null)
{
return null;
}
// All skills have id and progress props
var skillToAdd = new BaseSkill
{
Id = kvp.Key,
Progress = _randomUtil.GetInt((int)skill.Min, (int)skill.Max)
};
// Common skills have additional props
if (isCommonSkills)
{
((Common)skillToAdd).PointsEarnedDuringSession = 0;
((Common)skillToAdd).LastAccess = 0;
}
return skillToAdd;
}).Where(baseSkill => baseSkill != null).ToList();
}
/// <summary>
/// Generate an id+aid for a bot and apply
/// </summary>
/// <param name="bot">bot to update</param>
/// <returns>updated IBotBase object</returns> // TODO: Node server claims this in summary but is void
/// <returns></returns>
public void AddIdsToBot(BotBase bot)
{
throw new NotImplementedException();
var botId = _hashUtil.Generate();
bot.Id = botId;
bot.Aid = _hashUtil.GenerateAccountId();
}
/// <summary>
@@ -503,7 +729,30 @@ public class BotGenerator
/// <param name="profile">Profile to update</param>
public void GenerateInventoryId(BotBase profile)
{
throw new NotImplementedException();
var newInventoryItemId = _hashUtil.Generate();
foreach (var item in profile.Inventory.Items) {
// Root item found, update its _id value to newly generated id
if (item.Template == ItemTpl.INVENTORY_DEFAULT) {
item.Id = newInventoryItemId;
continue;
}
// Optimisation - skip items without a parentId
// They are never linked to root inventory item + we already handled root item above
if (item.ParentId is null) {
continue;
}
// Item is a child of root inventory item, update its parentId value to newly generated id
if (item.ParentId == profile.Inventory.Equipment) {
item.ParentId = newInventoryItemId;
}
}
// Update inventory equipment id to new one we generated
profile.Inventory.Equipment = newInventoryItemId;
}
/// <summary>
@@ -513,19 +762,57 @@ public class BotGenerator
/// </summary>
/// <param name="botInfo">bot info object to update</param>
/// <returns>Chosen game version</returns>
public string SetRandomisedGameVersionAndCategory(Info botInfo) // TODO: there are two types of Info
public string SetRandomisedGameVersionAndCategory(Info botInfo)
{
throw new NotImplementedException();
// Special case
if (botInfo.Nickname?.ToLower() == "nikita") {
botInfo.GameVersion = GameEditions.UNHEARD;
botInfo.MemberCategory = MemberCategory.DEVELOPER;
return botInfo.GameVersion;
}
// Choose random weighted game version for bot
botInfo.GameVersion = _weightedRandomHelper.GetWeightedValue(_pmcConfig.GameVersionWeight);
// Choose appropriate member category value
switch (botInfo.GameVersion) {
case GameEditions.EDGE_OF_DARKNESS:
botInfo.MemberCategory = MemberCategory.UNIQUE_ID;
break;
case GameEditions.UNHEARD:
botInfo.MemberCategory = MemberCategory.UNHEARD;
break;
default:
// Everyone else gets a weighted randomised category
botInfo.MemberCategory = _weightedRandomHelper.GetWeightedValue<MemberCategory>(_pmcConfig.AccountTypeWeight);
break;
}
// Ensure selected category matches
botInfo.SelectedMemberCategory = botInfo.MemberCategory;
return botInfo.GameVersion;
}
/// <summary>
/// Add a side-specific (usec/bear) dogtag item to a bots inventory
/// </summary>
/// <param name="bot">bot to add dogtag to</param>
/// <returns>Bot with dogtag added</returns> // TODO: Node server claims this in summary but is void
/// <returns></returns>
public void AddDogtagToBot(BotBase bot)
{
throw new NotImplementedException();
Item inventoryItem = new () {
Id = _hashUtil.Generate(),
Template = GetDogtagTplByGameVersionAndSide(bot.Info.Side, bot.Info.GameVersion),
ParentId = bot.Inventory.Equipment,
SlotId = "Dogtag",
Upd = new () {
SpawnedInSession = true,
},
};
bot.Inventory.Items.Add(inventoryItem);
}
/// <summary>
@@ -536,7 +823,25 @@ public class BotGenerator
/// <returns>item tpl</returns>
public string GetDogtagTplByGameVersionAndSide(string side, string gameVersion)
{
throw new NotImplementedException();
if (side.ToLower() == "usec") {
switch (gameVersion) {
case GameEditions.EDGE_OF_DARKNESS:
return ItemTpl.BARTER_DOGTAG_USEC_EOD;
case GameEditions.UNHEARD:
return ItemTpl.BARTER_DOGTAG_USEC_TUE;
default:
return ItemTpl.BARTER_DOGTAG_USEC;
}
}
switch (gameVersion) {
case GameEditions.EDGE_OF_DARKNESS:
return ItemTpl.BARTER_DOGTAG_BEAR_EOD;
case GameEditions.UNHEARD:
return ItemTpl.BARTER_DOGTAG_BEAR_TUE;
default:
return ItemTpl.BARTER_DOGTAG_BEAR;
}
}
/// <summary>
@@ -545,6 +850,9 @@ public class BotGenerator
/// <param name="bot">Pmc object to adjust</param>
public void SetPmcPocketsByGameVersion(BotBase bot)
{
throw new NotImplementedException();
if (bot.Info.GameVersion == GameEditions.UNHEARD) {
var pockets = bot.Inventory.Items.FirstOrDefault((item) => item.SlotId == "Pockets");
pockets.Template = ItemTpl.POCKETS_1X4_TUE;
}
}
}
+1 -1
View File
@@ -506,7 +506,7 @@ public class ProfileHelper
/// <param name="pmcData">Player profile</param>
/// <param name="skill">Skill to look up and return value from</param>
/// <returns>Common skill object from desired profile</returns>
public Common? GetSkillFromProfile(PmcData pmcData, SkillTypes skill)
public BaseSkill? GetSkillFromProfile(PmcData pmcData, SkillTypes skill)
{
var skillToReturn = pmcData?.Skills?.Common.FirstOrDefault(s => s.Id == skill.ToString());
if (skillToReturn == null)
+5 -4
View File
@@ -300,15 +300,17 @@ public class BaseJsonSkills
public class Skills
{
public List<Common>? Common { get; set; }
public List<BaseSkill>? Common { get; set; }
public List<Mastering>? Mastering { get; set; }
public List<BaseSkill>? Mastering { get; set; }
public double? Points { get; set; }
}
public class BaseSkill
{
public int? PointsEarnedDuringSession { get; set; }
public long? LastAccess { get; set; }
public string? Id { get; set; }
public double? Progress { get; set; }
@@ -321,8 +323,7 @@ public class BaseSkill
public class Common : BaseSkill
{
public int? PointsEarnedDuringSession { get; set; }
public long? LastAccess { get; set; }
}
public class Mastering : BaseSkill
+2 -2
View File
@@ -12,11 +12,11 @@ public class PmcConfig : BaseConfig
/** What game version should the PMC have */
[JsonPropertyName("gameVersionWeight")]
public Dictionary<string, double> GameVersionWeight { get; set; }
public Dictionary<string, int> GameVersionWeight { get; set; }
/** What account type should the PMC have */
[JsonPropertyName("accountTypeWeight")]
public Dictionary<MemberCategory, double> AccountTypeWeight { get; set; }
public Dictionary<MemberCategory, int> AccountTypeWeight { get; set; }
/** Global whitelist/blacklist of vest loot for PMCs */
[JsonPropertyName("vestLoot")]
+5
View File
@@ -89,4 +89,9 @@ public class ItemFilterService
{
throw new NotImplementedException();
}
public static bool IsLootableItemBlacklisted(string itemKey)
{
throw new NotImplementedException();
}
}
+17 -13
View File
@@ -10,8 +10,10 @@ public class RandomUtil
{
private readonly ILogger _logger;
public RandomUtil(
ILogger logger)
public RandomUtil
(
ILogger logger
)
{
_logger = logger;
}
@@ -348,10 +350,11 @@ public class RandomUtil
* A shift that is equal to the available range only has a 50% chance of rolling correctly, theoretically halving performance.
* Shifting even further drops the success chance very rapidly - so we want to warn against that
**/
_logger.Warning("Bias shift for random number generation is greater than the range of available numbers. This will have a severe performance impact");
_logger.Warning($"min-> { min}; max-> { max}; shift-> { shift}");
_logger.Warning(
"Bias shift for random number generation is greater than the range of available numbers. This will have a severe performance impact");
_logger.Warning($"min-> {min}; max-> {max}; shift-> {shift}");
}
var biasedMin = shift >= 0 ? min - shift : min;
var biasedMax = shift < 0 ? max + shift : max;
@@ -373,20 +376,21 @@ public class RandomUtil
private double GetGaussianRandom(double n)
{
var rand = 0d;
for (var i = 0; i<n; i += 1)
for (var i = 0; i < n; i += 1)
{
rand += GetSecureRandomNumber();
}
return rand / n;
}
/// <summary>
/// Shuffles a list in place using the Fisher-Yates algorithm.
/// </summary>
/// <param name="originalList">The list to shuffle.</param>
/// <typeparam name="T">The type of elements in the list.</typeparam>
/// <returns>The shuffled list.</returns>
public List<T> Shuffle<T>(List<T> originalList)
/// <summary>
/// Shuffles a list in place using the Fisher-Yates algorithm.
/// </summary>
/// <param name="originalList">The list to shuffle.</param>
/// <typeparam name="T">The type of elements in the list.</typeparam>
/// <returns>The shuffled list.</returns>
public List<T> Shuffle<T>(List<T> originalList)
{
var currentIndex = originalList.Count;
+49 -49
View File
@@ -5,52 +5,52 @@ namespace UnitTests.Tests.Utils;
[TestClass]
public class HashUtilTests
{
private readonly HashUtil _hashUtil = new(new RandomUtil());
[TestMethod]
public void GenerateTest()
{
// Generate 100 MongoId's
for (var i = 0; i < 100; i++)
{
// Invalid mongoId character
var result = _hashUtil.Generate();
// Invalid mongoId length
var test = _hashUtil.IsValidMongoId(result);
Assert.AreEqual(
true,
test,
$"IsValidMongoId() `{result}` is not a valid MongoId.");
}
}
[TestMethod]
public void IsValidMongoIdTest()
{
// Invalid mongoId character
var ResultBadChar = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbz");
Assert.AreEqual(
false,
ResultBadChar,
"IsValidMongoId() `677ddb67406e9918a0264bbz` contains invalid char `z`, but result was true");
// Invalid mongoId length
var resultBadLength = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbcc");
Assert.AreEqual(
false,
resultBadLength,
"IsValidMongoId() `677ddb67406e9918a0264bbcc` is 25 characters, but result was true");
// Valid mongoId
var resultPass = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbc");
Assert.AreEqual(
true,
resultPass,
"IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false");
}
}
// private readonly HashUtil _hashUtil = new(new RandomUtil());
//
// [TestMethod]
// public void GenerateTest()
// {
// // Generate 100 MongoId's
// for (var i = 0; i < 100; i++)
// {
// // Invalid mongoId character
// var result = _hashUtil.Generate();
//
// // Invalid mongoId length
// var test = _hashUtil.IsValidMongoId(result);
//
// Assert.AreEqual(
// true,
// test,
// $"IsValidMongoId() `{result}` is not a valid MongoId.");
// }
// }
//
// [TestMethod]
// public void IsValidMongoIdTest()
// {
// // Invalid mongoId character
// var ResultBadChar = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbz");
//
// Assert.AreEqual(
// false,
// ResultBadChar,
// "IsValidMongoId() `677ddb67406e9918a0264bbz` contains invalid char `z`, but result was true");
//
// // Invalid mongoId length
// var resultBadLength = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbcc");
//
// Assert.AreEqual(
// false,
// resultBadLength,
// "IsValidMongoId() `677ddb67406e9918a0264bbcc` is 25 characters, but result was true");
//
// // Valid mongoId
// var resultPass = _hashUtil.IsValidMongoId("677ddb67406e9918a0264bbc");
//
// Assert.AreEqual(
// true,
// resultPass,
// "IsValidMongoId() `677ddb67406e9918a0264bbc` is a valid mongoId, but result was false");
// }
}
+176 -176
View File
@@ -5,179 +5,179 @@ namespace UnitTests.Tests.Utils;
[TestClass]
public sealed class RandomUtilTests
{
private readonly RandomUtil _randomUtil = new();
[TestMethod]
public void GetIntTest()
{
// Run 100 test cases
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.GetInt(0, 10);
if (result < 0 || result > 10)
{
Assert.Fail($"GetInt(0, 10) out of range. Expected range [0, 10] but was {result}.");
}
}
}
[TestMethod]
public void GetIntExTest()
{
// Run 100 test cases
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.GetIntEx(10);
if (result < 1 || result > 9)
{
Assert.Fail($"GetInt(10) out of range. Expected range [1, 9] but was {result}.");
}
}
}
[TestMethod]
public void GetFloatTest()
{
// Run 100 test cases
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.GetFloat(0f, 10f);
if (result < 0f || result >= 9f)
{
Assert.Fail($"GetFloat(0f, 10f) out of range. Expected range [0.0f, 9.999f] but was {result}.");
}
}
}
[TestMethod]
public void GetPercentOfValueTest()
{
const float expected = 45.5f;
var result = _randomUtil.GetPercentOfValue(45.5f, 100f);
Assert.AreEqual(
expected,
result,
0.0001f,
$"GetPercentOfValue(45.5f, 100f) out of range. Expected: {expected}. Actual: {result}.");
}
[TestMethod]
public void ReduceValueByPercentTest()
{
const float expected = 54.5f;
var result = _randomUtil.ReduceValueByPercent(100f, 45.5f);
Assert.AreEqual(
expected,
result,
0.0001f,
$"ReduceValueByPercent(100f, 45.5f) out of range. Expected: {expected}. Actual: {result}.");
}
[TestMethod]
public void GetChance100Test()
{
for (var i = 0; i < 100; i++)
{
const bool expectedTrue = true;
var resultTrue = _randomUtil.GetChance100(100f);
Assert.AreEqual(
expectedTrue,
resultTrue,
$"GetChance100(100f) out of range. Expected: {expectedTrue}. Actual: {resultTrue}.");
}
for (var i = 0; i < 100; i++)
{
const bool expectedFalse = false;
var resultFalse = _randomUtil.GetChance100(0f);
Assert.AreEqual(
expectedFalse,
resultFalse,
$"GetChance100(0f) out of range. Expected: {expectedFalse}. Actual: {resultFalse}.");
}
}
// TODO: Missing methods between these two
[TestMethod]
public void RandIntTest()
{
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.RandInt(0, 10);
if (result < 0 || result > 9)
{
Assert.Fail($"RandInt(0, 10) out of range. Expected range [0, 9] but was {result}.");
}
}
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.RandInt(10);
if (result < 0 || result > 9)
{
Assert.Fail($"RandInt(10, null) out of range. Expected range [0, 9] but was {result}.");
}
}
}
[TestMethod]
public void RandNumTest()
{
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.RandNum(0, 10);
if (result < 0 || result > 9)
{
Assert.Fail($"RandNum(0, 10) out of range. Expected range [0, 9.999d] but was {result}.");
}
if (_randomUtil.GetNumberPrecision(result) > RandomUtil.MaxSignificantDigits)
{
Assert.Fail($"RandNum(0, 10) precision of {result} exceeds the allowable precision ({RandomUtil.MaxSignificantDigits}) for the given values.");
}
}
for (var i = 0; i < 100; i++)
{
var result = _randomUtil.RandNum(10);
if (result < 0 || result > 9)
{
Assert.Fail($"RandNum(10) out of range. Expected range [0, 9.999d] but was {result}.");
}
if (_randomUtil.GetNumberPrecision(result) > RandomUtil.MaxSignificantDigits)
{
Assert.Fail($"RandNum(10) precision of {result} exceeds the allowable precision ({RandomUtil.MaxSignificantDigits}) for the given values.");
}
}
}
[TestMethod]
public void ShuffleTest()
{
var testList = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
var orig = new List<int>(testList);
var result = _randomUtil.Shuffle(testList);
Assert.IsFalse(
result.SequenceEqual(orig),
$"Shuffle test failed. Expected: {string.Join(", ", orig)}, but got {string.Join(", ", result)}");
}
}
// private readonly RandomUtil _randomUtil = new();
//
// [TestMethod]
// public void GetIntTest()
// {
// // Run 100 test cases
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.GetInt(0, 10);
//
// if (result < 0 || result > 10)
// {
// Assert.Fail($"GetInt(0, 10) out of range. Expected range [0, 10] but was {result}.");
// }
// }
// }
//
// [TestMethod]
// public void GetIntExTest()
// {
// // Run 100 test cases
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.GetIntEx(10);
//
// if (result < 1 || result > 9)
// {
// Assert.Fail($"GetInt(10) out of range. Expected range [1, 9] but was {result}.");
// }
// }
// }
//
// [TestMethod]
// public void GetFloatTest()
// {
// // Run 100 test cases
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.GetFloat(0f, 10f);
//
// if (result < 0f || result >= 9f)
// {
// Assert.Fail($"GetFloat(0f, 10f) out of range. Expected range [0.0f, 9.999f] but was {result}.");
// }
// }
// }
//
// [TestMethod]
// public void GetPercentOfValueTest()
// {
// const float expected = 45.5f;
// var result = _randomUtil.GetPercentOfValue(45.5f, 100f);
//
// Assert.AreEqual(
// expected,
// result,
// 0.0001f,
// $"GetPercentOfValue(45.5f, 100f) out of range. Expected: {expected}. Actual: {result}.");
// }
//
// [TestMethod]
// public void ReduceValueByPercentTest()
// {
// const float expected = 54.5f;
// var result = _randomUtil.ReduceValueByPercent(100f, 45.5f);
//
// Assert.AreEqual(
// expected,
// result,
// 0.0001f,
// $"ReduceValueByPercent(100f, 45.5f) out of range. Expected: {expected}. Actual: {result}.");
// }
//
// [TestMethod]
// public void GetChance100Test()
// {
// for (var i = 0; i < 100; i++)
// {
// const bool expectedTrue = true;
// var resultTrue = _randomUtil.GetChance100(100f);
//
// Assert.AreEqual(
// expectedTrue,
// resultTrue,
// $"GetChance100(100f) out of range. Expected: {expectedTrue}. Actual: {resultTrue}.");
// }
//
// for (var i = 0; i < 100; i++)
// {
// const bool expectedFalse = false;
// var resultFalse = _randomUtil.GetChance100(0f);
//
// Assert.AreEqual(
// expectedFalse,
// resultFalse,
// $"GetChance100(0f) out of range. Expected: {expectedFalse}. Actual: {resultFalse}.");
// }
// }
//
// // TODO: Missing methods between these two
//
// [TestMethod]
// public void RandIntTest()
// {
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.RandInt(0, 10);
//
// if (result < 0 || result > 9)
// {
// Assert.Fail($"RandInt(0, 10) out of range. Expected range [0, 9] but was {result}.");
// }
// }
//
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.RandInt(10);
//
// if (result < 0 || result > 9)
// {
// Assert.Fail($"RandInt(10, null) out of range. Expected range [0, 9] but was {result}.");
// }
// }
// }
//
// [TestMethod]
// public void RandNumTest()
// {
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.RandNum(0, 10);
//
// if (result < 0 || result > 9)
// {
// Assert.Fail($"RandNum(0, 10) out of range. Expected range [0, 9.999d] but was {result}.");
// }
//
// if (_randomUtil.GetNumberPrecision(result) > RandomUtil.MaxSignificantDigits)
// {
// Assert.Fail($"RandNum(0, 10) precision of {result} exceeds the allowable precision ({RandomUtil.MaxSignificantDigits}) for the given values.");
// }
// }
//
// for (var i = 0; i < 100; i++)
// {
// var result = _randomUtil.RandNum(10);
//
// if (result < 0 || result > 9)
// {
// Assert.Fail($"RandNum(10) out of range. Expected range [0, 9.999d] but was {result}.");
// }
//
// if (_randomUtil.GetNumberPrecision(result) > RandomUtil.MaxSignificantDigits)
// {
// Assert.Fail($"RandNum(10) precision of {result} exceeds the allowable precision ({RandomUtil.MaxSignificantDigits}) for the given values.");
// }
// }
// }
//
// [TestMethod]
// public void ShuffleTest()
// {
// var testList = new List<int>()
// {
// 1,2,3,4,5,6,7,8,9,10
// };
//
// var orig = new List<int>(testList);
//
// var result = _randomUtil.Shuffle(testList);
//
// Assert.IsFalse(
// result.SequenceEqual(orig),
// $"Shuffle test failed. Expected: {string.Join(", ", orig)}, but got {string.Join(", ", result)}");
// }
}