diff --git a/Content.Shared/Chemistry/ReagentUnit.cs b/Content.Shared/Chemistry/ReagentUnit.cs index 184f7aa5d7..63385fe297 100644 --- a/Content.Shared/Chemistry/ReagentUnit.cs +++ b/Content.Shared/Chemistry/ReagentUnit.cs @@ -1,21 +1,23 @@ using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Serialization; using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq; namespace Content.Shared.Chemistry { [Serializable] - public struct ReagentUnit : ISelfSerialize + public struct ReagentUnit : ISelfSerialize, IComparable, IEquatable { private int _value; private static readonly int Shift = 2; public static ReagentUnit MaxValue => new ReagentUnit(int.MaxValue); - private decimal ShiftDown() + private double ShiftDown() { - return _value / (decimal)Math.Pow(10, Shift); + return _value / Math.Pow(10, Shift); } private ReagentUnit(int value) @@ -55,7 +57,7 @@ namespace Content.Shared.Chemistry private static float FloatFromString(string value) { - return float.Parse(value); + return float.Parse(value, CultureInfo.InvariantCulture); } public static ReagentUnit operator +(ReagentUnit a) => a; @@ -82,11 +84,22 @@ namespace Content.Shared.Chemistry } public static ReagentUnit operator *(ReagentUnit a, decimal b) + { + var aD = (decimal) a.ShiftDown(); + return New(aD * b); + } + + public static ReagentUnit operator *(ReagentUnit a, double b) { var aD = a.ShiftDown(); return New(aD * b); } + public static ReagentUnit operator *(ReagentUnit a, int b) + { + return new ReagentUnit(a._value * b); + } + public static ReagentUnit operator /(ReagentUnit a, ReagentUnit b) { if (b._value == 0) @@ -138,14 +151,17 @@ namespace Content.Shared.Chemistry return a._value > b._value; } - public override string ToString() => $"{ShiftDown()}"; - public float Float() { return (float) ShiftDown(); } public decimal Decimal() + { + return (decimal) ShiftDown(); + } + + public double Double() { return ShiftDown(); } @@ -157,7 +173,12 @@ namespace Content.Shared.Chemistry public static ReagentUnit Min(params ReagentUnit[] reagentUnits) { - return reagentUnits.OrderBy(x => x._value).First(); + return reagentUnits.Min(); + } + + public static ReagentUnit Min(ReagentUnit a, ReagentUnit b) + { + return a < b ? a : b; } public override bool Equals(object obj) @@ -176,9 +197,29 @@ namespace Content.Shared.Chemistry _value = FromFloat(FloatFromString(value)); } + public override string ToString() => $"{ShiftDown().ToString(CultureInfo.InvariantCulture)}"; + public string Serialize() { return ToString(); } + + public bool Equals([AllowNull] ReagentUnit other) + { + return _value == other._value; + } + + public int CompareTo([AllowNull] ReagentUnit other) + { + if(other._value > _value) + { + return -1; + } + if(other._value < _value) + { + return 1; + } + return 0; + } } } diff --git a/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs b/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs index 1cae6e1db2..46d391459b 100644 --- a/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs +++ b/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs @@ -118,5 +118,37 @@ namespace Content.Tests.Shared.Chemistry var result = (int) Math.Round(a * (float) Math.Pow(10, 2)); Assert.AreEqual(expected, result); } + + [Test] + public void ReagentUnitMin() + { + var unorderedList = new[] + { + ReagentUnit.New(5), + ReagentUnit.New(3), + ReagentUnit.New(1), + ReagentUnit.New(2), + ReagentUnit.New(4), + }; + var min = ReagentUnit.Min(unorderedList); + Assert.AreEqual(ReagentUnit.New(1), min); + } + + [Test] + [TestCase(1, 0, false)] + [TestCase(0, 0, true)] + [TestCase(-1, 0, false)] + [TestCase(null, 0, true)] + [TestCase(1, 1, true)] + [TestCase(0, 1, false)] + [TestCase(-1, 1, false)] + [TestCase(null, 1, false)] + public void ReagentUnitEquals(int a, int b, bool expected) + { + var parameter = ReagentUnit.New(a); + var comparison = ReagentUnit.New(b); + Assert.AreEqual(comparison.Equals(parameter), parameter.Equals(comparison)); + Assert.AreEqual(expected, comparison.Equals(parameter)); + } } } diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/Solution_Tests.cs index e3024d3a07..2714ce2252 100644 --- a/Content.Tests/Shared/Chemistry/Solution_Tests.cs +++ b/Content.Tests/Shared/Chemistry/Solution_Tests.cs @@ -203,6 +203,41 @@ namespace Content.Tests.Shared.Chemistry Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750)); } + [Test] + public void SplitSolutionFractional() + { + var solution = new Solution(); + solution.AddReagent("water", ReagentUnit.New(1)); + solution.AddReagent("fire", ReagentUnit.New(2)); + + var splitSolution = solution.SplitSolution(ReagentUnit.New(1)); + + Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f)); + Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2)); + + Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f)); + Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(1)); + } + + [Test] + [TestCase(0.03f, 0.01f, 0.02f)] + [TestCase(0.03f, 0.02f, 0.01f)] + public void SplitSolutionTinyFractionalBigSmall(float initial, float reduce, float remainder) + { + var solution = new Solution(); + solution.AddReagent("water", ReagentUnit.New(initial)); + + var splitSolution = solution.SplitSolution(ReagentUnit.New(reduce)); + + Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder)); + Assert.That(solution.TotalVolume.Float(), Is.EqualTo(remainder)); + + Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce)); + Assert.That(splitSolution.TotalVolume.Float(), Is.EqualTo(reduce)); + } + [Test] public void SplitSolutionMoreThanTotalRemovesAll() {