diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3a2238d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,245 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ \ No newline at end of file diff --git a/GarethCanfieldCashRegister/GarethCanfieldCashRegister.sln b/GarethCanfieldCashRegister/GarethCanfieldCashRegister.sln new file mode 100644 index 00000000..f97734c9 --- /dev/null +++ b/GarethCanfieldCashRegister/GarethCanfieldCashRegister.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GarethCanfieldCashRegister", "GarethCanfieldCashRegister\GarethCanfieldCashRegister.csproj", "{42721639-5D8A-47B9-AC8C-3D303B7A4665}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{315779CE-947D-41D3-A196-BEED0A9E7EFE}" + ProjectSection(SolutionItems) = preProject + GarethCanfieldCashRegister\bin\Debug\InputFile.txt = GarethCanfieldCashRegister\bin\Debug\InputFile.txt + GarethCanfieldCashRegister\bin\Debug\OutputFile.txt = GarethCanfieldCashRegister\bin\Debug\OutputFile.txt + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {42721639-5D8A-47B9-AC8C-3D303B7A4665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42721639-5D8A-47B9-AC8C-3D303B7A4665}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42721639-5D8A-47B9-AC8C-3D303B7A4665}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42721639-5D8A-47B9-AC8C-3D303B7A4665}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/GarethCanfieldCashRegister/GarethCanfieldCashRegister/App.config b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/App.config new file mode 100644 index 00000000..88fa4027 --- /dev/null +++ b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/GarethCanfieldCashRegister/GarethCanfieldCashRegister/GarethCanfieldCashRegister.csproj b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/GarethCanfieldCashRegister.csproj new file mode 100644 index 00000000..0600cf67 --- /dev/null +++ b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/GarethCanfieldCashRegister.csproj @@ -0,0 +1,60 @@ + + + + + Debug + AnyCPU + {42721639-5D8A-47B9-AC8C-3D303B7A4665} + Exe + Properties + GarethCanfieldCashRegister + GarethCanfieldCashRegister + v4.5.2 + 512 + 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/GarethCanfieldCashRegister/GarethCanfieldCashRegister/Program.cs b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/Program.cs new file mode 100644 index 00000000..9067f7c3 --- /dev/null +++ b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/Program.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; + +namespace GarethCanfieldCashRegister +{ + /// + /// Program.cs will read in cash values for the total cash due and total cash received from the Input File (located in Solution Items), and output the expected cash back using the least + /// amount of US Currency possible (dollars, quarters, dimes, nickels, pennies) to the Output File (located in Solution Items). If the total due in cents is divisible by 3, random change denominations will be used. + /// + /// Created By: Gareth Canfield + /// 1/12/2020 + /// + class Program + { + private static string path = System.IO.Path.Combine(Environment.CurrentDirectory); + private static string inputFile = "InputFile.txt"; + private static string outputFile = "OutputFile.txt"; + private static Random rand = new Random(); + + /// + /// The basic transaction that will include the total due(double), total given(double), if the change will be in random denominations(bool), and if the format is correct(bool) + /// + private class Transaction + { + public double totalDue { get; set; } + public double totalGiven { get; set; } + public bool isRandom { get; set; } + public bool isFormat { get; set; } + } + + private static void Main(string[] args) + { + // List of every line on the Input file saved into a Transaction + var transactionsList = _extractPrices(); + _printChangeDue(transactionsList); + } + + /// + /// Compiles and prints all lines that will be added to the Output file + /// + /// List of transactions that will be analyzed and printed + /// List of strings that contain the text for each output line + private static void _printChangeDue(List transactionsList) + { + var outputLines = new List(); + foreach (var transaction in transactionsList) + { + var changeDue = Math.Round(transaction.totalGiven - transaction.totalDue, 2); + if (!transaction.isFormat) + { + outputLines.Add("**INVALID FORMAT**"); + } + else if (changeDue < 0) + { + outputLines.Add($"ERROR: Insufficient funds were provided! Total due is ${transaction.totalDue.ToString("F" + 2)} but only received ${transaction.totalGiven.ToString("F" + 2)}."); + } + else if (changeDue == 0) + { + outputLines.Add("Exact funds have been provided, no change will be given."); + } + else + { + outputLines.Add(_computeChangeDue(changeDue, transaction.isRandom)); + } + } + System.IO.File.WriteAllLines($"{path}\\{outputFile}", outputLines); + } + + /// + /// Computes how the change due will be split up into US Currencies + /// + /// Current amount of change that is due + /// If true, the change denominations will be computed randomly + /// String containing the change due in formatted US currencies + private static string _computeChangeDue(double changeDue, bool isRandom) + { + var endString = ""; + Dictionary tenders = new Dictionary(); + tenders.Add("dollar", 1.0); + tenders.Add("quarter", 0.25); + tenders.Add("dime", 0.1); + tenders.Add("nickel", 0.05); + tenders.Add("penny", 0.01); + if (isRandom) + { + tenders = _randomizeTenders(tenders); + } + var firstPrint = true; + foreach (KeyValuePair tender in tenders) + { + long counter = 0; + if (tender.Key.Equals("penny")) //Pennies will always be needed for certain values (ex. $1.87) + { + if (changeDue != 0) + { + counter = Convert.ToInt64(changeDue / tender.Value); + changeDue = 0; + } + } + else if (!isRandom) //If this is not random, it will calculate the maximum amount of each specific tender for the current change due + { + if (changeDue >= tender.Value) + { + counter = Convert.ToInt64(Math.Floor(changeDue / tender.Value)); + changeDue -= (counter * tender.Value); + } + } + else //If this is random, it will calculate a random amount of each specific tender for the current change do + { + if (changeDue > tender.Value) + { + var maxTenderAmount = Convert.ToInt64(Math.Floor(changeDue / tender.Value)); + counter = randomLong(0, maxTenderAmount + 1); + changeDue -= (counter * tender.Value); + } + } + if (counter != 0) + { + if (!firstPrint) + { + endString += ", "; + } + firstPrint = false; + endString += $"{counter.ToString()} {tender.Key}"; + if (counter > 1) + { + if (tender.Key.Equals("penny")) + { + endString = endString.TrimEnd('y'); + endString += "ies"; + } + else + { + endString += "s"; + } + } + } + } + return endString; + } + + /// + /// Randomizes the tenders that will be used to calculate change due + /// + /// List of all expected US tenders that are being used + /// List of random US tenders (always includes pennies) + private static Dictionary _randomizeTenders(Dictionary tenders) + { + var tendersToRemove = new List { }; + tenders.Remove("penny"); + foreach (KeyValuePair tender in tenders) + { + var randomization = rand.Next(2); + if (randomization == 0) + { + tendersToRemove.Add(tender.Key); + } + } + foreach (var tender in tendersToRemove) + { + tenders.Remove(tender); + } + tenders.Add("penny", 0.01); + return tenders; + } + + /// + /// Calculates a random Long number between the given parameters + /// + /// Minimum number to be returned + /// Maximum number to be returned + /// Random long value + private static long randomLong(long min, long max) + { + long result = rand.Next((Int32)(min >> 32), (Int32)(max >> 32)); + result = (result << 32); + result = result | (long)rand.Next((Int32)min, (Int32)max); + return result; + } + + /// + /// Extracts the prices from every line in the Input file into a list of Transactions, calculating if the change denominations will be random and if the format is correct + /// + /// List of Transactions based off of the Input file's contents + private static List _extractPrices() + { + var lineCounter = 1; + string[] lines = System.IO.File.ReadAllLines($"{path}\\{inputFile}"); + var expectedValues = new List> { }; + foreach (var line in lines) + { + var formatChecker = true; + var inputNumbers = line.Split(','); + try + { + expectedValues.Add(Tuple.Create(Math.Round(Convert.ToDouble(inputNumbers[0]), 2), Math.Round(Convert.ToDouble(inputNumbers[1]), 2), formatChecker)); + } + catch (FormatException fmex) + { + Console.WriteLine($"ERROR: Input at line #{lineCounter} was not provided in the expected format.\r\n{fmex}"); + expectedValues.Add(Tuple.Create(00.00, 00.00, false)); + } + catch (IndexOutOfRangeException iore) + { + Console.WriteLine($"ERROR: Input at line #{lineCounter} was not provided in the expected format.\r\n{iore}"); + expectedValues.Add(Tuple.Create(00.00, 00.00, false)); + } + ++lineCounter; + } + var pricesAndPayments = new List { }; + foreach (var expectedValue in expectedValues) + { + pricesAndPayments.Add(new Transaction { totalDue = expectedValue.Item1, totalGiven = expectedValue.Item2, isRandom = Convert.ToDecimal(expectedValue.Item1) % 0.03M == 0, isFormat = expectedValue.Item3 }); + } + return pricesAndPayments; + } + } +} diff --git a/GarethCanfieldCashRegister/GarethCanfieldCashRegister/Properties/AssemblyInfo.cs b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0077ba4e --- /dev/null +++ b/GarethCanfieldCashRegister/GarethCanfieldCashRegister/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("GarethCanfieldCashRegister")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GarethCanfieldCashRegister")] +[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("42721639-5d8a-47b9-ac8c-3d303b7a4665")] + +// 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")]