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
1 change: 1 addition & 0 deletions _codeql_detected_source_root
41 changes: 27 additions & 14 deletions c/src/supermarket.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
#include <stdio.h>
#include "supermarket.h"

// Constants for magic numbers
#define DEFAULT_ITEM_QUANTITY 1.0
#define TWO_FOR_AMOUNT_QUANTITY 2
#define THREE_FOR_TWO_QUANTITY 3
#define FIVE_FOR_AMOUNT_QUANTITY 5
#define PERCENTAGE_DIVISOR 100.0

// Constants for discount description strings
#define THREE_FOR_TWO_DESCRIPTION "3 for 2"
#define TWO_FOR_FORMAT "2 for %f"
#define FOR_FORMAT "%d for %f"
#define PERCENT_OFF_FORMAT "%.0f%% off"

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,36 +89,36 @@ 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_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, TWO_FOR_FORMAT, 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 > TWO_FOR_AMOUNT_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, THREE_FOR_TWO_DESCRIPTION);
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);
sprintf(description, PERCENT_OFF_FORMAT, offer->argument);
discount = discount_create(description, -quantity * unitPrice * offer->argument / PERCENTAGE_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_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);
sprintf(description, FOR_FORMAT, x, offer->argument);
discount = discount_create(description, -discountTotal, &product);
}
if (discount != NULL) {
Expand Down
36 changes: 23 additions & 13 deletions common-lisp/source/shopping-cart.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

(in-package :supermarket-receipt)

;;; Constants for magic numbers
(defconstant +default-item-quantity+ 1.0)
(defconstant +two-for-amount-quantity+ 2)
(defconstant +three-for-two-quantity+ 3)
(defconstant +five-for-amount-quantity+ 5)
(defconstant +percentage-divisor+ 100.0)

;;; Constants for discount description strings
(defconstant +three-for-two-description+ "3 for 2")

(defclass shopping-cart ()
((items :initform nil
:type list
Expand All @@ -11,7 +21,7 @@
:accessor shopping-cart-product-quantities)))

(defmethod add-item ((a-cart shopping-cart) (an-item product))
(add-item-quantity a-cart an-item 1.0))
(add-item-quantity a-cart an-item +default-item-quantity+))

(defmethod add-item-quantity ((a-cart shopping-cart) (an-item product) (a-quantity single-float))
(push (make-instance 'product-quantity
Expand All @@ -35,39 +45,39 @@
(x 1)
(the-offer-type (offer-type offer-for-product)))
(if (eq the-offer-type 'three-for-two)
(setf x 3)
(setf x +three-for-two-quantity+)
(when (eq the-offer-type 'two-for-amount)
(setf x 2)
(when (>= floored-quantity 2)
(setf x +two-for-amount-quantity+)
(when (>= floored-quantity +two-for-amount-quantity+)
(let* ((total (+ (* (offer-argument offer-for-product) (floor (/ floored-quantity x)))
(* (mod floored-quantity 2) a-unit-price)))
(* (mod floored-quantity +two-for-amount-quantity+) a-unit-price)))
(discount-n (- (* a-unit-price a-quantity) total)))
(setf a-discount (make-instance 'discount
:product a-product
:description (format nil "2 for ~S" (offer-argument offer-for-product))
:amount (- discount-n)))))))
(when (eq the-offer-type 'five-for-amount)
(setf x 5))
(setf x +five-for-amount-quantity+))
(let ((number-of-x (floor (/ floored-quantity x))))
(when (and (eq the-offer-type 'three-for-two)
(> floored-quantity 2))
(> floored-quantity +two-for-amount-quantity+))
(let ((discount-amount (- (* a-quantity a-unit-price)
(+ (* number-of-x 2 a-unit-price)
(* (mod floored-quantity 3) a-unit-price)))))
(+ (* number-of-x +two-for-amount-quantity+ a-unit-price)
(* (mod floored-quantity +three-for-two-quantity+) a-unit-price)))))
(setf a-discount (make-instance 'discount
:product a-product
:description "3 for 2"
:description +three-for-two-description+
:amount (- discount-amount)))))
(when (eq the-offer-type 'ten-percent-discount)
(setf a-discount (make-instance 'discount
:product a-product
:description (format nil "~S % off" (offer-argument offer-for-product))
:amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) 100.0))))
:amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) +percentage-divisor+))))
(when (and (eq the-offer-type 'five-for-amount)
(>= floored-quantity 5))
(>= floored-quantity +five-for-amount-quantity+))
(let ((discount-total (- (* a-quantity a-unit-price)
(+ (* (offer-argument offer-for-product) number-of-x)
(* (mod floored-quantity 5) a-unit-price)))))
(* (mod floored-quantity +five-for-amount-quantity+) a-unit-price)))))
(setf a-discount (make-instance 'discount
:product a-product
:description (format nil "~S for ~S" x (offer-argument offer-for-product))
Expand Down
43 changes: 29 additions & 14 deletions cpp/src/ShoppingCart.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
#include "ShoppingCart.h"

// Constants for magic numbers
namespace {
constexpr double DEFAULT_ITEM_QUANTITY = 1.0;
constexpr int TWO_FOR_AMOUNT_QUANTITY = 2;
constexpr int THREE_FOR_TWO_QUANTITY = 3;
constexpr int FIVE_FOR_AMOUNT_QUANTITY = 5;
constexpr double PERCENTAGE_DIVISOR = 100.0;

// Constants for discount description strings
const std::string THREE_FOR_TWO_DESCRIPTION = "3 for 2";
const std::string TWO_FOR_PREFIX = "2 for ";
const std::string FOR_SEPARATOR = " for ";
const std::string PERCENT_OFF_SUFFIX = "% off";
}

void addItemQuantity(const Product& product, double quantity);

std::vector<ProductQuantity> ShoppingCart::getItems() const {
Expand All @@ -11,7 +26,7 @@ std::map<Product, double> ShoppingCart::getProductQuantities() const {
}

void ShoppingCart::addItem(const Product& product) {
addItemQuantity(product, 1.0);
addItemQuantity(product, DEFAULT_ITEM_QUANTITY);
}

void ShoppingCart::addItemQuantity(const Product& product, double quantity) {
Expand All @@ -35,28 +50,28 @@ void ShoppingCart::handleOffers(Receipt& receipt, std::map<Product, Offer> offer
int x = 1;

if (offer.getOfferType() == SpecialOfferType::ThreeForTwo) {
x = 3;
x = THREE_FOR_TWO_QUANTITY;
} else if (offer.getOfferType() == SpecialOfferType::TwoForAmount) {
x = 2;
if (quantityAsInt >= 2) {
double total = offer.getArgument() * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice;
x = TWO_FOR_AMOUNT_QUANTITY;
if (quantityAsInt >= TWO_FOR_AMOUNT_QUANTITY) {
double total = offer.getArgument() * (quantityAsInt / x) + quantityAsInt % TWO_FOR_AMOUNT_QUANTITY * unitPrice;
double discountN = unitPrice * quantity - total;
discount = new Discount("2 for " + std::to_string(offer.getArgument()), -discountN, product);
discount = new Discount(TWO_FOR_PREFIX + std::to_string(offer.getArgument()), -discountN, product);
}
} if (offer.getOfferType() == SpecialOfferType::FiveForAmount) {
x = 5;
x = FIVE_FOR_AMOUNT_QUANTITY;
}
int numberOfXs = quantityAsInt / x;
if (offer.getOfferType() == SpecialOfferType::ThreeForTwo && quantityAsInt > 2) {
double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice);
discount = new Discount("3 for 2", -discountAmount, product);
if (offer.getOfferType() == SpecialOfferType::ThreeForTwo && quantityAsInt > TWO_FOR_AMOUNT_QUANTITY) {
double discountAmount = quantity * unitPrice - ((numberOfXs * TWO_FOR_AMOUNT_QUANTITY * unitPrice) + quantityAsInt % THREE_FOR_TWO_QUANTITY * unitPrice);
discount = new Discount(THREE_FOR_TWO_DESCRIPTION, -discountAmount, product);
}
if (offer.getOfferType() == SpecialOfferType::TenPercentDiscount) {
discount = new Discount(std::to_string(offer.getArgument()) + "% off", -quantity * unitPrice * offer.getArgument() / 100.0, product);
discount = new Discount(std::to_string(offer.getArgument()) + PERCENT_OFF_SUFFIX, -quantity * unitPrice * offer.getArgument() / PERCENTAGE_DIVISOR, product);
}
if (offer.getOfferType() == SpecialOfferType::FiveForAmount && quantityAsInt >= 5) {
double discountTotal = unitPrice * quantity - (offer.getArgument() * numberOfXs + quantityAsInt % 5 * unitPrice);
discount = new Discount(std::to_string(x) + " for " + std::to_string(offer.getArgument()), -discountTotal, product);
if (offer.getOfferType() == SpecialOfferType::FiveForAmount && quantityAsInt >= FIVE_FOR_AMOUNT_QUANTITY) {
double discountTotal = unitPrice * quantity - (offer.getArgument() * numberOfXs + quantityAsInt % FIVE_FOR_AMOUNT_QUANTITY * unitPrice);
discount = new Discount(std::to_string(x) + FOR_SEPARATOR + std::to_string(offer.getArgument()), -discountTotal, product);
}
if (discount != nullptr)
receipt.addDiscount(*discount);
Expand Down
41 changes: 27 additions & 14 deletions csharp-ms/SupermarketReceipt/ShoppingCart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ namespace SupermarketReceipt
{
public class ShoppingCart
{
// Constants for magic numbers
private const double DefaultItemQuantity = 1.0;
private const int TwoForAmountQuantity = 2;
private const int ThreeForTwoQuantity = 3;
private const int FiveForAmountQuantity = 5;
private const double PercentageDivisor = 100.0;

// Constants for discount description strings
private const string ThreeForTwoDescription = "3 for 2";
private const string TwoForPrefix = "2 for ";
private const string ForSeparator = " for ";
private const string PercentOffSuffix = "% off";

private readonly List<ProductQuantity> _items = new List<ProductQuantity>();
private readonly Dictionary<Product, double> _productQuantities = new Dictionary<Product, double>();

Expand All @@ -15,7 +28,7 @@ public List<ProductQuantity> GetItems()

public void AddItem(Product product)
{
AddItemQuantity(product, 1.0);
AddItemQuantity(product, DefaultItemQuantity);
}


Expand Down Expand Up @@ -47,32 +60,32 @@ public void HandleOffers(Receipt receipt, Dictionary<Product, Offer> offers, Sup
var x = 1;
if (offer.OfferType == SpecialOfferType.ThreeForTwo)
{
x = 3;
x = ThreeForTwoQuantity;
}
else if (offer.OfferType == SpecialOfferType.TwoForAmount)
{
x = 2;
if (quantityAsInt >= 2)
x = TwoForAmountQuantity;
if (quantityAsInt >= TwoForAmountQuantity)
{
var total = offer.Argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice;
var total = offer.Argument * (quantityAsInt / x) + quantityAsInt % TwoForAmountQuantity * unitPrice;
var discountN = unitPrice * quantity - total;
discount = new Discount(p, "2 for " + offer.Argument, -discountN);
discount = new Discount(p, TwoForPrefix + offer.Argument, -discountN);
}
}

if (offer.OfferType == SpecialOfferType.FiveForAmount) x = 5;
if (offer.OfferType == SpecialOfferType.FiveForAmount) x = FiveForAmountQuantity;
var numberOfXs = quantityAsInt / x;
if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2)
if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > TwoForAmountQuantity)
{
var discountAmount = quantity * unitPrice - (numberOfXs * 2 * unitPrice + quantityAsInt % 3 * unitPrice);
discount = new Discount(p, "3 for 2", -discountAmount);
var discountAmount = quantity * unitPrice - (numberOfXs * TwoForAmountQuantity * unitPrice + quantityAsInt % ThreeForTwoQuantity * unitPrice);
discount = new Discount(p, ThreeForTwoDescription, -discountAmount);
}

if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + "% off", -quantity * unitPrice * offer.Argument / 100.0);
if (offer.OfferType == SpecialOfferType.FiveForAmount && quantityAsInt >= 5)
if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + PercentOffSuffix, -quantity * unitPrice * offer.Argument / PercentageDivisor);
if (offer.OfferType == SpecialOfferType.FiveForAmount && quantityAsInt >= FiveForAmountQuantity)
{
var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % 5 * unitPrice);
discount = new Discount(p, x + " for " + offer.Argument, -discountTotal);
var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % FiveForAmountQuantity * unitPrice);
discount = new Discount(p, x + ForSeparator + offer.Argument, -discountTotal);
}

if (discount != null)
Expand Down
Loading