In Zoo 1.5, move the portion and price calculations into the objects that own their data. Return the amount actually removed from a wallet, pass that payment to the vending machine, and use Boolean and string return values to answer questions about the zoo.
BGetting Started
1Copy your completed Zoo 1.4 solution, then rename the copied folder and solution file for Zoo 1.5. Open the copied solution in Visual Studio.
2Build your starting solution before making the following changes.
CStarting Point — End of Zoo 1.4
The feeding handlers already calculate a portion from Weight and PortionSizePercentage, calculate its price, and call RemoveMoney, AddMoney, RemoveFood, and Eat. Pregnancy is already represented by the Baby reference. The starting-state reference below uses the members present in the supplied Zoo 1.4 end project.
Starting structure — supplied Zoo 1.4 End
NNew
CChanged
RRemoved
1In MainWindow.xaml.cs, confirm these calls already appear in the matching creation methods after the FeaturedAnimal fields, including Weight and Type, have been assigned. Add a missing call once so the starting state matches the completed Zoo 1.4 project.
In CreateComoZoo():
this.ComoZoo.FeaturedAnimal.MakePregnant();
In CreateSanDiegoZoo():
this.SanDiegoZoo.FeaturedAnimal.MakePregnant();
2Create each zoo and inspect its FeaturedAnimal. Dolly and Patti are both Female. Confirm their Baby references are non-null, with starting Baby weights of approximately 3.53 and 0.327 respectively.
Use Returned Values Throughout the Feeding Transaction
Acceptance Criteria
The animal returns its portion size using its existing percentage field.
The vending machine returns a price rounded to cents.
The wallet returns zero, the requested amount, or its remaining balance as appropriate.
Guest returns the wallet’s result to MainWindow.
Both feeding handlers deposit the returned payment and use the calculated portion for food removal and eating.
2.Return the Food Portion Size
Animal returns its portion size
NNew
CChanged
RRemoved
GetPortionSize call and return
NNew
CChanged
RRemoved
Class change: add publicdouble GetPortionSize() to Animal. Keep Weight and PortionSizePercentage. Call flow: MainWindow calls FeaturedAnimal.GetPortionSize(); Animal returns its calculated portion; MainWindow stores the result in foodWeight.
Problem
Both feeding handlers reach into the animal to calculate its portion. The animal can provide that answer itself.
Solution
Add Animal.GetPortionSize() and use its returned value in both feeding handlers.
AMake the Changes
1In Animal.cs, add GetPortionSize() inside the Animal class, after the fields and before Eat. Use the existing PortionSizePercentage field so the calculation stays with the animal.
1Create each zoo, then break on its feeding handler’s first statement. Step into GetPortionSize(), inspect the animal’s fields, and step out. After the assignment runs, foodWeight should be approximately 0.706 for Dolly and 0.0654 for Patti.
3.Return the Food Price
VendingMachine returns a rounded price
NNew
CChanged
RRemoved
DetermineFoodCost call and return
NNew
CChanged
RRemoved
Class change: add publicdecimal DetermineFoodCost(double maxFoodWeight) to VendingMachine. Call flow: MainWindow passes foodWeight to AnimalSnackMachine.DetermineFoodCost; the vending machine calculates and rounds the price; MainWindow stores the returned value in foodCost.
Problem
The handler also reaches into the vending machine to calculate food cost. Move that calculation into the vending machine and round the returned price once.
Solution
Add VendingMachine.DetermineFoodCost(double maxFoodWeight) and use its rounded return value in both feeding handlers.
AMake the Changes
1In VendingMachine.cs, add DetermineFoodCost(double maxFoodWeight) after AddFoodBag. The existing using System; makes Math.Round available.
1From newly created zoos, step through DetermineFoodCost. Como’s unrounded cost is 0.5295m and its returned cost is 0.53m. San Diego’s unrounded cost is 0.07848m and its returned cost is 0.08m.
4.Return the Amount Actually Removed
Guest and Wallet return the actual payment
NNew
CChanged
RRemoved
Payment returned through Guest
NNew
CChanged
RRemoved
Class changes: change RemoveMoney(decimal amount) from void to decimal in both Wallet and Guest. Call flow: MainWindow calls Visitor.RemoveMoney(foodCost); Guest calls Wallet.RemoveMoney(amount); Wallet returns the amount removed; Guest returns that same value to MainWindow.
Problem
A requested payment may exceed the wallet’s balance. The caller needs to know how much money was actually removed.
Solution
Change Wallet.RemoveMoney and Guest.RemoveMoney to return decimal, passing the actual payment back to the feeding handler.
AMake the Changes
1In Wallet.cs, replace RemoveMoney(decimal amount) with the following version. Change the return type from void to decimal. Each branch assigns amountRemoved; the method then subtracts and returns that amount.
The first branch rejects zero or negative requests. The second branch pays the full request when funds are sufficient. The final branch pays the remaining balance when funds are insufficient.
BCheck Your Work
Use a breakpoint in Wallet.RemoveMoney. Test each case independently with a fresh balance; inspect amountRemoved before the return statement.
Start with MoneyBalance = 5.25m and request amount = 0.53m. Confirm amountRemoved = 0.53m and the ending MoneyBalance = 4.72m.
Start with MoneyBalance = 0.20m and request amount = 0.53m. Confirm amountRemoved = 0.20m and the ending MoneyBalance = 0.00m.
Start with MoneyBalance = 5.25m and request amount = 0.00m. Confirm amountRemoved = 0.00m and the ending MoneyBalance = 5.25m.
Start with MoneyBalance = 5.25m and request amount = -1.00m. Confirm amountRemoved = 0.00m and the ending MoneyBalance = 5.25m.
1Confirm all payment branches return the expected value and that Guest.RemoveMoney returns the same value as Wallet.RemoveMoney.
5.Use the Returned Payment in Both Feeding Handlers
AMake the Changes
1In each feeding handler in MainWindow.xaml.cs, replace the standalone Visitor.RemoveMoney(foodCost) call with a decimal payment assignment. Pass payment to AddMoney so the machine receives only the money the wallet removed.
2Complete darlaFeedDingoButton_Click as shown. The last two calls continue using foodWeight.
Follow the complete feeding call flow for either zoo:
MainWindow asks the featured Animal for foodWeight.
MainWindow asks the VendingMachine for foodCost using that weight.
MainWindow asks Guest to remove the cost; Guest asks Wallet and returns the actual payment.
MainWindow passes payment to the VendingMachine’s AddMoney.
MainWindow passes foodWeight to the VendingMachine’s RemoveFood.
MainWindow passes that same foodWeight to the Animal’s Eat.
BCheck Your Work
Restart the application, create both zoos, and click each feeding button once. The initial vending-machine MoneyBalance is 0.00m. Both featured animals begin with a Baby. Compare floating-point values approximately.
CCheck Your Work — Como Zoo — Dolly
foodWeight: 0.706.
foodCost / payment: 0.53m / 0.53m.
Visitor.Wallet.MoneyBalance: 4.72m.
AnimalSnackMachine.MoneyBalance: 0.53m.
AnimalSnackMachine.FoodStock: 249.294.
Animal.Eat weightGain: 0.5648.
FeaturedAnimal.Weight: 35.8648.
Animal.Eat babyWeightGain: 0.0706.
FeaturedAnimal.Baby.Weight: 3.6006.
DCheck Your Work — San Diego Zoo — Patti
foodWeight: 0.0654.
foodCost / payment: 0.08m / 0.08m.
Visitor.Wallet.MoneyBalance: 3.67m.
AnimalSnackMachine.MoneyBalance: 0.08m.
AnimalSnackMachine.FoodStock: 249.9346.
Animal.Eat weightGain: 0.05232.
FeaturedAnimal.Weight: 3.32232.
Animal.Eat babyWeightGain: 0.00654.
FeaturedAnimal.Baby.Weight: 0.33354.
1Set breakpoints in both handlers. Step through the calls and confirm the values listed for each zoo. Eat already updates the animal and its Baby; use its existing implementation.
6.Return Pregnancy Status and Exit Early
Pregnancy status and the early return
NNew
CChanged
RRemoved
MakePregnant checks the existing Baby
NNew
CChanged
RRemoved
Class change: add publicbool GetIsPregnant() to Animal and use it in the existing void MakePregnant() method.
Zoo 1.4 already uses Baby == null in MakePregnant. Give that test a named method, then return early when pregnancy already exists.
AMake the Changes
1In Animal.cs, add GetIsPregnant() after the fields and before GetPortionSize(). It returns true when Baby references an Animal.
2Replace MakePregnant() with the following version. Put the early-return condition at the beginning, then move the existing Baby creation statements outside the old if block.
CreateComoZoo() or CreateSanDiegoZoo() calls the featured animal’s MakePregnant().
MakePregnant() calls GetIsPregnant() on that same Animal.
If Baby != null, the returned value is true and MakePregnant() ends immediately.
If Baby == null, the returned value is false and the existing Baby creation and field assignments run.
BCheck Your Work
1Break in MakePregnant while creating each zoo. With Baby initially null, confirm GetIsPregnant() returns false, allowing creation. Dolly’s Baby starts at approximately 3.53 pounds; Patti’s starts at 0.327 pounds.
2While paused after creation, call MakePregnant() again on that same animal in the debugger. Confirm GetIsPregnant() returns true and the existing Baby reference and values are preserved.
7.Return Machine Status and Formatted Temperature
Boolean and string return values
NNew
CChanged
RRemoved
Class changes: VendingMachine.IsFull returns bool and Zoo.GetTemperatureDisplay returns string.
Add two more methods from the completed Zoo 1.5 design. One answers a Boolean question; the other returns text formatted for display.
AMake the Changes
1In VendingMachine.cs, add IsFull() after DetermineFoodCost and before RemoveFood. The comparison reports whether the stock has reached or exceeded capacity.
2In Zoo.cs, add GetTemperatureDisplay() after the Visitor field and before the class’s closing brace. It returns the birthing-room temperature with one decimal place.
1With execution paused after creating a zoo, evaluate this.ComoZoo.AnimalSnackMachine.IsFull() or its San Diego equivalent: it returns true. After one feeding it returns false; after the matching fill button it returns true.
2After creating San Diego Zoo, evaluate this.SanDiegoZoo.GetTemperatureDisplay(): the result is "77.0" with a period-decimal culture. Increase the temperature once and check for "77.5". The decimal separator follows the application’s current culture.
8.Review the Completed Design
Ending structure — supplied Zoo 1.5 End
NNew
CChanged
RRemoved
The completed Zoo 1.5 structure retains the starting fields and relationships. Confirm these additions and changes:
Animal adds double GetPortionSize() and bool GetIsPregnant().
Animal.MakePregnant() remains void and now returns early when GetIsPregnant() is true.
Wallet.RemoveMoney(decimal amount) returns decimal and handles nonpositive requests, full payment, and partial payment.
Guest.RemoveMoney(decimal amount) returns the wallet’s decimal result.
VendingMachine adds decimal DetermineFoodCost(double maxFoodWeight) and bool IsFull().
Zoo adds string GetTemperatureDisplay().
Both feeding handlers use GetPortionSize(), DetermineFoodCost(foodWeight), and the returned payment.
Animal.Eat, VendingMachine.AddMoney, VendingMachine.RemoveFood, and VendingMachine.AddFoodBag retain their Zoo 1.4 implementations.
BirthingRoom.Animal retains its existing name. XAML controls and their Click handlers retain their existing names.
IsFull() and GetTemperatureDisplay() are available but are not called by the supplied MainWindow code.
ACheck Your Work
1Build the solution and resolve errors or warnings. Include XML return-value documentation on every added or changed value-returning method.
2Run from a fresh start. Create each zoo before using its feeding, filling, or temperature controls. Confirm both feeding paths and all existing buttons work.
3Check exact casing: GetPortionSize, DetermineFoodCost, RemoveMoney, GetIsPregnant, IsFull, GetTemperatureDisplay, Sex, and PortionSizePercentage. The existing XAML names, button Content, and Click handlers need no changes.
9.Submit Zoo 1.5
AConfirm all modified C# files pass the project’s StyleCop checks with no warnings.
BClose Visual Studio and create a ZIP file containing the complete Zoo 1.5 solution folder.