Pada laporan ini saya telah berhasil mengimplementasikan aplikasi Vending Coffee Machine sederhana. Jujur sebenarnya sudah terkena spoiler dari ETS tahun lalu.
Fitur:
Memilih jenis kopi, yaitu ESPRESSO, AMERICANO, LATTE, atau CAPPUCCINO
Memilih ukuran gelas, yaitu S / M / L
Additional gula per sendok dan extra milk shot
Menghitung kembalian
Checker stock
Pembuatan kopi, pengurangan stok, log transaksi, dan peringatan refill jika stok di bawah ambang
public class CoffeeMachine
{
private final Stock stock;
private final Logger log = new Logger();
private final int sugarPrice = 500;
private final int milkShotPrice = 3000;
public CoffeeMachine(Stock stock)
{
this.stock = stock;
}
public int priceOf(Order order)
{
int base = (int)Math.round(order.type.basePrice() * order.size.multiplier());
int addons = order.sugarAdd * sugarPrice + order.extraMilk * milkShotPrice;
return base + addons;
}
public String payNBrew(Order order, int cash)
{
Recipe need = order.type.baseRecipe().scaled(order.size, order.extraMilk);
if (!stock.has(need, order.sugarAdd))
{
return "[Stock tidak cukup]";
}
int price = priceOf(order);
if (cash < price) return "Uang kurang. Perlu: " + price + ", bayar: " + cash;
stock.consume(need, order.sugarAdd);
int change = cash - price;
log.add(new Transaction(order, cash, price, change));
String status = stock.needsRefill() ? " REFILL ALERT" : "";
return "Membuat " + order.type + " size " + order.size + " Selesai! Kembalian: " + change + "." + status;
}
public Logger getLog()
{
return log;
}
public String getStock()
{
return stock.status();
}
public String orderNPay(String coffeeType, String cupSize, int sugar, int extraMilk, int cash)
{
Order o = new Order(CoffeeType.valueOf(coffeeType), CupSize.valueOf(cupSize), sugar, extraMilk);
return payNBrew(o, cash);
}
}
public enum CoffeeType
{
ESPRESSO(15000, new Recipe(8, 30, 0)),
AMERICANO(18000, new Recipe(8, 150, 0)),
LATTE(22000, new Recipe(8, 30, 120)),
CAPPUCCINO(22000, new Recipe(8, 30, 80));
private final int basePrice;
private final Recipe baseRecipe;
CoffeeType(int basePrice, Recipe baseRecipe)
{
this.basePrice = basePrice;
this.baseRecipe = baseRecipe;
}
public int basePrice()
{
return basePrice;
}
public Recipe baseRecipe()
{
return baseRecipe;
}
}
public class Recipe
{
private final int coffeeGr;
private final int waterMl;
private final int milkMl;
public Recipe(int coffeeGr, int waterMl, int milkMl)
{
this.coffeeGr = coffeeGr;
this.waterMl = waterMl;
this.milkMl = milkMl;
}
public int coffeeGr()
{
return coffeeGr;
}
public int waterMl()
{
return waterMl;
}
public int milkMl()
{
return milkMl;
}
public Recipe scaled(CupSize size, int extraMilk)
{
double m = size.multiplier();
int milk = (int)Math.round(milkMl * m) + extraMilk * 50;
return new Recipe((int)Math.round(coffeeGr * m), (int)Math.round(waterMl * m), milk);
}
}
public enum CupSize
{
S(1.0, 150),
M(1.3, 250),
L(1.6, 350);
private final double multiplier;
private final int volumeMl;
CupSize(double multiplier, int volumeMl)
{
this.multiplier = multiplier;
this.volumeMl = volumeMl;
}
public double multiplier()
{
return multiplier;
}
public int volumeMl()
{
return volumeMl;
}
}
import java.time.LocalDateTime;
public class Transaction
{
public final LocalDateTime time = LocalDateTime.now();
public final Order order;
public final int paid;
public final int price;
public final int change;
public Transaction(Order order, int paid, int price, int change)
{
this.order = order; this.paid = paid; this.price = price; this.change = change;
}
public String toString()
{
return String.format("%.10s %s %s sugar:%d milk:%d price:%d paid:%d change:%d", time, order.type, order.size, order.sugarAdd, order.extraMilk, price, paid, change);
}
}
public class Order
{
public final CoffeeType type;
public final CupSize size;
public final int sugarAdd;
public final int extraMilk;
public Order(CoffeeType type, CupSize size, int sugarAdd, int extraMilk)
{
this.type = type; this.size = size;
this.sugarAdd = sugarAdd; this.extraMilk = extraMilk;
}
}
public class Stock
{
private int coffeeGr, sugarGr, milkMl, waterMl;
private final int minCoffee, minSugar, minMilk, minWater;
public Stock(int coffeeGr, int sugarGr, int milkMl, int waterMl)
{
this(coffeeGr, sugarGr, milkMl, waterMl, 50, 50, 200, 500);
}
public Stock(int coffeeGr, int sugarGr, int milkMl, int waterMl, int minCoffee, int minSugar, int minMilk, int minWater)
{
this.coffeeGr = coffeeGr; this.sugarGr = sugarGr;
this.milkMl = milkMl; this.waterMl = waterMl;
this.minCoffee = minCoffee; this.minSugar = minSugar;
this.minMilk = minMilk; this.minWater = minWater;
}
public boolean has(Recipe r, int sugarAdd)
{
return coffeeGr >= r.coffeeGr() && waterMl >= r.waterMl() && milkMl >= r.milkMl() && sugarGr >= sugarAdd * 4;
}
public void consume(Recipe r, int sugarAdd)
{
coffeeGr -= r.coffeeGr();
waterMl -= r.waterMl();
milkMl -= r.milkMl();
sugarGr -= sugarAdd * 4;
}
public void refill(int coffee, int sugar, int milk, int water) {
coffeeGr += coffee; sugarGr += sugar; milkMl += milk; waterMl += water;
}
public boolean needsRefill()
{
return coffeeGr < minCoffee || sugarGr < minSugar || milkMl < minMilk || waterMl < minWater;
}
public String status()
{
return String.format("[Stock] coffee:%dg sugar:%dg milk:%dml water:%dml%s", coffeeGr, sugarGr, milkMl, waterMl, needsRefill() ? " (REFILL!)" : "");
}
}
import java.util.ArrayList;
import java.util.List;
public class Logger
{
private final List<Transaction> items = new ArrayList<>();
public void add(Transaction t)
{
items.add(t);
}
public List<Transaction> all()
{
return items;
}
public int totalRevenue()
{
int sum = 0;
for (Transaction t : items) sum += t.price;
return sum;
}
public void print()
{
for (Transaction t : items) System.out.println(t);
System.out.println("Total: " + totalRevenue());
}
}
import java.util.Scanner;
public class App
{
public static void main(String[] args)
{
Stock stock = new Stock(100, 100, 100, 100);
CoffeeMachine machine = new CoffeeMachine(stock);
Scanner sc = new Scanner(System.in);
System.out.println("=== Vending Coffee Machine ===");
while (true) {
System.out.println("\n[Menu] ESPRESSO, AMERICANO, LATTE, CAPPUCCINO");
System.out.print("Pilih: "); String t = sc.next().toUpperCase();
System.out.print("\n");
System.out.print("[Additional]");
System.out.print("\n");
System.out.print("Ukuran (S/M/L): "); String s = sc.next().toUpperCase();
System.out.print("Gula (sendok): "); int sugar = sc.nextInt();
System.out.print("Extra milk shots: "); int shots = sc.nextInt();
System.out.print("\n");
Order o = new Order(CoffeeType.valueOf(t), CupSize.valueOf(s), sugar, shots);
int price = machine.priceOf(o);
System.out.print("[Payment]");
System.out.print("\n");
System.out.println("Total harga: " + price);
System.out.print("Masukkan uang: "); int cash = sc.nextInt();
System.out.print("\n");
System.out.println(machine.payNBrew(o, cash));
System.out.println(machine.getStock());
System.out.print("\n");
System.out.print("Order lagi?: ");
if (!sc.next().equalsIgnoreCase("y")) break;
}
System.out.println("\n== Log Transaksi ==");
machine.getLog().print();
}
}