Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e2ddaaf
Started planning out program
Badde00 Aug 19, 2024
33a6cf4
Initial commit
Badde00 Aug 20, 2024
51e3e9d
RED: testAddBagel
Badde00 Aug 20, 2024
3e6bb36
GREEN: testAddBagel passed
Badde00 Aug 20, 2024
09c679a
REFACTOR: Redesigned Bagel and how the data is stored and added a ui …
Badde00 Aug 20, 2024
b261050
RED: testAddBagelToFullBasket
Badde00 Aug 20, 2024
8b7f9c2
GREEN: testAddBagelToFullBasket passes
Badde00 Aug 20, 2024
98b5ffd
REFACTOR: Added warning to not add more bagels into the controller an…
Badde00 Aug 20, 2024
8361604
typo
Badde00 Aug 20, 2024
641e5ba
RED: testRemoveBagel
Badde00 Aug 20, 2024
7aa15c2
GREEN: testRemoveBagel passes
Badde00 Aug 20, 2024
280c64f
RED: testGetBagelsIsClone
Badde00 Aug 20, 2024
3967409
GREEN: testGetBagelsIsClone passes
Badde00 Aug 20, 2024
5b86883
RED: testCalculateCost
Badde00 Aug 20, 2024
deeb7de
GREEN: testCalculateCost passes and made a toString()
Badde00 Aug 20, 2024
d6776e2
REFACTOR: Added ui to use new code in tests
Badde00 Aug 20, 2024
31591d2
RED: testRemoveNonexistentBagel
Badde00 Aug 20, 2024
92d4325
GREEN: testRemoveNonexistentBagel passes
Badde00 Aug 20, 2024
f64e572
REFACTOR: fixed unsafe cast
Badde00 Aug 20, 2024
4e3b610
RED: testChangeSize
Badde00 Aug 20, 2024
5f5a227
GREEN: testChangeSize passes
Badde00 Aug 20, 2024
6c281a0
RED: testChangeSizeToSmallerThanNumberOfBagels
Badde00 Aug 20, 2024
0b23a8d
GREEN: testChangeSizeToSmallerThanNumberOfBagels passes
Badde00 Aug 20, 2024
094f60f
REFACTOR: Added ui to be able to change basket size
Badde00 Aug 20, 2024
008e42f
typo
Badde00 Aug 21, 2024
7a1621b
RED: testCalculateCost
Badde00 Aug 21, 2024
28fcd7f
GREEN: testCalculateCost passes
Badde00 Aug 21, 2024
7837a7b
REFACTOR: testCalculateCostOnEmptyBasket to comply with domain model
Badde00 Aug 21, 2024
05e8763
REFACTOR: improved ui
Badde00 Aug 21, 2024
b83e943
REFACTOR: made bagel into product to more general in preparation of e…
Badde00 Aug 22, 2024
d81e301
RED: testAddSeveralFillings, testToString
Badde00 Aug 22, 2024
3442c21
GREEN: testAddSeveralFillings, testToString passes
Badde00 Aug 22, 2024
11eb178
REFACTOR: Can now add several fillings to bagel through ui
Badde00 Aug 22, 2024
0447e1c
RED: testFindDiscountOn12Bagels
Badde00 Aug 22, 2024
a1cec46
GREEN: testFindDiscountOn12Bagels passes
Badde00 Aug 22, 2024
77902ef
RED: Various testFindDiscount, with and without Coffee
Badde00 Aug 22, 2024
6c020e0
GREEN: Various testFindDiscounts now pass
Badde00 Aug 22, 2024
81a7af7
REFACTOR: displaying cost now accounts for discount and you can now o…
Badde00 Aug 22, 2024
9210134
REFACTOR: cleaning up code
Badde00 Aug 22, 2024
e2040ed
REFACTOR: intellij recommendations
Badde00 Aug 22, 2024
7d80a74
Merge pull request #1 from Badde00/extension1
Badde00 Aug 23, 2024
881c02f
RED: testReceiptInfo
Badde00 Aug 23, 2024
41a60aa
GREEN: testReceiptInfo + ui
Badde00 Aug 23, 2024
3f9ac70
Merge pull request #2 from Badde00/Extension2
Badde00 Aug 26, 2024
bcd082b
RED: testCalculateCostOn2BagelsAnd1Coffee crashes
Badde00 Aug 26, 2024
c9fa470
Merge remote-tracking branch 'origin/main'
Badde00 Aug 26, 2024
08cd4aa
GREEN: testCalculateCostOn2BagelsAnd1Coffee passes
Badde00 Aug 26, 2024
eb5373c
REFACTOR: ui
Badde00 Aug 26, 2024
ae3a7bd
REFACTOR: ui and test assistance on choice 12
Badde00 Aug 26, 2024
2da3b48
REFACTOR: ui bug
Badde00 Aug 26, 2024
82dad28
Diagram and @Override in Bagel
Badde00 Aug 26, 2024
d3718a5
removed the specific @toString because it was too much and removed th…
Badde00 Aug 26, 2024
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
47 changes: 47 additions & 0 deletions src/main/java/com/booleanuk/core/Bagel.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.booleanuk.core;

import java.util.ArrayList;

public class Bagel implements Product {
private final Triple<String, String, Float> bagelType;
private final ArrayList<Triple<String, String, Float>> fillings;

public Bagel(Triple<String, String, Float> bagelType, Triple<String, String, Float> fillingType) {
this.bagelType = bagelType;
this.fillings = new ArrayList<>();
this.fillings.add(fillingType);
}

public Bagel(Triple<String, String, Float> bagelType, ArrayList<Triple<String, String, Float>> fillings) {
this.bagelType = bagelType;
this.fillings = new ArrayList<>();
this.fillings.addAll(fillings);
}

@Override
public float calculateCost() {
return bagelType.c() + (float) fillings.stream().mapToDouble(Triple::c).sum();
}

public float calculateBreadCost() {
return bagelType.c();
}

public ArrayList<Triple<String, String, Float>> getFillings() {
return new ArrayList<>(fillings);
}

public Triple<String, String, Float> getBagelType() {
return bagelType;
}

@Override
public float basicPrice() {
return bagelType.c();
}

@Override
public String name() {
return bagelType.b() + " " + bagelType.a();
}
}
228 changes: 228 additions & 0 deletions src/main/java/com/booleanuk/core/Basket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package com.booleanuk.core;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.NoSuchElementException;

public class Basket {
private final ArrayList<Product> products;
private ArrayList<Product> unDiscountedProducts;
private int basketSize;

public Basket(int basketSize) {
products = new ArrayList<>();
unDiscountedProducts = new ArrayList<>();
this.basketSize = basketSize;
}

public int size() {
return products.size();
}

public void addProduct(Product product) {
if (products.size() < basketSize) {
products.add(product);
unDiscountedProducts.add(product);
}
}

public float findDiscount() {
ArrayList<Product> bagels = new ArrayList<>();
for (Product p: unDiscountedProducts) {
if (p instanceof Bagel) {
bagels.add(p);
}
}
// Sort and compare bread cost
bagels.sort((o1, o2) -> (int) (1000 * (((Bagel) o2).calculateBreadCost() - ((Bagel) o1).calculateBreadCost())));
if (bagels.size() >= 12) {
return calculateDiscount(bagels, 12, 3.99f) + findDiscount();
} else if (bagels.size() >= 6) {
return calculateDiscount(bagels, 6, 2.49f) + findDiscount();
} else if (bagels.size() < unDiscountedProducts.size()) {
// Sort so Bagels are first, coffee after. After sort by cost, but coffee is sorted inversely.
unDiscountedProducts.sort((o1, o2) -> switch (o1) {
case Bagel bagel when o2 instanceof Bagel ->
(int) (1000 * (((Bagel) o2).calculateBreadCost() - bagel.calculateBreadCost()));
case Coffee ignored when o2 instanceof Coffee ->
(int) (1000 * (o1.calculateCost() - o2.calculateCost()));
case Bagel ignored -> -1;
case null, default -> 1;
});


int coffeeSize = products.size() - bagels.size();
int coffeeBagelDeals = Math.min(bagels.size(), coffeeSize);
float sumCost = 0.0f;
for (int i = 0; i < coffeeBagelDeals; i++) {
sumCost += unDiscountedProducts.get(unDiscountedProducts.size() - 1 - i).calculateCost() + ((Bagel) bagels.get(i)).calculateBreadCost();
}
return sumCost - 1.25f * coffeeBagelDeals;
}
return 0;
}

private float calculateDiscount(ArrayList<Product> items, int num, float dis) {
float sumBreadCost = 0.0f;
for (int i = 0; i < num; i++) {
sumBreadCost += ((Bagel)items.get(i)).calculateBreadCost();
unDiscountedProducts.remove(items.get(i));
}
return sumBreadCost - dis;
}

public void removeProduct(Product product) {
if (!products.contains(product)) {
throw new NoSuchElementException("No such product exists");
}
products.remove(product);
}

public ArrayList<Product> getProducts() {
return new ArrayList<>(products);
}

public void setBasketSize(int basketSize) {
if (basketSize < products.size()) {
products.clear();
}
this.basketSize = basketSize;
}

public float calculateCost() {
float sum = 0.0f;
for (Product p: products) {
sum += p.calculateCost();
}
float discount = findDiscount();
sum -= discount;
unDiscountedProducts = new ArrayList<>(products);
return sum;
}

record ReceiptInfo(HashMap<String, Integer> fillings,
ArrayList<Triple<HashMap<String, Integer>, Float, Float>> deals, ArrayList<Product> remaining) {
}

public ReceiptInfo receiptInformation() {
HashMap<String, Integer> fillings = new HashMap<>(); // <filling, num> to display later
ArrayList<Triple<HashMap<String, Integer>, Float, Float>> deals = new ArrayList<>(); // T< HM<name, num> , price, discount>>
ArrayList<Product> remaining = new ArrayList<>();



unDiscountedProducts = new ArrayList<>(products);
ArrayList<Product> bagels = new ArrayList<>();
for (Product p: unDiscountedProducts) {
if (p instanceof Bagel) {
for (Triple<String, String, Float> t: ((Bagel) p).getFillings()) {
if (fillings.containsKey(t.b())) {
fillings.replace(t.b(), fillings.get(t.b()) + 1);
} else {
fillings.put(t.b(), 1);
}
}
bagels.add(p);
}
}

bagels.sort((o1, o2) -> (int) (1000 * (((Bagel) o2).calculateBreadCost() - ((Bagel) o1).calculateBreadCost())));

boolean keepRunning = true;
while (keepRunning) {
if (bagels.size() >= 12) {
HashMap<String, Integer> breadKinds = new HashMap<>();
float breadCost = 3.99f;
for (int i = 0; i < 12; i++) {
String bagelType = bagels.get(i).name();
if (breadKinds.containsKey(bagelType)) {
breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1);
} else {
breadKinds.put(bagelType, 1);
}
}
float discount = calculateDiscount(bagels, 12, 3.99f);
deals.add(new Triple<>(breadKinds, breadCost, -discount));
for (int i = 0; i < 12; i++) {
bagels.removeFirst();
}
} else if (bagels.size() >= 6) {
HashMap<String, Integer> breadKinds = new HashMap<>();
float breadCost = 2.49f;
for (int i = 0; i < 6; i++) {
String bagelType = bagels.get(i).name();
if (breadKinds.containsKey(bagelType)) {
breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1);
} else {
breadKinds.put(bagelType, 1);
}
}
float discount = calculateDiscount(bagels, 6, 2.49f);
deals.add(new Triple<>(breadKinds, breadCost, -discount));
for (int i = 0; i < 6; i++) {
bagels.removeFirst();
}
} else if (bagels.size() < unDiscountedProducts.size()) {
// Sort so Bagels are first, after that, sort by cost.
unDiscountedProducts.sort((o1, o2) -> switch (o1) {
case Bagel bagel when o2 instanceof Bagel ->
(int) (1000 * (((Bagel) o2).calculateBreadCost() - bagel.calculateBreadCost()));
case Coffee ignored when o2 instanceof Coffee ->
(int) (1000 * (o2.calculateCost() - o1.calculateCost()));
case Bagel ignored -> -1;
case null, default -> 1;
});


HashMap<String, Integer> breadKinds = new HashMap<>();
HashMap<String, Integer> coffeeType = new HashMap<>();
ArrayList<Product> coffeeList = new ArrayList<>();

for (Product p: unDiscountedProducts) {
if (p instanceof Coffee) {
coffeeList.add(p);
}
}

int coffeeBagelDeals = Math.min(bagels.size(), coffeeList.size());
for (int i = 0; i < coffeeBagelDeals; i++) {
String bagelType = bagels.get(i).name();
if (breadKinds.containsKey(bagelType)) {
breadKinds.replace(bagelType, breadKinds.get(bagelType) + 1);
} else {
breadKinds.put(bagelType, 1);
}

String coffeeString = coffeeList.get(i).name();
if (coffeeType.containsKey(coffeeString)) {
coffeeType.replace(coffeeString, coffeeType.get(coffeeString) + 1);
} else {
coffeeType.put(coffeeString, 1);
}
}

for (int i = 0; i < coffeeBagelDeals; i++) {
HashMap<String, Integer> dealContents = new HashMap<>();
dealContents.put(coffeeList.get(i).name(), 1);
dealContents.put(unDiscountedProducts.getFirst().name(), 1);
float coffeeCost = ((Coffee) coffeeList.get(i)).getCoffeeType().c();
float bagelCost = ((Bagel) unDiscountedProducts.getFirst()).getBagelType().c();
float dis = 1.25f - coffeeCost - bagelCost;
deals.add(new Triple<>(dealContents, 1.25f, dis));
unDiscountedProducts.removeFirst();
unDiscountedProducts.remove(coffeeList.get(i));
}
} else {
remaining.addAll(unDiscountedProducts);
keepRunning = false;
}
}

return new ReceiptInfo(fillings, deals, remaining);
}

public void clear() {
products.clear();
unDiscountedProducts.clear();
}
}
28 changes: 28 additions & 0 deletions src/main/java/com/booleanuk/core/Coffee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.booleanuk.core;

public class Coffee implements Product{
private final Triple<String, String, Float> coffeeType;

public Coffee(Triple<String, String, Float> coffeeType) {
this.coffeeType = coffeeType;
}

@Override
public float calculateCost() {
return coffeeType.c();
}

public Triple<String, String, Float> getCoffeeType() {
return coffeeType;
}

@Override
public String name() {
return coffeeType.b();
}

@Override
public float basicPrice() {
return coffeeType.c();
}
}
Loading