/// <summary> /// Attempts to vend an item /// </summary> /// <param name="itemPriceInUnits">The unit price of the item</param> /// <param name="tenderedChange">The change tendered to purchase the item</param> /// <returns>The success of the vend</returns> protected override VendingResult DoVend(int itemPriceInUnits, IEnumerable<Change> tenderedChange) { // We can use the tendered change supplied by the user to work out the change we can give. // For examples, for an item costing 20p a user may supply a 2p followed by a 20p. // If the machine was empty and we didn't consider that they tendered then we couldn't // give change, but if we do include it in the calculation then we can // NOTE: In the event we can't give change we will need to remove it Add(tenderedChange); // The caller methods in the base have validated that the tendered change is at least the price of the item int changeRequired = tenderedChange.TotalValue() - itemPriceInUnits; VendingResult result = Greedy(changeRequired, this.Balance); if(result.Success) { // We were able to give the exact change. // We now need to remove the coins we're going to give from the machine Remove(result.Change); } else { // We aren't able to give change, so remove the tendered coins // from the machine so that the balance is flat Remove(tenderedChange); } return result; }
private ItemVM ToCollection(IEnumerable <ItemData> items) { var itemVM = new ItemVM { Items = items, TotalValue = items.TotalValue(), ProfitAmount = items.Profit() }; return(itemVM); }
/// <summary> /// Attempts to vend an item /// </summary> /// <param name="itemPriceInUnits">The unit price of the item</param> /// <param name="tenderedChange">The change tendered to purchase the item</param> /// <returns>The success of the vend</returns> protected override VendingResult DoVend(int itemPriceInUnits, IEnumerable<Change> tenderedChange) { // We can use the tendered change supplied by the user to work out the change we can give. // For examples, for an item costing 20p a user may supply a 2p followed by a 20p. // If the machine was empty and we didn't consider that they tendered then we couldn't // give change, but if we do include it in the calculation then we can // NOTE: In the event we can't give change we will need to remove it Add(tenderedChange); List<Change> changeToGive = new List<Change>(); // The caller methods in the base have validated that the tendered change is at least the price of the item int outstandingChange = tenderedChange.TotalValue() - itemPriceInUnits; // The recursive algorithm is more performance intensive that a regular greedy // algorithm as it considers all possibilities. We can simplify this a bit // by only using change which the denomination is no bigger than the amount we need to give, // as anything bigger will be ignored List<Change> changeAvailable = this.Balance.Where(c => (c.Denomination <= outstandingChange)).ToList(); // Kick off the recursion VendingResult result = RecursiveVend(outstandingChange, 0, changeAvailable); if(result.Success) { // We were able to give the exact change. // We now need to remove the coins we're going to give from the machine Remove(result.Change); } else { // We aren't able to give change, so remove the tendered change from the machine Remove(tenderedChange); } return result; }
/// <summary> /// Validates the supplied vending parameters to save each base class having to do it /// </summary> /// <param name="itemPriceInUnits">The price of the item</param> /// <param name="tenderedChange">The change tendered to purchase the item</param> private void ValidateVendData(int itemPriceInUnits, IEnumerable<Change> tenderedChange) { // We need to be buying something that cost something... if(itemPriceInUnits < 1) throw new ArgumentException("invalid price", "itemPriceInUnits"); // The caller needs to have supplied some money to buy the items if(tenderedChange == null) throw new ArgumentNullException("tenderedChange"); // Make sure there are no nulls in the tendered change bool hasNullChange = tenderedChange.Contains(null); if(hasNullChange) throw new ArgumentException("there are null items in the tendered change", "tenderedChange"); // Make sure the change is at least the value of the item int totalTenderedAmount = tenderedChange.TotalValue(); if(totalTenderedAmount < itemPriceInUnits) throw new ArgumentException("not enough change tendered", "tenderedChange"); }