diff --git a/c/.gitignore b/c/.gitignore index 401f294..afb6d3a 100644 --- a/c/.gitignore +++ b/c/.gitignore @@ -2,3 +2,17 @@ /subprojects/Catch2-*/ /subprojects/packagecache/ /cmake-build-*/ + +# CMake build artifacts +CMakeCache.txt +CMakeFiles/ +_deps/ +Makefile +cmake_install.cmake +CTestTestfile.cmake + +# Binary files +sample_test_catch2 +sample_test_gtest +*.a +*.o diff --git a/c/src/supermarket.c b/c/src/supermarket.c index 414ce1d..802449e 100644 --- a/c/src/supermarket.c +++ b/c/src/supermarket.c @@ -71,43 +71,23 @@ void handle_offers(struct cart_t* cart, struct receipt_t* receipt, struct specia double quantity = cart->quantities[i]; if (strcmp(offer->product->name, product.name) == 0) { double unitPrice = unit_price(catalog, &product); - int quantityAsInt = (int)quantity; struct discount_t* discount = NULL; - int x = 1; - - if (offer->type == ThreeForTwo) { - x = 3; - } else if (offer->type == TwoForAmount) { - x = 2; - if (quantityAsInt >= 2) { - double total = offer->argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice; - double discountN = unitPrice * quantity - total; - char description[MAX_NAME_LENGTH]; - sprintf(description, "2 for %f", offer->argument); - discount = discount_create(description, -discountN, &product); - } - } if (offer->type == FiveForAmount) { - x = 5; - } - int numberOfXs = quantityAsInt / x; - if (offer->type == ThreeForTwo && quantityAsInt > 2) { - double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); - char description[MAX_NAME_LENGTH]; - sprintf(description, "3 for 2"); - 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); + switch (offer->type) { + case ThreeForTwo: + discount = calculate_three_for_two_discount(&product, quantity, unitPrice); + break; + case TwoForAmount: + discount = calculate_two_for_amount_discount(&product, quantity, unitPrice, offer->argument); + break; + case TenPercentDiscount: + discount = calculate_ten_percent_discount(&product, quantity, unitPrice, offer->argument); + break; + case FiveForAmount: + discount = calculate_five_for_amount_discount(&product, quantity, unitPrice, offer->argument); + break; } - if (offer->type == FiveForAmount && quantityAsInt >= 5) { - double discountTotal = unitPrice * quantity - (offer->argument * numberOfXs + quantityAsInt % 5 * unitPrice); - char description[MAX_NAME_LENGTH]; - sprintf(description, "%d for %f", x, offer->argument); - discount = discount_create(description, -discountTotal, &product); - } + if (discount != NULL) { receipt->discounts[receipt->discountCount] = *discount; receipt->discountCount++; @@ -149,3 +129,48 @@ double unit_price(struct catalog_t* catalog, struct product_t *product) { } return 0; } + +struct discount_t* calculate_three_for_two_discount(struct product_t* product, double quantity, double unitPrice) { + int quantityAsInt = (int)quantity; + if (quantityAsInt <= 2) { + return NULL; + } + + int numberOfThrees = quantityAsInt / 3; + double discountAmount = quantity * unitPrice - ((numberOfThrees * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); + char description[MAX_NAME_LENGTH]; + sprintf(description, "3 for 2"); + return discount_create(description, -discountAmount, product); +} + +struct discount_t* calculate_two_for_amount_discount(struct product_t* product, double quantity, double unitPrice, double amount) { + int quantityAsInt = (int)quantity; + if (quantityAsInt < 2) { + return NULL; + } + + double total = amount * (quantityAsInt / 2) + quantityAsInt % 2 * unitPrice; + double discountN = unitPrice * quantity - total; + char description[MAX_NAME_LENGTH]; + sprintf(description, "2 for %f", amount); + return discount_create(description, -discountN, product); +} + +struct discount_t* calculate_ten_percent_discount(struct product_t* product, double quantity, double unitPrice, double percentage) { + char description[MAX_NAME_LENGTH]; + sprintf(description, "%.0f%% off", percentage); + return discount_create(description, -quantity * unitPrice * percentage / 100.0, product); +} + +struct discount_t* calculate_five_for_amount_discount(struct product_t* product, double quantity, double unitPrice, double amount) { + int quantityAsInt = (int)quantity; + if (quantityAsInt < 5) { + return NULL; + } + + int numberOfFives = quantityAsInt / 5; + double discountTotal = unitPrice * quantity - (amount * numberOfFives + quantityAsInt % 5 * unitPrice); + char description[MAX_NAME_LENGTH]; + sprintf(description, "5 for %f", amount); + return discount_create(description, -discountTotal, product); +} diff --git a/c/src/supermarket.h b/c/src/supermarket.h index 20085a9..e21dad9 100644 --- a/c/src/supermarket.h +++ b/c/src/supermarket.h @@ -75,6 +75,13 @@ struct discount_t* discount_create(char* description, double discount, struct pr struct receipt_t* check_out_articles(struct teller_t* teller, struct cart_t* cart); double total_price(struct receipt_t* receipt); double unit_price(struct catalog_t* catalog, struct product_t *product); + +// Discount calculation functions +struct discount_t* calculate_three_for_two_discount(struct product_t* product, double quantity, double unitPrice); +struct discount_t* calculate_two_for_amount_discount(struct product_t* product, double quantity, double unitPrice, double amount); +struct discount_t* calculate_ten_percent_discount(struct product_t* product, double quantity, double unitPrice, double percentage); +struct discount_t* calculate_five_for_amount_discount(struct product_t* product, double quantity, double unitPrice, double amount); + void handle_offers(struct cart_t* cart, struct receipt_t* receipt, struct special_offer_t* offer, struct catalog_t* catalog); #endif //SAMPLE_H diff --git a/csharp-ms/SupermarketReceipt/ShoppingCart.cs b/csharp-ms/SupermarketReceipt/ShoppingCart.cs index 28abbe7..441ae41 100644 --- a/csharp-ms/SupermarketReceipt/ShoppingCart.cs +++ b/csharp-ms/SupermarketReceipt/ShoppingCart.cs @@ -38,41 +38,26 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup foreach (var p in _productQuantities.Keys) { var quantity = _productQuantities[p]; - var quantityAsInt = (int) quantity; if (offers.ContainsKey(p)) { var offer = offers[p]; var unitPrice = catalog.GetUnitPrice(p); Discount discount = null; - var x = 1; - if (offer.OfferType == SpecialOfferType.ThreeForTwo) - { - x = 3; - } - else if (offer.OfferType == SpecialOfferType.TwoForAmount) - { - x = 2; - if (quantityAsInt >= 2) - { - var total = offer.Argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice; - var discountN = unitPrice * quantity - total; - discount = new Discount(p, "2 for " + offer.Argument, -discountN); - } - } - - if (offer.OfferType == SpecialOfferType.FiveForAmount) x = 5; - var numberOfXs = quantityAsInt / x; - if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2) - { - var discountAmount = quantity * unitPrice - (numberOfXs * 2 * unitPrice + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -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) + switch (offer.OfferType) { - var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % 5 * unitPrice); - discount = new Discount(p, x + " for " + offer.Argument, -discountTotal); + case SpecialOfferType.ThreeForTwo: + discount = CalculateThreeForTwoDiscount(p, quantity, unitPrice); + break; + case SpecialOfferType.TwoForAmount: + discount = CalculateTwoForAmountDiscount(p, quantity, unitPrice, offer.Argument); + break; + case SpecialOfferType.TenPercentDiscount: + discount = CalculateTenPercentDiscount(p, quantity, unitPrice, offer.Argument); + break; + case SpecialOfferType.FiveForAmount: + discount = CalculateFiveForAmountDiscount(p, quantity, unitPrice, offer.Argument); + break; } if (discount != null) @@ -80,5 +65,49 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup } } } + + private Discount CalculateThreeForTwoDiscount(Product product, double quantity, double unitPrice) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt <= 2) + { + return null; + } + + var numberOfThrees = quantityAsInt / 3; + var discountAmount = quantity * unitPrice - (numberOfThrees * 2 * unitPrice + quantityAsInt % 3 * unitPrice); + return new Discount(product, "3 for 2", -discountAmount); + } + + private Discount CalculateTwoForAmountDiscount(Product product, double quantity, double unitPrice, double amount) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt < 2) + { + return null; + } + + var total = amount * (quantityAsInt / 2) + quantityAsInt % 2 * unitPrice; + var discountN = unitPrice * quantity - total; + return new Discount(product, "2 for " + amount, -discountN); + } + + private Discount CalculateTenPercentDiscount(Product product, double quantity, double unitPrice, double percentage) + { + return new Discount(product, percentage + "% off", -quantity * unitPrice * percentage / 100.0); + } + + private Discount CalculateFiveForAmountDiscount(Product product, double quantity, double unitPrice, double amount) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt < 5) + { + return null; + } + + var numberOfFives = quantityAsInt / 5; + var discountTotal = unitPrice * quantity - (amount * numberOfFives + quantityAsInt % 5 * unitPrice); + return new Discount(product, "5 for " + amount, -discountTotal); + } } } \ No newline at end of file diff --git a/csharp/SupermarketReceipt/ShoppingCart.cs b/csharp/SupermarketReceipt/ShoppingCart.cs index 72b6b4a..9d512da 100644 --- a/csharp/SupermarketReceipt/ShoppingCart.cs +++ b/csharp/SupermarketReceipt/ShoppingCart.cs @@ -40,41 +40,26 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup foreach (var p in _productQuantities.Keys) { var quantity = _productQuantities[p]; - var quantityAsInt = (int) quantity; if (offers.ContainsKey(p)) { var offer = offers[p]; var unitPrice = catalog.GetUnitPrice(p); Discount discount = null; - var x = 1; - if (offer.OfferType == SpecialOfferType.ThreeForTwo) - { - x = 3; - } - else if (offer.OfferType == SpecialOfferType.TwoForAmount) - { - x = 2; - if (quantityAsInt >= 2) - { - var total = offer.Argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice; - var discountN = unitPrice * quantity - total; - discount = new Discount(p, "2 for " + PrintPrice(offer.Argument), -discountN); - } - } - - if (offer.OfferType == SpecialOfferType.FiveForAmount) x = 5; - var numberOfXs = quantityAsInt / x; - if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2) - { - var discountAmount = quantity * unitPrice - (numberOfXs * 2 * unitPrice + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -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) + switch (offer.OfferType) { - var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % 5 * unitPrice); - discount = new Discount(p, x + " for " + PrintPrice(offer.Argument), -discountTotal); + case SpecialOfferType.ThreeForTwo: + discount = CalculateThreeForTwoDiscount(p, quantity, unitPrice); + break; + case SpecialOfferType.TwoForAmount: + discount = CalculateTwoForAmountDiscount(p, quantity, unitPrice, offer.Argument); + break; + case SpecialOfferType.TenPercentDiscount: + discount = CalculateTenPercentDiscount(p, quantity, unitPrice, offer.Argument); + break; + case SpecialOfferType.FiveForAmount: + discount = CalculateFiveForAmountDiscount(p, quantity, unitPrice, offer.Argument); + break; } if (discount != null) @@ -82,6 +67,50 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup } } } + + private Discount CalculateThreeForTwoDiscount(Product product, double quantity, double unitPrice) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt <= 2) + { + return null; + } + + var numberOfThrees = quantityAsInt / 3; + var discountAmount = quantity * unitPrice - (numberOfThrees * 2 * unitPrice + quantityAsInt % 3 * unitPrice); + return new Discount(product, "3 for 2", -discountAmount); + } + + private Discount CalculateTwoForAmountDiscount(Product product, double quantity, double unitPrice, double amount) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt < 2) + { + return null; + } + + var total = amount * (quantityAsInt / 2) + quantityAsInt % 2 * unitPrice; + var discountN = unitPrice * quantity - total; + return new Discount(product, "2 for " + PrintPrice(amount), -discountN); + } + + private Discount CalculateTenPercentDiscount(Product product, double quantity, double unitPrice, double percentage) + { + return new Discount(product, percentage + "% off", -quantity * unitPrice * percentage / 100.0); + } + + private Discount CalculateFiveForAmountDiscount(Product product, double quantity, double unitPrice, double amount) + { + var quantityAsInt = (int) quantity; + if (quantityAsInt < 5) + { + return null; + } + + var numberOfFives = quantityAsInt / 5; + var discountTotal = unitPrice * quantity - (amount * numberOfFives + quantityAsInt % 5 * unitPrice); + return new Discount(product, "5 for " + PrintPrice(amount), -discountTotal); + } private string PrintPrice(double price) { diff --git a/java/pom.xml b/java/pom.xml index 73ba4a7..c62567d 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -45,8 +45,8 @@ maven-compiler-plugin 3.8.0 - 22 - 22 + 17 + 17 diff --git a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java index 9293086..e1977da 100644 --- a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java +++ b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java @@ -38,38 +38,63 @@ void handleOffers(Receipt receipt, Map offers, SupermarketCatalo if (offers.containsKey(p)) { Offer offer = offers.get(p); double unitPrice = catalog.getUnitPrice(p); - int quantityAsInt = (int) quantity; Discount discount = null; - int x = 1; - if (offer.offerType == SpecialOfferType.THREE_FOR_TWO) { - x = 3; - } else if (offer.offerType == SpecialOfferType.TWO_FOR_AMOUNT) { - x = 2; - if (quantityAsInt >= 2) { - double total = offer.argument * (quantityAsInt / x) + quantityAsInt % 2 * unitPrice; - double discountN = unitPrice * quantity - total; - discount = new Discount(p, "2 for " + offer.argument, -discountN); - } - - } if (offer.offerType == SpecialOfferType.FIVE_FOR_AMOUNT) { - x = 5; - } - int numberOfXs = quantityAsInt / x; - if (offer.offerType == SpecialOfferType.THREE_FOR_TWO && quantityAsInt > 2) { - double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -discountAmount); - } - if (offer.offerType == SpecialOfferType.TEN_PERCENT_DISCOUNT) { - discount = new Discount(p, offer.argument + "% off", -quantity * unitPrice * offer.argument / 100.0); - } - if (offer.offerType == SpecialOfferType.FIVE_FOR_AMOUNT && quantityAsInt >= 5) { - double discountTotal = unitPrice * quantity - (offer.argument * numberOfXs + quantityAsInt % 5 * unitPrice); - discount = new Discount(p, x + " for " + offer.argument, -discountTotal); + switch (offer.offerType) { + case THREE_FOR_TWO: + discount = calculateThreeForTwoDiscount(p, quantity, unitPrice); + break; + case TWO_FOR_AMOUNT: + discount = calculateTwoForAmountDiscount(p, quantity, unitPrice, offer.argument); + break; + case TEN_PERCENT_DISCOUNT: + discount = calculateTenPercentDiscount(p, quantity, unitPrice, offer.argument); + break; + case FIVE_FOR_AMOUNT: + discount = calculateFiveForAmountDiscount(p, quantity, unitPrice, offer.argument); + break; } + if (discount != null) receipt.addDiscount(discount); } } } + + private Discount calculateThreeForTwoDiscount(Product product, double quantity, double unitPrice) { + int quantityAsInt = (int) quantity; + if (quantityAsInt <= 2) { + return null; + } + + int numberOfThrees = quantityAsInt / 3; + double discountAmount = quantity * unitPrice - (numberOfThrees * 2 * unitPrice + quantityAsInt % 3 * unitPrice); + return new Discount(product, "3 for 2", -discountAmount); + } + + private Discount calculateTwoForAmountDiscount(Product product, double quantity, double unitPrice, double amount) { + int quantityAsInt = (int) quantity; + if (quantityAsInt < 2) { + return null; + } + + double total = amount * (quantityAsInt / 2) + quantityAsInt % 2 * unitPrice; + double discountN = unitPrice * quantity - total; + return new Discount(product, "2 for " + amount, -discountN); + } + + private Discount calculateTenPercentDiscount(Product product, double quantity, double unitPrice, double percentage) { + return new Discount(product, percentage + "% off", -quantity * unitPrice * percentage / 100.0); + } + + private Discount calculateFiveForAmountDiscount(Product product, double quantity, double unitPrice, double amount) { + int quantityAsInt = (int) quantity; + if (quantityAsInt < 5) { + return null; + } + + int numberOfFives = quantityAsInt / 5; + double discountTotal = unitPrice * quantity - (amount * numberOfFives + quantityAsInt % 5 * unitPrice); + return new Discount(product, "5 for " + amount, -discountTotal); + } } diff --git a/php/src/Model/ShoppingCart.php b/php/src/Model/ShoppingCart.php index d2f6c78..60efc81 100644 --- a/php/src/Model/ShoppingCart.php +++ b/php/src/Model/ShoppingCart.php @@ -57,43 +57,20 @@ public function handleOffers(Receipt $receipt, Map $offers, SupermarketCatalog $ * @var float $quantity */ foreach ($this->productQuantities as $p => $quantity) { - $quantityAsInt = (int) $quantity; if ($offers->hasKey($p)) { /** @var Offer $offer */ $offer = $offers[$p]; $unitPrice = $catalog->getUnitPrice($p); $discount = null; - $x = 1; + if ($offer->getOfferType()->equals(SpecialOfferType::THREE_FOR_TWO())) { - $x = 3; + $discount = $this->calculateThreeForTwoDiscount($p, $quantity, $unitPrice); } elseif ($offer->getOfferType()->equals(SpecialOfferType::TWO_FOR_AMOUNT())) { - $x = 2; - if ($quantityAsInt >= 2) { - $total = $offer->getArgument() * intdiv($quantityAsInt, $x) + $quantityAsInt % 2 * $unitPrice; - $discountN = $unitPrice * $quantity - $total; - $discount = new Discount($p, "2 for {$offer->getArgument()}", -1 * $discountN); - } - } - - if ($offer->getOfferType()->equals(SpecialOfferType::FIVE_FOR_AMOUNT())) { - $x = 5; - } - $numberOfXs = intdiv($quantityAsInt, $x); - if ($offer->getOfferType()->equals(SpecialOfferType::THREE_FOR_TWO()) && $quantityAsInt > 2) { - $discountAmount = $quantity * $unitPrice - ($numberOfXs * 2 * $unitPrice + $quantityAsInt % 3 * $unitPrice); - $discount = new Discount($p, '3 for 2', -$discountAmount); - } - - if ($offer->getOfferType()->equals(SpecialOfferType::TEN_PERCENT_DISCOUNT())) { - $discount = new Discount( - $p, - "{$offer->getArgument()}% off", - -$quantity * $unitPrice * $offer->getArgument() / 100.0 - ); - } - if ($offer->getOfferType()->equals(SpecialOfferType::FIVE_FOR_AMOUNT()) && $quantityAsInt >= 5) { - $discountTotal = $unitPrice * $quantity - ($offer->getArgument() * $numberOfXs + $quantityAsInt % 5 * $unitPrice); - $discount = new Discount($p, "${x} for {$offer->getArgument()}", -$discountTotal); + $discount = $this->calculateTwoForAmountDiscount($p, $quantity, $unitPrice, $offer->getArgument()); + } elseif ($offer->getOfferType()->equals(SpecialOfferType::TEN_PERCENT_DISCOUNT())) { + $discount = $this->calculateTenPercentDiscount($p, $quantity, $unitPrice, $offer->getArgument()); + } elseif ($offer->getOfferType()->equals(SpecialOfferType::FIVE_FOR_AMOUNT())) { + $discount = $this->calculateFiveForAmountDiscount($p, $quantity, $unitPrice, $offer->getArgument()); } if ($discount !== null) { @@ -102,4 +79,49 @@ public function handleOffers(Receipt $receipt, Map $offers, SupermarketCatalog $ } } } + + private function calculateThreeForTwoDiscount(Product $product, float $quantity, float $unitPrice): ?Discount + { + $quantityAsInt = (int) $quantity; + if ($quantityAsInt <= 2) { + return null; + } + + $numberOfThrees = intdiv($quantityAsInt, 3); + $discountAmount = $quantity * $unitPrice - ($numberOfThrees * 2 * $unitPrice + $quantityAsInt % 3 * $unitPrice); + return new Discount($product, '3 for 2', -$discountAmount); + } + + private function calculateTwoForAmountDiscount(Product $product, float $quantity, float $unitPrice, float $amount): ?Discount + { + $quantityAsInt = (int) $quantity; + if ($quantityAsInt < 2) { + return null; + } + + $total = $amount * intdiv($quantityAsInt, 2) + $quantityAsInt % 2 * $unitPrice; + $discountN = $unitPrice * $quantity - $total; + return new Discount($product, "2 for {$amount}", -$discountN); + } + + private function calculateTenPercentDiscount(Product $product, float $quantity, float $unitPrice, float $percentage): Discount + { + return new Discount( + $product, + "{$percentage}% off", + -$quantity * $unitPrice * $percentage / 100.0 + ); + } + + private function calculateFiveForAmountDiscount(Product $product, float $quantity, float $unitPrice, float $amount): ?Discount + { + $quantityAsInt = (int) $quantity; + if ($quantityAsInt < 5) { + return null; + } + + $numberOfFives = intdiv($quantityAsInt, 5); + $discountTotal = $unitPrice * $quantity - ($amount * $numberOfFives + $quantityAsInt % 5 * $unitPrice); + return new Discount($product, "5 for {$amount}", -$discountTotal); + } }