Removed Bugs from cs files & almost completed CoffeeVendingMachine.cs
This commit is contained in:
parent
bc7f2da775
commit
66cc7055fa
4 changed files with 273 additions and 41 deletions
|
|
@ -2,24 +2,45 @@
|
||||||
|
|
||||||
public class CoffeeVendingMachine
|
public class CoffeeVendingMachine
|
||||||
{
|
{
|
||||||
private static readonly CoinType[] withdrawalOrder;
|
private static readonly CoinType[] withdrawalOrder =
|
||||||
|
[
|
||||||
|
CoinType.Euro02,
|
||||||
|
CoinType.Euro01,
|
||||||
|
CoinType.Cent50,
|
||||||
|
CoinType.Cent20,
|
||||||
|
CoinType.Cent10,
|
||||||
|
CoinType.Cent05
|
||||||
|
];
|
||||||
private readonly CoinDepot[] _currentChangeCoins;
|
private readonly CoinDepot[] _currentChangeCoins;
|
||||||
private readonly CoinDepot[] _currentInputCoins;
|
private readonly CoinDepot[] _currentInputCoins;
|
||||||
private readonly Product[] _products;
|
private readonly Product[] _products;
|
||||||
|
|
||||||
public readonly string Location;
|
public string Location { get; }
|
||||||
public readonly int TotalChangeAmountInMachine;
|
public int TotalChangeAmountInMachine => SumDepotValue(_currentChangeCoins);
|
||||||
public readonly int TotalMoneyCurrentlyInput;
|
public int TotalMoneyCurrentlyInput => SumDepotValue(_currentInputCoins);
|
||||||
public readonly Product[] AvailableProducts;
|
public Product[] AvailableProducts => GetAvailableProducts();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new coffee vending machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="coinDepots"></param>
|
||||||
|
/// <param name="products"></param>
|
||||||
|
/// <param name="location"></param>
|
||||||
public CoffeeVendingMachine(CoinDepot[] coinDepots, Product[] products, string location)
|
public CoffeeVendingMachine(CoinDepot[] coinDepots, Product[] products, string location)
|
||||||
{
|
{
|
||||||
//TODO
|
Location = location;
|
||||||
|
_currentChangeCoins = coinDepots;
|
||||||
|
_products = products;
|
||||||
|
_currentInputCoins = CreateCoinDepots(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoffeeVendingMachine(string location)
|
/// <summary>
|
||||||
|
/// Creates a new coffee vending machine with default products.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location"></param>
|
||||||
|
public CoffeeVendingMachine(string location) : this(CreateCoinDepots(6, true), CreateDefaultProducts(), location)
|
||||||
{
|
{
|
||||||
//TODO
|
// no need to implement anything here
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoinDepot[] Cancel()
|
public CoinDepot[] Cancel()
|
||||||
|
|
@ -28,66 +49,274 @@ public class CoffeeVendingMachine
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts the given coin into the machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="coin"></param>
|
||||||
|
/// <returns>True if the coin was inserted, false otherwise.</returns>
|
||||||
public bool InsertCoin(CoinType coin)
|
public bool InsertCoin(CoinType coin)
|
||||||
{
|
{
|
||||||
//TODO
|
foreach (var inputDepot in _currentInputCoins)
|
||||||
|
{
|
||||||
|
if (inputDepot.Coin == coin)
|
||||||
|
{
|
||||||
|
inputDepot.Add();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SelectProduct(string productName, out CoinDepot[]? change, out int? price)
|
/// <summary>
|
||||||
|
/// Withdraws the change from the machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="productName"></param>
|
||||||
|
/// <param name="change"></param>
|
||||||
|
/// <param name="remainder"></param>
|
||||||
|
/// <returns>True if the change was withdrawn, false otherwise.</returns>
|
||||||
|
public bool SelectProduct(string productName, out CoinDepot[]? change, out int? remainder)
|
||||||
{
|
{
|
||||||
//TODO
|
if(!TryFindProduct(productName, out Product? product) || product == null || !product.InStock || TotalMoneyCurrentlyInput < product.Price)
|
||||||
change = null;
|
{
|
||||||
price = null;
|
change = null;
|
||||||
return false;
|
remainder = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int returnAmount = TotalMoneyCurrentlyInput - product.Price;
|
||||||
|
AddInputToChange();
|
||||||
|
product.AddSale();
|
||||||
|
int? remainingAmount = PrepareChangeCoins(returnAmount, out CoinDepot[] changeCoins);
|
||||||
|
|
||||||
|
change = changeCoins;
|
||||||
|
remainder = remainingAmount;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Withdraws the input coins from the machine.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The withdrawn coins.</returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
//TODO
|
string coinString = "";
|
||||||
return "";
|
string productString = "";
|
||||||
|
foreach (var coin in CoinType.GetValues(typeof(CoinType)))
|
||||||
|
{
|
||||||
|
CoinDepot? depot = GetDepotByType(_currentChangeCoins, (CoinType)coin);
|
||||||
|
if (depot != null)
|
||||||
|
{
|
||||||
|
coinString += $"|{depot.ToString()}".PadRight(40) + $"|{Environment.NewLine}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var product in _products)
|
||||||
|
{
|
||||||
|
productString += $"|{product.ToString()}".PadRight(40) + $"|{Environment.NewLine}";
|
||||||
|
}
|
||||||
|
return $"|=======================================|{Environment.NewLine}" +
|
||||||
|
$"|Machine located at: {Location}".PadRight(40) + $"|{Environment.NewLine}" +
|
||||||
|
$"|=======================================|{Environment.NewLine}" +
|
||||||
|
coinString +
|
||||||
|
$"|=======================================|{Environment.NewLine}" +
|
||||||
|
productString +
|
||||||
|
"|=======================================|";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the input coins to the change coins.
|
||||||
|
/// </summary>
|
||||||
private void AddInputToChange()
|
private void AddInputToChange()
|
||||||
{
|
{
|
||||||
//TODO
|
for (int i = 0; i < _currentInputCoins.Length; i++)
|
||||||
|
{
|
||||||
|
while (_currentInputCoins[i].Count > 0)
|
||||||
|
{
|
||||||
|
_currentChangeCoins[i].Add();
|
||||||
|
_currentInputCoins[i].Withdraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CoinDepot[] CreateCoinDepots(int count)
|
/// <summary>
|
||||||
|
/// Creates the coin depots.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <returns>The created coin depots.</returns>
|
||||||
|
private static CoinDepot[] CreateCoinDepots(int count, bool fill = false)
|
||||||
{
|
{
|
||||||
//TODO
|
CoinDepot[] coinDepots = new CoinDepot[count];
|
||||||
return [];
|
CoinType[] coinTypes = (CoinType[])Enum.GetValues(typeof(CoinType));
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
coinDepots[i] = new CoinDepot(coinTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fill)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < coinDepots.Length; i++)
|
||||||
|
{
|
||||||
|
while(coinDepots[i].Count < 3) // magic number
|
||||||
|
{
|
||||||
|
coinDepots[i].Add();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coinDepots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the default products.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The default products.</returns>
|
||||||
private static Product[] CreateDefaultProducts()
|
private static Product[] CreateDefaultProducts()
|
||||||
{
|
{
|
||||||
//TODO
|
Product[] products = new Product[3]; // magic number
|
||||||
return [];
|
products[0] = new Product("Cappuccino", 085, 10);
|
||||||
|
products[1] = new Product("Mocca", 100, 10);
|
||||||
|
products[2] = new Product("Cacao", 060, 10);
|
||||||
|
|
||||||
|
return products;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the depot by the given coin type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="coinDepots"></param>
|
||||||
|
/// <param name="coinType"></param>
|
||||||
|
/// <returns>The depot with the given coin type or null if not found.</returns>
|
||||||
private static CoinDepot? GetDepotByType(CoinDepot[] coinDepots, CoinType coinType)
|
private static CoinDepot? GetDepotByType(CoinDepot[] coinDepots, CoinType coinType)
|
||||||
{
|
{
|
||||||
//TODO
|
foreach (var coinDepot in coinDepots)
|
||||||
|
{
|
||||||
|
if (coinDepot.Coin == coinType)
|
||||||
|
{
|
||||||
|
return coinDepot;
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prepares the change coins for the given amount.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amount"></param>
|
||||||
|
/// <param name="changeCoins"></param>
|
||||||
|
/// <returns>The remaining amount that could not be changed.</returns>
|
||||||
private int? PrepareChangeCoins(int amount, out CoinDepot[] changeCoins)
|
private int? PrepareChangeCoins(int amount, out CoinDepot[] changeCoins)
|
||||||
{
|
{
|
||||||
//TODO
|
changeCoins = CreateCoinDepots(_currentChangeCoins.Length);
|
||||||
changeCoins = [];
|
|
||||||
return null;
|
foreach (var coinType in withdrawalOrder)
|
||||||
|
{
|
||||||
|
CoinDepot? depot = GetDepotByType(_currentChangeCoins, coinType);
|
||||||
|
if (depot == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (amount >= (int)coinType && depot.Count > 0)
|
||||||
|
{
|
||||||
|
amount -= (int)coinType;
|
||||||
|
depot.Withdraw();
|
||||||
|
CoinDepot? changeDepot = GetDepotByType(changeCoins, coinType);
|
||||||
|
changeDepot?.Add();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changeCoins = RemoveUnusedCoins(changeCoins);
|
||||||
|
return amount > 0 ? amount : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CoinDepot[] RemoveUnusedCoins(CoinDepot[] coins)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
foreach (var coin in coins)
|
||||||
|
{
|
||||||
|
if (coin.Count > 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinDepot[] usedCoins = new CoinDepot[count];
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < coins.Length; i++)
|
||||||
|
{
|
||||||
|
if (coins[i].Count > 0)
|
||||||
|
{
|
||||||
|
usedCoins[j] = coins[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return usedCoins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sums the value of all coins in the coin depots.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="coinDepots"></param>
|
||||||
|
/// <returns>The sum of all coins in the coin depots.</returns>
|
||||||
private static int SumDepotValue(CoinDepot[] coinDepots)
|
private static int SumDepotValue(CoinDepot[] coinDepots)
|
||||||
{
|
{
|
||||||
//TODO
|
int sum = 0;
|
||||||
return 0;
|
foreach (var coinDepot in coinDepots)
|
||||||
|
{
|
||||||
|
sum += coinDepot.Count * (int)coinDepot.Coin;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to find a product by its name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="productName"></param>
|
||||||
|
/// <param name="product"></param>
|
||||||
|
/// <returns>True if the product was found, false otherwise.</returns>
|
||||||
private bool TryFindProduct(string productName, out Product? product)
|
private bool TryFindProduct(string productName, out Product? product)
|
||||||
{
|
{
|
||||||
//TODO
|
foreach (var _product in _products)
|
||||||
|
{
|
||||||
|
if(_product.Name == productName)
|
||||||
|
{
|
||||||
|
product = _product;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
product = null;
|
product = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the available products.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The available products.</returns>
|
||||||
|
private Product[] GetAvailableProducts()
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
foreach (var product in _products)
|
||||||
|
{
|
||||||
|
if (product.InStock)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Product[] availableProducts = new Product[count];
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < _products.Length; i++)
|
||||||
|
{
|
||||||
|
if (_products[i].InStock)
|
||||||
|
{
|
||||||
|
availableProducts[j] = _products[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return availableProducts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class CoinDepot
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Coin}: {Count}";
|
return $"{Coin} x{Count}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Withdraw()
|
public bool Withdraw()
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ namespace CoffeeVendingMachines;
|
||||||
|
|
||||||
public enum CoinType
|
public enum CoinType
|
||||||
{
|
{
|
||||||
Cent05,
|
Cent05 = 005,
|
||||||
Cent10,
|
Cent10 = 010,
|
||||||
Cent20,
|
Cent20 = 020,
|
||||||
Cent50,
|
Cent50 = 050,
|
||||||
Euro01,
|
Euro01 = 100,
|
||||||
Euro02
|
Euro02 = 200
|
||||||
}
|
}
|
||||||
|
|
@ -5,17 +5,20 @@ public class Product
|
||||||
public const int FallbackPrice = 50;
|
public const int FallbackPrice = 50;
|
||||||
private readonly int _price;
|
private readonly int _price;
|
||||||
private int _stock;
|
private int _stock;
|
||||||
public readonly bool InStock;
|
public bool InStock => _stock > 0;
|
||||||
public readonly string Name;
|
public string Name { get; }
|
||||||
public int NumberSold { get; private set; }
|
public int NumberSold { get; private set; }
|
||||||
public int Price { get; private init; }
|
public int Price => _price;
|
||||||
|
|
||||||
public Product (string name, int price = FallbackPrice, int stock = 0)
|
public Product (string name, int price = FallbackPrice, int stock = 0)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
_price = price;
|
_price = price;
|
||||||
_stock = stock;
|
_stock = stock;
|
||||||
InStock = _stock > 0;
|
if(price <= 0 || price % 5 != 0)
|
||||||
|
{
|
||||||
|
_price = FallbackPrice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddSale()
|
public bool AddSale()
|
||||||
|
|
@ -32,6 +35,6 @@ public class Product
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Name} € {Price} [{_stock} in stock | {NumberSold} sold]";
|
return $"{Name,-10} € {(decimal)Price/100:0.00} [{_stock} in stock | {NumberSold} sold]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue