diff --git a/Cash_Register.py b/Cash_Register.py new file mode 100644 index 00000000..1d6d2cc0 --- /dev/null +++ b/Cash_Register.py @@ -0,0 +1,40 @@ +''' + Author: Connor Johnson + Completed: 09/06/2021 + Contains the main code to be run for the Cash Register project +''' + +import sys +from calculate_change import * + +# Read in data from text file +with open(sys.argv[1], 'r') as f: + lines = f.readlines() + + +# Loop through each line in the text file +counter = 0 # Counter for tracking which line the loop is on +for s in lines: + counter = counter + 1 + + # Input from text file is checked that it's formatted correctly and values are assigned + nums = s.split(",") + if len(nums) != 2: + print("Line " + str(counter) + " of input.txt must contain 2 numbers separated by a comma.") + continue + try: + cents = float(nums[1]) - float(nums[0]) #Calculate the change to be given + except ValueError: + print("Line " + str(counter) + " of input.txt must contain 2 numbers separated by a comma.") + continue + + cents = int(cents*100+0.5) # Change cents to an integer that represents the total cents in change + + final_change = calculate_change(cents) + if final_change == None: + print("Invalid Input. Total due can't be more than amount paid.") + else: + print(final_change[0]) + + + diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..514fc1d6 --- /dev/null +++ b/README.txt @@ -0,0 +1,37 @@ +Connor Johnson +Cash Register Project +Completed: 09/06/2021 + + +This project is used to find the coins that would be needed to give a certain amount of change. It takes a text file as input that should contain a list of values. +Each line in the text file should contain 2 numbers separated by a comma. The first number is the price of something that is being payed for. The second number is the amount +of money that the customer payed with. The program takes these numbers and returns the change that should be given back to the customers in dollars and coins. It normally +gives change in the least possible number of coins, except when the total change in cents is divisible by three. In this case, the different denominations of change given +is randomized while still adding up to the correct amount of change. If any lines in the input file are formatted incorrectly, they will be skipped, and the user will be +notified of the incorrectly formatted lines. The test python file contains unit tests to make sure the calculate change method works correctly for a range of values. + +Files: Cash_Register.py, calculate_change.py, calculate_change_test.py + +Cash_Register.py: This is the file that contains the main and is used to the run the applicaiton. +calculate_change.py: Contains a method that calculates the change and is called by Cash_Register.py +calculate_change_test.py: Contains a few unit tests to test the functionality of calculate_change.py + +Running the application: Type the following command in the terminal +python Cash_Register.py [filename] +Example: python Cash_Register.py input.txt + +Example Input: +1.33, 2.00 +2.71,4.00 +1.45,%4.00^ +1.50 + +Example Output: +2 quarters, 1 dime, 1 nickel, 2 pennies +3 quarters, 1 dime, 1 nickel, 39 pennies +Line 3 of input.txt must contain 2 numbers separated by a comma. +Line 4 of input.txt must contain 2 numbers separated by a comma. + +Modules: random, numpy, sys + +Known Bugs: There are currently no known bugs contained in this project. \ No newline at end of file diff --git a/calculate_change.py b/calculate_change.py new file mode 100644 index 00000000..3158911c --- /dev/null +++ b/calculate_change.py @@ -0,0 +1,59 @@ +''' + Author: Connor Johnson + Completed: 09/06/2021 + Contains the calculate_change method used in Cash_Register.py +''' + +import random + +# Names and values of coin denominations, pennies are excluded because they are handled differently +coin_values = [100, 25, 10, 5] +coin_names = ['dollar', 'quarter', 'dime', 'nickel'] + + +def calculate_change(cents): + ''' + calculate_change takes an amount in cents and calculates the change in coins that would be given for this amount + cents: The amount of cents in change as an integer + return: Returns a tuple containing a string that has the description of change and a list containing the value of each denomination; dollars, quarters, etc. + Returns None if cents is not a positive integer + ''' + # Checks that cents is a positive integer + if type(cents) != int or cents < 0: + return None + # Handles if cents is equal to zero + if cents == 0: + return ('No change', [0,0,0,0,0]) + + coin_string = '' # Final string to be returned + div_by_3 = cents%3 == 0 # Boolean variable that is true if the total change is divisible by 3 + + coin_cents = [0] * 5 # Tracks the number of each denomination, will be returned by this function + + for i in range(0,4): + # Number of each denomination is determined, picked randomly if the total cents is divisible by 3 + if(div_by_3): + num_coins = random.randint(0,int(cents/coin_values[i])) + cents = cents - num_coins*coin_values[i] + else: + num_coins = int(cents/coin_values[i]) + cents = cents%coin_values[i] + + coin_cents[i] = num_coins + + if num_coins == 0: # Add nothing to string if number of that coin type is zero + continue + + # Add the number of each denomination to the final string + coin_string = coin_string + str(num_coins) + ' ' + coin_names[i] + if num_coins > 1: + coin_string = coin_string + 's' + coin_string = coin_string + ', ' + + # All remaining cents are set as pennies + coin_cents[4] = cents + if cents > 0: + coin_string = coin_string + '1 penny' if cents == 1 else coin_string + str(cents) + ' pennies' + + # The resulting string and array of coins is returned + return (coin_string, coin_cents) \ No newline at end of file diff --git a/calculate_change_test.py b/calculate_change_test.py new file mode 100644 index 00000000..413a7836 --- /dev/null +++ b/calculate_change_test.py @@ -0,0 +1,22 @@ +''' + Author: Connor Johnson + Completed: 09/06/2021 + Contains some unit tests for calculate_change method +''' + +from calculate_change import * +import numpy + +coin_values = [100, 25, 10, 5, 1] + +# Testing a range of positive values +for t in range(0, 500): + change = numpy.dot(calculate_change(t)[1], coin_values) + assert change == t, "Change is not the correct amount. Should be " + str(t) + ", but return is " + str(change) + +# Testing a range of negative values +for t in range(-100, 0): + assert calculate_change(t) == None, "Method should return None since it is passed a negative integer" + +# Testing a non integer argument +assert calculate_change("some_string") == None, "Method chould return none since it is passed a non integer" \ No newline at end of file