diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6281743c --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +################################################################################ +# This .gitignore file was automatically created by Microsoft(R) Visual Studio. +################################################################################ + +/.vs/CashRegister/v16/Server/sqlite3 +/SWCashRegisterSB/.vs/SWCashRegisterSB/v16 +/SWCashRegisterSB/bin/Debug +/SWCashRegisterSB/obj/Debug +/.vs/slnx.sqlite diff --git a/.vs/CashRegister/v16/.suo b/.vs/CashRegister/v16/.suo new file mode 100644 index 00000000..e7d97944 Binary files /dev/null and b/.vs/CashRegister/v16/.suo differ diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 00000000..6b611411 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,6 @@ +{ + "ExpandedNodes": [ + "" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/SWCashRegisterSB/App.config b/SWCashRegisterSB/App.config new file mode 100644 index 00000000..56efbc7b --- /dev/null +++ b/SWCashRegisterSB/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SWCashRegisterSB/Calculators/ChangeCalculator.cs b/SWCashRegisterSB/Calculators/ChangeCalculator.cs new file mode 100644 index 00000000..bd62bd82 --- /dev/null +++ b/SWCashRegisterSB/Calculators/ChangeCalculator.cs @@ -0,0 +1,31 @@ +using SWCashRegisterSB.Calculators.Interfaces; +using SWCashRegisterSB.Models; +using SWCashRegisterSB.Models.Interfaces; +using SWCashRegisterSB.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Calculators +{ + public class ChangeCalculator : IChangeCalculator + { + public List CalculateChange(decimal changeAmount) + { + var result = new List(); + + while (changeAmount > 0) + { + var denomination = DenominationUtils.OrderedDenominations.First(x => x.Value <= changeAmount); + var count = decimal.ToInt32(changeAmount / denomination.Value); + + result.Add(new ChangeResult(denomination, count)); + changeAmount -= denomination.Value * count; + } + + return result; + } + } +} diff --git a/SWCashRegisterSB/Calculators/Interfaces/IChangeCalculator.cs b/SWCashRegisterSB/Calculators/Interfaces/IChangeCalculator.cs new file mode 100644 index 00000000..de952367 --- /dev/null +++ b/SWCashRegisterSB/Calculators/Interfaces/IChangeCalculator.cs @@ -0,0 +1,14 @@ +using SWCashRegisterSB.Models.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Calculators.Interfaces +{ + public interface IChangeCalculator + { + List CalculateChange(decimal changeAmount); + } +} diff --git a/SWCashRegisterSB/Calculators/RandomChangeCalculator.cs b/SWCashRegisterSB/Calculators/RandomChangeCalculator.cs new file mode 100644 index 00000000..a51d2f52 --- /dev/null +++ b/SWCashRegisterSB/Calculators/RandomChangeCalculator.cs @@ -0,0 +1,40 @@ +using SWCashRegisterSB.Calculators.Interfaces; +using SWCashRegisterSB.Models; +using SWCashRegisterSB.Models.Interfaces; +using SWCashRegisterSB.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Calculators +{ + public class RandomChangeCalculator : IChangeCalculator + { + + public List CalculateChange(decimal changeAmount) + { + var result = new Dictionary(); + var random = new Random(); + + while(changeAmount > 0) + { + var denominations = DenominationUtils.OrderedDenominations.Where(x => x.Value <= changeAmount).ToList(); + var index = random.Next(0, denominations.Count()); + var denomination = denominations[index]; + var count = random.Next(1, decimal.ToInt32(changeAmount / denomination.Value)); + + if (result.ContainsKey(denomination.Name)) + result[denomination.Name].Quantity += count; + else + result.Add(denomination.Name, new ChangeResult(denomination, count)); + + changeAmount -= denomination.Value * count; + + } + + return result.Values.ToList(); + } + } +} diff --git a/SWCashRegisterSB/Models/ChangeDenomination.cs b/SWCashRegisterSB/Models/ChangeDenomination.cs new file mode 100644 index 00000000..1b1adc0c --- /dev/null +++ b/SWCashRegisterSB/Models/ChangeDenomination.cs @@ -0,0 +1,16 @@ +using SWCashRegisterSB.Models.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Models +{ + public class ChangeDenomination : IDenomination + { + public string Name { get; set; } + public string PluralName { get; set; } + public decimal Value { get; set; } + } +} diff --git a/SWCashRegisterSB/Models/ChangeResult.cs b/SWCashRegisterSB/Models/ChangeResult.cs new file mode 100644 index 00000000..4a7c35ee --- /dev/null +++ b/SWCashRegisterSB/Models/ChangeResult.cs @@ -0,0 +1,20 @@ +using SWCashRegisterSB.Models.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Models +{ + public class ChangeResult : IChangeResult + { + public ChangeResult(IDenomination denomination, int quantity) + { + Denomination = denomination; + Quantity = quantity; + } + public IDenomination Denomination { get; set; } + public int Quantity { get; set; } + } +} diff --git a/SWCashRegisterSB/Models/Interfaces/IChangeResult.cs b/SWCashRegisterSB/Models/Interfaces/IChangeResult.cs new file mode 100644 index 00000000..3f5a06fa --- /dev/null +++ b/SWCashRegisterSB/Models/Interfaces/IChangeResult.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Models.Interfaces +{ + public interface IChangeResult + { + IDenomination Denomination { get; set; } + int Quantity { get; set; } + } +} diff --git a/SWCashRegisterSB/Models/Interfaces/IDenomination.cs b/SWCashRegisterSB/Models/Interfaces/IDenomination.cs new file mode 100644 index 00000000..7c36c7ec --- /dev/null +++ b/SWCashRegisterSB/Models/Interfaces/IDenomination.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Models.Interfaces +{ + public interface IDenomination + { + string Name { get; set; } + string PluralName { get; set; } + decimal Value { get; set; } + } +} diff --git a/SWCashRegisterSB/Program.cs b/SWCashRegisterSB/Program.cs new file mode 100644 index 00000000..4c10838b --- /dev/null +++ b/SWCashRegisterSB/Program.cs @@ -0,0 +1,94 @@ +using SWCashRegisterSB.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB +{ + /// + /// Softwriters Cash Register by Stephen Bierly + /// Input file location is: "{RepoPath}\\SWCashRegisterSB\\input.txt" + /// Output file location is: "{RepoPath}\\SWCashRegisterSB\\output.txt" + /// + class Program + { + static void Main(string[] args) + { + var basePath = Path.GetFullPath(@"..\..\"); + var inputPath = basePath + "input.txt"; + var outputPath = basePath + "output.txt"; + + + if (!File.Exists(inputPath)) + { + Console.WriteLine($"Could not find input file. Expected to be '{inputPath}'"); + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + return; + } + + try + { + using (StreamWriter outWriter = new StreamWriter(outputPath, false)) + { + var currentLineNum = 1; + foreach (var line in File.ReadLines(inputPath)) + { + var parts = line.Split(','); + decimal amountDue; + decimal amountPaid; + if(parts.Length != 2 || !decimal.TryParse(parts[0], out amountDue) || !decimal.TryParse(parts[1], out amountPaid)) + { + Console.WriteLine($"Improperly formated line '{line}' on line '{currentLineNum}"); + currentLineNum++; + continue; + } + + //Excluding the possibility of refunds currently + if(amountDue < 0 || amountPaid < 0) + { + Console.WriteLine($"Amount Paid ('{amountPaid}') and Amount Due ('{amountDue}') must be positive."); + continue; + } + + var changeDue = amountPaid - amountDue; + + if(changeDue < 0) + { + Console.WriteLine($"Insufficient payment on line '{currentLineNum}', payment is '{Math.Abs(changeDue)}' less than required."); + currentLineNum++; + continue; + } + + if (changeDue == 0) + { + Console.WriteLine($"No change due on line {currentLineNum}"); + currentLineNum++; + continue; + } + + var calculator = DenominationUtils.GetChangeCalculator(amountDue); + + var change = calculator.CalculateChange(changeDue); + + var changeOutputLine = DenominationUtils.GetChangeOutput(change); + + outWriter.WriteLine(changeOutputLine); + currentLineNum++; + } + + } + } + catch(Exception e) + { + Console.WriteLine($"Unexpected Error : '{e.Message}'"); + } + + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); + } + } +} diff --git a/SWCashRegisterSB/Properties/AssemblyInfo.cs b/SWCashRegisterSB/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..126fc933 --- /dev/null +++ b/SWCashRegisterSB/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SWCashRegisterSB")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SWCashRegisterSB")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5cf33ad0-25e5-4d11-954f-ad914ae820ac")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SWCashRegisterSB/SWCashRegisterSB.csproj b/SWCashRegisterSB/SWCashRegisterSB.csproj new file mode 100644 index 00000000..80280149 --- /dev/null +++ b/SWCashRegisterSB/SWCashRegisterSB.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {5CF33AD0-25E5-4D11-954F-AD914AE820AC} + Exe + SWCashRegisterSB + SWCashRegisterSB + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SWCashRegisterSB/SWCashRegisterSB.sln b/SWCashRegisterSB/SWCashRegisterSB.sln new file mode 100644 index 00000000..4180722a --- /dev/null +++ b/SWCashRegisterSB/SWCashRegisterSB.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SWCashRegisterSB", "SWCashRegisterSB.csproj", "{5CF33AD0-25E5-4D11-954F-AD914AE820AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5CF33AD0-25E5-4D11-954F-AD914AE820AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CF33AD0-25E5-4D11-954F-AD914AE820AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CF33AD0-25E5-4D11-954F-AD914AE820AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CF33AD0-25E5-4D11-954F-AD914AE820AC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {069B2EC7-CEE6-4846-94FE-69BF508FB37C} + EndGlobalSection +EndGlobal diff --git a/SWCashRegisterSB/Utils/DenominationUtils.cs b/SWCashRegisterSB/Utils/DenominationUtils.cs new file mode 100644 index 00000000..c5dfbfc7 --- /dev/null +++ b/SWCashRegisterSB/Utils/DenominationUtils.cs @@ -0,0 +1,61 @@ +using SWCashRegisterSB.Calculators; +using SWCashRegisterSB.Calculators.Interfaces; +using SWCashRegisterSB.Models; +using SWCashRegisterSB.Models.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SWCashRegisterSB.Utils +{ + public static class DenominationUtils + { + #region static Change Denominations... + public readonly static ChangeDenomination Hundred = new ChangeDenomination { Name = "hundred", PluralName = "hundreds", Value = 100 }; + public readonly static ChangeDenomination Fifty = new ChangeDenomination { Name = "fifty", PluralName = "fifties", Value = 50 }; + public readonly static ChangeDenomination Twenty = new ChangeDenomination { Name = "twenty", PluralName = "twenties", Value = 20 }; + public readonly static ChangeDenomination Ten = new ChangeDenomination { Name = "ten", PluralName = "tens", Value = 10 }; + public readonly static ChangeDenomination Five = new ChangeDenomination { Name = "five", PluralName = "fives", Value = 5 }; + public readonly static ChangeDenomination Dollar = new ChangeDenomination { Name = "dollar", PluralName = "dollars", Value = 1 }; + + public readonly static ChangeDenomination Quarter = new ChangeDenomination { Name = "quarter", PluralName = "quarters", Value = 0.25M }; + public readonly static ChangeDenomination Dime = new ChangeDenomination { Name = "dime", PluralName = "dimes", Value = 0.10M }; + public readonly static ChangeDenomination Nickel = new ChangeDenomination { Name = "nickel", PluralName = "nickels", Value = 0.05M }; + public readonly static ChangeDenomination Penny = new ChangeDenomination { Name = "penny", PluralName = "pennies", Value = 0.01M }; + + public readonly static List OrderedDenominations = new List { Hundred, Fifty, Twenty, Ten, Five, Dollar, Quarter, Dime, Nickel, Penny }; + #endregion + + private readonly static RandomChangeCalculator _randomChangeCalculator = new RandomChangeCalculator(); + private readonly static ChangeCalculator _changeCalculator = new ChangeCalculator(); + + public static IChangeCalculator GetChangeCalculator(decimal amountDue) + { + if (amountDue % 0.03m == 0) + return _randomChangeCalculator; + else + return _changeCalculator; + } + + public static string GetChangeOutput(List changeResults) + { + var changeSB = new StringBuilder(); + + var sortedResults = changeResults.OrderByDescending(x => x.Denomination.Value); + + foreach(var result in sortedResults) + { + if (changeSB.Length > 0) + changeSB.Append(','); + + var plural = result.Quantity > 1; + + changeSB.Append($"{result.Quantity} {(plural ? result.Denomination.PluralName : result.Denomination.Name)}"); + } + + return changeSB.ToString(); + } + } +} diff --git a/SWCashRegisterSB/input.txt b/SWCashRegisterSB/input.txt new file mode 100644 index 00000000..43c5d189 --- /dev/null +++ b/SWCashRegisterSB/input.txt @@ -0,0 +1,19 @@ +2.12,3.00 +1.75,2.00 +1.97,2.00 +3.33,5.00 +2.99,3 +3.95,5.00 +NaN,NaN +5,000.00,6,000.00 +5.06,50.00 +5.04,20.00 +2.21,10.00 +6.11,5.10 +891.31,1000.00 +32.21,100.00 +6.31,6.31 +3.33,3.33 +-3.21,4.33 +1.05,-2.22 +10.01,50 diff --git a/SWCashRegisterSB/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/SWCashRegisterSB/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache new file mode 100644 index 00000000..053452f4 Binary files /dev/null and b/SWCashRegisterSB/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/SWCashRegisterSB/obj/Debug/SWCashRegisterSB.csprojAssemblyReference.cache b/SWCashRegisterSB/obj/Debug/SWCashRegisterSB.csprojAssemblyReference.cache new file mode 100644 index 00000000..24df8ab7 Binary files /dev/null and b/SWCashRegisterSB/obj/Debug/SWCashRegisterSB.csprojAssemblyReference.cache differ diff --git a/SWCashRegisterSB/output.txt b/SWCashRegisterSB/output.txt new file mode 100644 index 00000000..b23449a8 --- /dev/null +++ b/SWCashRegisterSB/output.txt @@ -0,0 +1,12 @@ +3 quarters,1 dime,3 pennies +1 quarter +3 pennies +5 quarters,3 dimes,2 nickels,2 pennies +1 penny +1 dollar,1 nickel +2 twenties,4 dollars,3 quarters,1 dime,1 nickel,4 pennies +1 five,2 dollars,28 quarters,6 dimes,3 nickels,21 pennies +1 five,2 dollars,3 quarters,4 pennies +1 hundred,1 five,3 dollars,2 quarters,1 dime,1 nickel,4 pennies +1 fifty,1 ten,1 five,2 dollars,3 quarters,4 pennies +1 twenty,1 ten,1 five,4 dollars,3 quarters,2 dimes,4 pennies