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