Peter
Peter Campbell Smith

Change and loops

Weekly challenge 236 — 25 September 2023

Week 236 - 25 Sep 2023

Task 1

Task — Exact change

You are asked to sell juice each costs $5. You are given an array of bills. You can only sell ONE juice to each customer but make sure you return exact change back. You only have $5, $10 and $20 notes. You do not have any change in hand at first. Write a script to find out if it is possible to sell to each customers with correct change.

Examples


Example 1
Input: @bills = (5, 5, 5, 10, 20)
Output: true

From the first 3 customers, we collect three $5 bills in order.
From the fourth customer, we collect a $10 bill and give back a $5.
From the fifth customer, we give a $10 bill and a $5 bill.
Since all customers got correct change, we output true.

Example 2
Input: @bills = (5, 5, 10, 10, 20)
Output: false

From the first two customers in order, we collect two $5 bills.
For the next two customers in order, we collect a $10 bill and give back a $5 bill.
For the last customer, we can not give the change of $15 back because we only have two $10 bills.
Since not every customer received the correct change, the answer is false.

Example 3
Input: @bills = (5, 5, 5, 20)
Output: true

Analysis

I think the easiest way to do this is just to mimic real life.

We start with nothing in the till.

A customer offering $5 can always be served.

A customer offering $10 can only be served if there is at least one $5 in the till.

A customer offering $20 can be served and given $10 + $5 from the till if that is possible, or 3 x $5 if that is possible, otherwise can't be served.

In each successful case the bill tendered by the customer gets added to the till, and we can check that the total in the till is always $5 x the number of customers served.

We might also note that even in this day of rapidly rising prices, $5 for a bottle of juice is rather steep. I suggest they'd all be better off going to Aldi.

Try it 

Try running the script with any input, for example:
5, 5, 10, 20


Script


#!/usr/bin/perl

use v5.16;    # The Weekly Challenge - 2023-09-25
use utf8;     # Week 236 task 1 - Exact change
use strict;   # Peter Campbell Smith
use warnings; # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

exact_change(5, 5, 5, 10, 20);
exact_change(5, 5, 10, 10, 20);
exact_change(5, 5, 5, 20);
exact_change(5, 5, 10, 20);

sub exact_change {
    
    my (@bills, $bill, $change, @till, $ok, $explain, $j);
    
    # initialise
    @bills = @_;
    $ok = 'true';
    
    # till starts empty
    $till[5] = $till[10] = $till[20] = 0;
    
    # loop over customers
    for $bill (@bills) {
        $explain .= qq[\n   \$$bill paid];
        $change = $bill - 5;
        
        # customer presents $5 - no change needed
        if ($change == 0) {
            $explain .= q[, no change due];
        
        # customer presents $10 so give him $5 change if we have a $5
        } elsif ($change == 5) {
            if ($till[5] > 0) {
                $till[5] --;
                $explain .= q[, $5 change];
            } else {
                $ok = 'false'; # we don't
            }
        
        # customer presents $20 so give her a $10 and a $5, or 3 x $5
        } elsif ($change == 15) {
            if ($till[10] > 0 and $till[5] > 0) {
                $till[10] --;
                $till[5] --;
                $explain .= q[, $10 + $5 change];
            } elsif ($till[5] >= 3) {
                $till[5] -= 3;
                $explain .= q[, 3 x $5 change];
            } else {
                $ok = 'false'; # we have neither
            }
        }
        
        # oh dear!
        unless ($ok eq 'true') {
            $explain .= q[, sorry, I don't have change];
            last;
        }
            
        # add customer's payment to till
        $till[$bill] ++;
        $explain .= qq[, till now $till[5] x \$5, $till[10] x \$10 $till[20] x \$20 = \$] .
            ($till[5] * 5 + $till[10] * 10 + $till[20] * 20);
    }       
    
    say qq[\nInput: \@bills = (] . join(', ', @bills) . ')';
    say qq[Output: $ok$explain];
}

Output


Input: @bills = (5, 5, 5, 10, 20)
Output: true
   $5 paid, no change due, till now 1 x $5, 0 x $10 0 x $20 = $5
   $5 paid, no change due, till now 2 x $5, 0 x $10 0 x $20 = $10
   $5 paid, no change due, till now 3 x $5, 0 x $10 0 x $20 = $15
   $10 paid, $5 change, till now 2 x $5, 1 x $10 0 x $20 = $20
   $20 paid, $10 + $5 change, till now 1 x $5, 0 x $10 1 x $20 = $25

Input: @bills = (5, 5, 10, 10, 20)
Output: false
   $5 paid, no change due, till now 1 x $5, 0 x $10 0 x $20 = $5
   $5 paid, no change due, till now 2 x $5, 0 x $10 0 x $20 = $10
   $10 paid, $5 change, till now 1 x $5, 1 x $10 0 x $20 = $15
   $10 paid, $5 change, till now 0 x $5, 2 x $10 0 x $20 = $20
   $20 paid, sorry, I don't have change

Input: @bills = (5, 5, 5, 20)
Output: true
   $5 paid, no change due, till now 1 x $5, 0 x $10 0 x $20 = $5
   $5 paid, no change due, till now 2 x $5, 0 x $10 0 x $20 = $10
   $5 paid, no change due, till now 3 x $5, 0 x $10 0 x $20 = $15
   $20 paid, 3 x $5 change, till now 0 x $5, 0 x $10 1 x $20 = $20

Input: @bills = (5, 5, 10, 20)
Output: true
   $5 paid, no change due, till now 1 x $5, 0 x $10 0 x $20 = $5
   $5 paid, no change due, till now 2 x $5, 0 x $10 0 x $20 = $10
   $10 paid, $5 change, till now 1 x $5, 1 x $10 0 x $20 = $15
   $20 paid, $10 + $5 change, till now 0 x $5, 0 x $10 1 x $20 = $20