Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 29 additions & 11 deletions c/src/printer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
#include <string.h>
#include "printer.h"

// Constants for receipt formatting
#define QUANTITY_THRESHOLD 1
#define PRICE_DECIMAL_PLACES 2
#define WEIGHT_DECIMAL_PLACES 3
#define INTEGER_DECIMAL_PLACES 0

// Format strings
#define PRICE_FORMAT "%.2f"
#define WEIGHT_FORMAT "%.3f"
#define INTEGER_FORMAT "%.0f"

// Display strings
#define UNIT_PRICE_INDENT " "
#define MULTIPLICATION_SYMBOL "*"
#define TOTAL_LABEL "Total:"
#define WHITESPACE_CHAR ' '
#define NEWLINE "\n"

void printReceiptItem(char *buffer, struct receipt_item_t *item);

void printDiscount(char *buffer, struct discount_t *pDiscount);
Expand All @@ -15,46 +33,46 @@ void print_receipt(char* buffer, struct receipt_t* receipt) {
for (int i = 0; i < receipt->discountCount; ++i) {
printDiscount(buffer, &receipt->discounts[i]);
}
sprintf(buffer + strlen(buffer), "\n");
sprintf(buffer + strlen(buffer), NEWLINE);

print_total(buffer, receipt);

}

void printReceiptItem(char *buffer, struct receipt_item_t *item) {
char price[MAX_NAME_LENGTH];
sprintf(price, "%.2f", (*item).totalPrice);
sprintf(price, PRICE_FORMAT, (*item).totalPrice);
char name[MAX_NAME_LENGTH];
sprintf(name, "%s", (*item).product->name);

char line[LINE_LENGTH];
print_line(line, name, price);
sprintf(buffer + strlen(buffer), "%s", line);

if (item->quantity != 1) {
if (item->quantity != QUANTITY_THRESHOLD) {
char line2[LINE_LENGTH];
if (item->product->unit == Each) {
sprintf(line2, " %.2f*%.0f", item->price, item->quantity);
sprintf(line2, UNIT_PRICE_INDENT PRICE_FORMAT MULTIPLICATION_SYMBOL INTEGER_FORMAT, item->price, item->quantity);
} else {
sprintf(line2, " %.2f*%.3f", item->price, item->quantity);
sprintf(line2, UNIT_PRICE_INDENT PRICE_FORMAT MULTIPLICATION_SYMBOL WEIGHT_FORMAT, item->price, item->quantity);
}
sprintf(buffer + strlen(buffer), "%s\n", line2);
sprintf(buffer + strlen(buffer), "%s" NEWLINE, line2);
}
}

void print_total(char *buffer, struct receipt_t *receipt) {
char total[MAX_NAME_LENGTH];
sprintf(total, "%0.2f", total_price(receipt));
sprintf(total, PRICE_FORMAT, total_price(receipt));
char total_line[LINE_LENGTH];
print_line(total_line, "Total:", total);
print_line(total_line, TOTAL_LABEL, total);
sprintf(buffer + strlen(buffer), "%s", total_line);
}

void printDiscount(char *buffer, struct discount_t *discount) {
char name[LINE_LENGTH];
sprintf(name, "%s(%s)", discount->description, discount->product->name);
char price[MAX_NAME_LENGTH];
sprintf(price, "%.2f", discount->amount);
sprintf(price, PRICE_FORMAT, discount->amount);

char line[LINE_LENGTH];
print_line(line, name, price);
Expand All @@ -67,9 +85,9 @@ print_line(char *buffer, const char *key, const char *value) {
int whitespace_length = LINE_LENGTH - strlen(key) - strlen(value);
char whitespace[whitespace_length];
for (int i = 0; i < whitespace_length -1; ++i) {
whitespace[i] = ' ';
whitespace[i] = WHITESPACE_CHAR;
}
whitespace[whitespace_length-1] = '\0';

sprintf(buffer, "%s%s%s\n", key, whitespace, value );
sprintf(buffer, "%s%s%s" NEWLINE, key, whitespace, value );
}
33 changes: 21 additions & 12 deletions c/src/supermarket.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
#include <stdio.h>
#include "supermarket.h"

// Constants for special offers
#define THREE_FOR_TWO_QUANTITY 3
#define TWO_FOR_AMOUNT_QUANTITY 2
#define FIVE_FOR_AMOUNT_QUANTITY 5
#define TWO_FOR_AMOUNT_MIN_QUANTITY 2
#define THREE_FOR_TWO_MIN_QUANTITY 2
#define FIVE_FOR_AMOUNT_MIN_QUANTITY 5
#define PERCENT_DIVISOR 100.0

struct product_t* product_create(char* name, enum unit unit) {
struct product_t* product = malloc(sizeof(*product));
strncpy(product->name, name, sizeof(product->name) - 1);
Expand Down Expand Up @@ -76,34 +85,34 @@ void handle_offers(struct cart_t* cart, struct receipt_t* receipt, struct specia
int x = 1;

if (offer->type == ThreeForTwo) {
x = 3;
x = THREE_FOR_TWO_QUANTITY;
} else if (offer->type == TwoForAmount) {
x = 2;
if (quantityAsInt >= 2) {
double total = offer->argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice;
x = TWO_FOR_AMOUNT_QUANTITY;
if (quantityAsInt >= TWO_FOR_AMOUNT_MIN_QUANTITY) {
double total = offer->argument * (quantityAsInt / x) + quantityAsInt % TWO_FOR_AMOUNT_QUANTITY * unitPrice;
double discountN = unitPrice * quantity - total;
char description[MAX_NAME_LENGTH];
sprintf(description, "2 for %f", offer->argument);
sprintf(description, "%d for %f", TWO_FOR_AMOUNT_QUANTITY, offer->argument);
discount = discount_create(description, -discountN, &product);
}
} if (offer->type == FiveForAmount) {
x = 5;
x = FIVE_FOR_AMOUNT_QUANTITY;
}
int numberOfXs = quantityAsInt / x;
if (offer->type == ThreeForTwo && quantityAsInt > 2) {
double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice);
if (offer->type == ThreeForTwo && quantityAsInt > THREE_FOR_TWO_MIN_QUANTITY) {
double discountAmount = quantity * unitPrice - ((numberOfXs * TWO_FOR_AMOUNT_QUANTITY * unitPrice) + quantityAsInt % THREE_FOR_TWO_QUANTITY * unitPrice);
char description[MAX_NAME_LENGTH];
sprintf(description, "3 for 2");
sprintf(description, "%d for %d", THREE_FOR_TWO_QUANTITY, TWO_FOR_AMOUNT_QUANTITY);
discount = discount_create(description, -discountAmount, &product);
}
if (offer->type == TenPercentDiscount) {
char description[MAX_NAME_LENGTH];
sprintf(description, "%.0f%% off", offer->argument);
discount = discount_create(description, -quantity * unitPrice * offer->argument / 100.0, &product);
discount = discount_create(description, -quantity * unitPrice * offer->argument / PERCENT_DIVISOR, &product);

}
if (offer->type == FiveForAmount && quantityAsInt >= 5) {
double discountTotal = unitPrice * quantity - (offer->argument * numberOfXs + quantityAsInt % 5 * unitPrice);
if (offer->type == FiveForAmount && quantityAsInt >= FIVE_FOR_AMOUNT_MIN_QUANTITY) {
double discountTotal = unitPrice * quantity - (offer->argument * numberOfXs + quantityAsInt % FIVE_FOR_AMOUNT_QUANTITY * unitPrice);
char description[MAX_NAME_LENGTH];
sprintf(description, "%d for %f", x, offer->argument);
discount = discount_create(description, -discountTotal, &product);
Expand Down
28 changes: 21 additions & 7 deletions common-lisp/source/receipt-printer.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@

(in-package :supermarket-receipt)

;; Constants for receipt formatting
(defconstant +default-columns+ 40)
(defconstant +quantity-threshold+ 1.0)
(defconstant +price-decimal-places+ 2)
(defconstant +weight-decimal-places+ 3)

;; Display strings
(defconstant +unit-price-indent+ " ")
(defconstant +multiplication-symbol+ " * ")
(defconstant +total-label+ "Total: ")
(defconstant +whitespace-char+ " ")

(defclass receipt-printer ()
((columns :initarg :columns
:initform 40
:initform +default-columns+
:type integer
:accessor printer-columns)))

Expand All @@ -22,35 +34,37 @@
(let* ((total-price-printed (print-price a-printer (item-total-price an-item)))
(name (product-name (item-product an-item)))
(line (format-line-with-whitespace a-printer name total-price-printed)))
(unless (= 1.0 (item-quantity an-item))
(setf line (format nil "~A ~A * ~A~%" line
(unless (= +quantity-threshold+ (item-quantity an-item))
(setf line (format nil "~A~A~A~A~A~%" line
+unit-price-indent+
(print-price a-printer (item-price an-item))
+multiplication-symbol+
(print-quantity a-printer an-item))))
line))

(defmethod format-line-with-whitespace ((a-printer receipt-printer) (a-name string) (a-value string))
(let* ((line a-name)
(whitespace-size (- (printer-columns a-printer) (length a-name) (length a-value))))
(loop for index from 1 to whitespace-size do
(setf line (concatenate 'string line " ")))
(setf line (concatenate 'string line +whitespace-char+)))
(setf line (concatenate 'string line a-value))
(setf line (format nil "~A~%" line))
line))

(defmethod print-price ((a-printer receipt-printer) (a-price single-float))
(format nil "~2$" a-price))
(format nil (format nil "~~~d$" +price-decimal-places+) a-price))

(defmethod print-quantity ((a-printer receipt-printer) (an-item receipt-item))
(if (eq 'each (the-product-unit (item-product an-item)))
(format nil "~d" (floor (item-quantity an-item)))
(format nil "~3$" (item-quantity an-item))))
(format nil (format nil "~~~d$" +weight-decimal-places+) (item-quantity an-item))))

(defmethod print-discount ((a-printer receipt-printer) (a-discount discount))
(let ((name (format nil "~A(~A)" (discount-description a-discount) (product-name (discounted-product a-discount))))
(value (print-price a-printer (discount-amount a-discount))))
(format-line-with-whitespace a-printer name value)))

(defmethod present-total ((a-printer receipt-printer) (a-receipt receipt))
(let ((name "Total: ")
(let ((name +total-label+)
(value (print-price a-printer (total-price a-receipt))))
(format-line-with-whitespace a-printer name value)))
31 changes: 22 additions & 9 deletions csharp/SupermarketReceipt.Test/ReceiptPrinter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ namespace SupermarketReceipt
{
public class ReceiptPrinter
{
// Constants for receipt formatting
private const int DefaultColumns = 40;
private const int QuantityThreshold = 1;
private const int PriceDecimalPlaces = 2;
private const int WeightDecimalPlaces = 3;

// Display strings
private const string UnitPriceIndent = " ";
private const string MultiplicationSymbol = " * ";
private const string TotalLabel = "Total: ";
private const string WhitespaceChar = " ";
private const string Newline = "\n";

private static readonly CultureInfo Culture = CultureInfo.CreateSpecificCulture("en-GB");

private readonly int _columns;
Expand All @@ -15,7 +28,7 @@ public ReceiptPrinter(int columns)
_columns = columns;
}

public ReceiptPrinter() : this(40)
public ReceiptPrinter() : this(DefaultColumns)
{
}

Expand All @@ -36,15 +49,15 @@ public string PrintReceipt(Receipt receipt)
}

{
result.Append("\n");
result.Append(Newline);
result.Append(PrintTotal(receipt));
}
return result.ToString();
}

private string PrintTotal(Receipt receipt)
{
string name = "Total: ";
string name = TotalLabel;
string value = PrintPrice(receipt.GetTotalPrice());
return FormatLineWithWhitespace(name, value);
}
Expand All @@ -62,9 +75,9 @@ private string PrintReceiptItem(ReceiptItem item)
string totalPrice = PrintPrice(item.TotalPrice);
string name = item.Product.Name;
string line = FormatLineWithWhitespace(name, totalPrice);
if (item.Quantity != 1)
if (item.Quantity != QuantityThreshold)
{
line += " " + PrintPrice(item.Price) + " * " + PrintQuantity(item) + "\n";
line += UnitPriceIndent + PrintPrice(item.Price) + MultiplicationSymbol + PrintQuantity(item) + Newline;
}

return line;
Expand All @@ -77,23 +90,23 @@ private string FormatLineWithWhitespace(string name, string value)
line.Append(name);
int whitespaceSize = this._columns - name.Length - value.Length;
for (int i = 0; i < whitespaceSize; i++) {
line.Append(" ");
line.Append(WhitespaceChar);
}
line.Append(value);
line.Append('\n');
line.Append(Newline);
return line.ToString();
}

private string PrintPrice(double price)
{
return price.ToString("N2", Culture);
return price.ToString("N" + PriceDecimalPlaces, Culture);
}

private static string PrintQuantity(ReceiptItem item)
{
return ProductUnit.Each == item.Product.Unit
? ((int) item.Quantity).ToString()
: item.Quantity.ToString("N3", Culture);
: item.Quantity.ToString("N" + WeightDecimalPlaces, Culture);
}

}
Expand Down
7 changes: 7 additions & 0 deletions go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,10 @@ require (
github.com/approvals/go-approval-tests v0.0.0-20220530063708-32d5677069bd
golang.org/x/text v0.4.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
9 changes: 9 additions & 0 deletions go/go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
github.com/approvals/go-approval-tests v0.0.0-20220530063708-32d5677069bd h1:8j7sBEy0h6+Bvr0AeKHIHCsmzCzWGXAQweA7k+uiRYk=
github.com/approvals/go-approval-tests v0.0.0-20220530063708-32d5677069bd/go.mod h1:PJOqSY8IofNv3heAD6k8E7EfFS6okiSS9bSAasaAUME=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading