Skip to content

Instantly share code, notes, and snippets.

@dduugg
Created May 18, 2020 20:21
Show Gist options
  • Save dduugg/765f0d3006cd46bdb853afc613c6396d to your computer and use it in GitHub Desktop.
Save dduugg/765f0d3006cd46bdb853afc613c6396d to your computer and use it in GitHub Desktop.
Programming challenge: Supermarket billing
-module(billing).
% use print_bill/1 for the defualt items/1 list, or supply your
% own using print_bill/2 and the remove_item/1 and
% upate_item/1 APIs
-export([items/0, print_bill/1, print_bill/2,
remove_item/2, test/0, update_item/2]).
items() ->
[{4719, "Fish Fingers", 121}, {5643, "Nappies", 1010},
{3814, "Orange Jelly", 56}, {1111, "Hula Hoops", 21},
{1112, "Hula Hoops (Giant)", 133},
{1234, "Dry Sherry, 1lt", 540}].
% helper function used to calculate bulk discounts
item_count([], _) -> 0;
item_count([Barcode | Barcodes], Item) ->
case Barcode of
Item -> 1 + item_count(Barcodes, Item);
_ -> item_count(Barcodes, Item)
end.
test_item_count() ->
2 = item_count([1234, 4719, 1234], 1234).
% removes an item from a list of items, if present
remove_item([], _) -> [];
remove_item([{Barcode, _, _} | Items], Barcode) ->
Items;
remove_item([Item | Items], Barcode) ->
[Item] ++ remove_item(Items, Barcode).
test_remove_item() ->
[{4719, "Fish Fingers", 121}] = remove_item([{4719,
"Fish Fingers", 121},
{5643, "Nappies", 1010}],
5643),
[{4719, "Fish Fingers", 121}, {5643, "Nappies", 1010}] =
remove_item([{4719, "Fish Fingers", 121},
{5643, "Nappies", 1010}],
1),
ok.
% adds or updates an item matching Barcode in a list of items
update_item(Items, {Barcode, Name, Cost}) ->
remove_item(Items, Barcode) ++ [{Barcode, Name, Cost}].
test_update_item() ->
[{5643, "Nappies", 1010},
{4719, "Deluxe Fish Fingers", 250}] =
update_item([{4719, "Fish Fingers", 121},
{5643, "Nappies", 1010}],
{4719, "Deluxe Fish Fingers", 250}),
ok.
% prints a bill to the console, given a list of barcodes
print_bill(Barcodes) -> print_bill(Barcodes, items()).
print_bill(Barcodes, Inventory) ->
Discount = -100 * item_count(Barcodes, 1234) div 2,
io:format("~s",
[string:join(print_bill(Barcodes, [], 0, 30, Discount,
Inventory),
"\n")
++ "\n"]).
print_bill([], Lines, Total, Width, Discount, _) ->
DiscountLines = case Discount of
0 -> [];
_ -> ["", format_line_item("Discount", Discount, Width)]
end,
[" Erlang Stores", ""] ++
Lines ++
DiscountLines ++
["",
format_line_item("Total", Total + Discount, Width)];
print_bill([Barcode | Barcodes], Lines, Total, Width,
Discount, Inventory) ->
{Name, Cost} = lookup_barcode(Barcode, Inventory),
case lookup_barcode(Barcode, Inventory) of
{Name, Cost} ->
Line = format_line_item(Name, Cost, Width),
print_bill(Barcodes, Lines ++ [Line], Total + Cost,
Width, Discount, Inventory);
_ ->
print_bill(Barcodes, Lines, Total, Width, Discount,
Inventory)
end.
test_print_bill() ->
[" Erlang Stores", "", "",
"Total.....................0.00"] =
print_bill([], [], 0, 30, 0, items()),
[" Erlang Stores", "",
"Dry Sherry, 1lt...........5.40",
"Fish Fingers..............1.21", "",
"Total.....................6.61"] =
print_bill([1234, 4719], [], 0, 30, 0, items()),
[" Erlang Stores", "",
"Dry Sherry, 1lt...........5.40",
"Fish Fingers..............1.21",
"Dry Sherry, 1lt...........5.40", "",
"Discount.................-1.00", "",
"Total....................11.01"] =
print_bill([1234, 4719, 1234], [], 0, 30, -100,
items()),
ok.
% Formats Name and Cost as a string of legth Width
format_line_item(Name, Cost, Width) ->
Right = format_cost(Cost),
Left = string:left(Name, Width - length(Right), $.),
Left ++ Right.
test_format_line_item() ->
"Fish Fingers..............1.21" =
format_line_item("Fish Fingers", 121, 30),
ok.
% format an int representing cents as a string representing dollars
format_cost(Digits) ->
format_cost(integer_to_list(Digits), "").
format_cost([Digit], "") -> "0.0" ++ [Digit];
format_cost([Dimes, Cents], "") ->
"0." ++ [Dimes, Cents];
format_cost([Dimes, Cents], Acc) ->
Acc ++ "." ++ [Dimes, Cents];
format_cost([Digit | Digits], Acc) ->
format_cost(Digits, Acc ++ [Digit]).
test_format_cost() ->
"0.00" = format_cost(0),
"0.56" = format_cost(56),
"5.40" = format_cost(540),
"13.90" = format_cost(1390),
ok.
% returns the item name and cost for a barcode
lookup_barcode(Barcode) ->
lookup_barcode(Barcode, items()).
lookup_barcode(_, []) -> {}; % or {"Unknown Item", 0};
lookup_barcode(Barcode, [{Code, Name, Cost} | Items]) ->
case Code of
Barcode -> {Name, Cost};
_ -> lookup_barcode(Barcode, Items)
end.
test_lookup_barcode() ->
{"Hula Hoops", 21} = lookup_barcode(1111), ok.
test() ->
test_item_count(),
test_remove_item(),
test_update_item(),
test_format_cost(),
test_format_line_item(),
test_lookup_barcode(),
test_print_bill(),
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment