Now,
there are so many possible solutions to create this Coffee Machine Program, satisfying all the requirements,
and the way that you code it up is essentially your choice, right?
Whether if you decide to use a while loop or use a for loop or create a different data structure, there
are endless possibilities.
What I'm going to show you now is just one of those possibilities.
And what's really important is you don't feel like you've done it wrong just because it's different
to mine.
As long as it works the way that you expect it to, then consider yourself successful.
The first thing I'm going to do is create a new project in PyCharm, and I'm going to call my project
CoffeeMachine. Again, making sure that I've got the latest version of Python as the interpreter.
I'll click create.
Now the first thing I'm going to do here is right click on this and create a new file, which is going
to be my main.py.
And then I'm going to go to my starting project in Replit,
and I'm just going to copy everything there is over here and paste it into this main.py.
Now you might find the font of your code or of PyCharm a little bit too big or too small.
If that's the case, you can just go into preferences and change the appearance and the font to a different
size,
and this is for the user interface.
And if you want to change the font of the Editor, then you can go here, go to font and then change that
size here I've tried to make it as large as possible so that when you're looking at this video on an
iPad or an iPhone, all the code should still be readable.
But of course, normally when you're coding, you'd probably want to fit more lines into the same screen,
but it's not good to strain your eyes, so try to strike a balance there.
Now I'm going to collapse that sidebar because I'm going to be coding entirely in this one file.
Now notice that at the beginning we get given a MENU,
and this is a dictionary which contains three entries,
and each of those entries have a name of a drink: espresso, latte, and cappuccino.
And then each of them have a value that holds a bunch of data, including the ingredients that are required
to make that drink, and also the price of the drink.
Now there's also a resources dictionary which holds the resources of the coffee machine.
Now that we've got all of that, then we're ready to go.
I'm going to tackle these requirements one by one.
And the first one says to prompt the user by asking, "What would you like? (espresso, latte, or cappuccino)
So I'm actually gonna just straight up copy this line and put that into an input.
This is going to be saved into some sort of variable which I'll name choice.
Now it tells me that the prompt should show every time action has completed,
for example, once the drink is dispensed and it should show again, and again, and again.
So that means we're probably going to have to embed this input in some sort of while loop.
So I'm just going to say for now, while something is True, then keep asking for this prompt. Right
now, if we decide to go and Run this code where we go to run and then click on this button and then
select the main.py to run, then you can see that it asks me, "What would you like?"
And if I put an input, it will keep asking me until eternity, basically, because there's currently
no way of turning that True into False.
So let's take a look at the next requirement.
We should be able to turn off the coffee machine by entering "off" into the prompt.
For maintainers of the coffee machine, they can use, off as the secret word to turn off the machine,
and your code should end execution when this happens.
So when somebody wants to buy coffee, this is the line that they see,
but when a maintenance guy comes along, then they should be able to enter something,
and if this choice happens to equal the secret code which is off, then in this case we should stop
the while loop and exit.
So that gives us a way of changing this true into some other form of variable.
Right?
So we could create a new variable called is_on.
Start it off as True,
and while the machine is_on, then it should continue to loop through and ask the user for their choice,
but if the choice happens to be off, then we're going to turn that is_on into False.
Now if we run our code again,
so now that you've run it once, you can either stop it or you can rerun it.
And now it's going to stop your existing code and rerun the code.
So if you don't want to see this dialog every time, then just check this box, and then click Stop and
Rerun.
So now if we make a selection or we say something, basically anything other than the keyword which
is off, it's going to loop back and forth and keep prompting us.
But if I say off, then the machine turns off and you can see that I've now exited the program.
Now we've tackled 1 and 2,
let's go on to Number 3.
When the user enters the keyword "report" to the prompt, another secret word,
a report should be generated that shows the current resource values, for example, water, milk, coffee
and money.
So how can we do that?
Well, firstly, we don't actually have a variable that holds the amount of money.
So let's create something.
Let's call it profit maybe and set it to equal 0 to begin with.
Our machine has an empty money box in the beginning, so now we have to check to see.
Well, elif, the choice was equal to report,
well, in this case, we have to generate a report.
And the report is basically going to print all the values of these resources.
So I'm simply going to copy the expected output and I'm going to paste it here,
and then we can try and turn that into print statements, making it dynamic instead of hardcoded.
In my case, I want to add print in front of all of these lines.
And previously we've been doing this just by writing it one by one,
and then maybe we could copy and paste it.
But let me show you a quick tip that you can do in PyCharm. If you're on Windows, hold down the Alt
and the shift key on your keyboard.
If you're on a Mac, hold down the option and the shift key.
Now click at the beginning and hold and drag down.
So if that doesn't work, try it a few times,
you'll get the hang of it eventually.
But notice how I've now got four cursors.
And that means when I write print.
Check this out.
Isn't that cool?
I've managed to write on four lines at once because I need that repeat functionality, and this is a
way of doing multi-line editing.
Remember that shortcut and use it in the future if you find it useful.
So I'm actually going to change this all into f-strings because I want to change these numbers, instead
of being hardcoded, I want to insert them into here using the curly braces.
The water is stored under resources and then it's in the key called "water".
And now notice how I've got a outer double quote,
so I can't have an inner double quote.
So I'm going to change this into single quotes instead, like so.
And I'm going to do the same for milk and coffee.
So now I've added the water, milk and coffee into my print statement.
All I have left is the money.
So let's delete the value and let's insert that profit into here.
Now let's run our code again and let's check it out.
If I type report, it should now give me a report of all the current values, and money is equal to $0
because that's what we start off with.
We're now ready to tackle number four.
Here we have to check that when the user chooses a drink, we're going to check if there are enough
resources to make that particular drink they chose.
For example, if a latte requires 200ml of water, but there's only 100ml left in the machine, it
should not make the drink as it actually can't make the drink,
and it's going to print out,
"Sorry, there's not enough water," or "not enough milk," or "not enough coffee," whatever it may be.
So let's tackle this particular checkpoint.
Now that I've got the if choice is equal off, if choice is equals report,
now if it's not either of those, then they're probably going to be entering the name of a drink.
So let's catch that using an else statement.
And then inside this else statement, I'm going to get hold of the particular drink that they ordered
by tapping into our MENU dictionary.
And then using that choice they typed in as the key.
Let's say that the particular drink that they chose is equal to MENU,
and then the key is of course going to be the choice.
So now if I just print this drink and I run my code...
So the shortcut for running is actually holding down the control and R.
And now I can go down here and you can see it's asking me for what I would like.
So I'm going to choose latte.
And what's going to be printed is the latte entry in my recipes dictionary up here.
So this particular value, now that I've got this value stored inside a variable called drink, well
then I can tap into its ingredients and loop through each of the ingredients, comparing it against
the resources and seeing if there's enough.
Now this is a little bit of functionality that should probably be self-contained.
So instead of just printing the drink I'm actually going to create a new function.
So up here I'm going to create a new function with our def and I'm going to call it, is_resource_sufficient().
And this is_resource_sufficient() is going to take the order_ingredients as an input,
and then it's going to work on that.
So if we want to call that function and pass in the order_ingredients, we'll have to call
is_resource_efficient()
and then the order_ingredients will be from the drink and then getting hold of the values under the
key, ingredients.
So under this particular key it will fetch this particular dictionary.
And this is the dictionary that's going to be passed over to this function as the input.
So now that we have a hold of a dictionary with all the ingredients that are required and the amount
of each ingredient, we can now compare it against our resources, which is a very similar dictionary
with the resources and the amount that's left in the machine.
We can loop through the order_ingredients, and for each of the items in the ingredients, we're going
to check to see if the order_ingredients at that particular key,
so this is getting hold of the value, is greater than or equal to the resources using the same particular
key.
For example, if we were looking at the first example, the item would be equal to water,
so if we fetch the value from order_ingredients with the key of water, we should get hold of 200,
and we would now test to see if 200 is greater than or equal to the 300 that we have under the resources,
well, in this case then we should probably tell the user that we actually can't make it.
So let's put an if statement there.
And I'm going to use this same string here to print it out.
Now notice when I pasted that string in and it has the double quotes from the PDF file here that it's
actually not being recognized,
and I'm getting an error here.
And the important thing to note is that there's a difference between decorative double quotes like these,
which look different for the beginning quote and the end quote,
and then there are programming double quotes which look like this.
So I'm going to select this whole line and I'm going to add a double quote,
and notice how they look identical from the front and the back.
So now it's going to print,
"Sorry, there is not enough..."
And the enough of what?
It's going to be the item that we're currently looping through.
So let's change that to an f-string, which makes that an active piece of code that's going to be inserted.
And in this case, we're going to return False because there is not enough resources.
But otherwise, if we managed to get to the end of the for loop and we still haven't returned or exited
the function by returning False, then, in this case, we can return True.
So if this particular logic is a little bit confusing for you, you could have something like like this.
So you have is_enough == True?
And you could change is_enough to False if any of the order_ingredients are greater than the resources.
And finally at the end you could return is_enough.
So basically it stays true unless one of these if statements gets activated.
But for simplicity's sake, I'm actually just going to keep it simple like this.
And we're now ready to receive that result here.
So we can put an if statement here.
If the resources are sufficient for the drink, then we can proceed to continue to the next step.
The next step is to process coins.
The user is going to be asked for the number of quarters they have, the number of dimes, nickels and
pennies.
And you have to remember their values.
So if you're from the US, this shouldn't be a problem,
but if you're like me, somebody who's not from the US, I actually find it really confusing
when I go to the States,
I always think that the larger coin that the nickel should be worth more than the dime, but I think
that's just me being silly.
So we're going to ask the user to insert some coins, we're going to process it, and then we're going
to calculate the total value of the coins they inserted.
That to me sounds like it should be a separate function as well.
So let's create another function here which I'm going to call process_coins().
And this is not going to take any inputs, but it is going to return the total value of the coins inserted.
Now how do we process coins?
Well first we can print to ask them to please insert coins, and then afterwards we're going to somehow
calculate a total.
Right?
This is the variable that we're going to keep track of,
and we're going to return as the output of this function.
The total is going to be calculated based on the four types of coins.
So the first question we're going to ask them is, "How many quarters?"
And this of course is going to be a whole number,
so we're going to turn it from a string into an integer.
And we know that each quarter is worth 0.25 of a dollar.
So we can multiply the number of quarters by 0.25,
and then we'll get the monetary value.
Now we'll need to do the same thing for a bunch of other coins.
So instead of quarters, this is going to be dimes, and then it's going to be nickels,
and finally, it's going to be pennies.
Dimes are worth $0.10, nickels are worth $0.05 and pennies are worth $0.01.
Now, instead of just setting the totals at each of these values, every subsequent one other than the
first one which, remember, creates this variable and sets its value, every other one is just going
to be added to the current value.
Like this.
So now at the very end of all of this, we're going to return the total as the output.
And whenever you have something that returns like both of these functions, you should probably be adding
a docstring.
So in this case, this """Returns the total calculated from coins inserted."""
And in this case, what happens is it returns True when order can be made, and False if ingredients
are insufficient.
Now let's call this function that we created process_coins().
If there's enough resources to make the drink, then the next step is to actually ask them for the money,
so here is where we're going to call process coins.
And notice when I write this and I hover over it, you can see that docstring we just wrote, "Returns
the total from coins inserted."
That means this is going to return, and we need to capture the user's payment in this variable.
So this returns the output, replaces this function call,
and then it gets saved inside this variable called payment.
Now what are we going to do with this payment.
Well that goes on to the next step which is to check that the transaction was successful.
So we have to make sure that the user has inserted enough money to actually purchase the drink they
wanted.
But each drink, of course has a different price,
so if the user inserts enough money, then we're going to give them some change.
But if they haven't inserted enough money, then we're going to say, "Sorry, that's not enough money..."
And the money is refunded.
But if they have inserted enough money, then the cost of the drink is going to be added to the machine
as the profit.
So the next time when we trigger the report, then we're going to get to see the increase in the monetary
value.
Again let's create a new function, and let's get rid of some of these squiggly lines by adding enough
spaces in between the functions.
This one I'm going to call is_transaction_successful().
Because that's basically what we're going to be checking.
And it's going to take two inputs,
It's going to take an input in terms of the amount of money that was received,
and it's also going to have another input, which is the cost of the drink.
This function's goal is to """Return True when the payment is accepted, or it's going to return False
if the money is insufficient."""
Notice how there's this line to the right here of your editor.
Basically, what happens is if you have a line of code that's a little bit too long past the recommendation
from PEP 8, you can see that PEP 8 recommends that a line should not be longer than 120 characters,
because it's very hard to read for somebody scrolling around like this.
So in this case, they would want you to put it onto a new line so that you don't have to scroll and
you can see it all on the same screen.
But in our case, this is not a problem because we have not exceeded the line length recommendation.
So how are we going to check if the transaction is successful?
Well, if the money_received is greater or equal to the cost of the drink,
well, in this case, that means we should return
True, right?
The transaction is successful.
And if it's not the case, if it's the opposite case, then we're going to print.
"Sorry, that's not enough money..." and the money is refunded to them.
So let's print that here.
And we're also going to return False.
Remember that the return has to be the last thing in your function,
if you put this above the print statement then the print statement will never get called.
And that's why you have this highlight.
And if you click on it, you can see that it tells you, "This code is unreachable."
So there's a lot of these little hints and tips that really help you when you're developing.
But if the user has inserted enough money, then the cost of the drink should be added to the machine
as the profit so that we can see it in the next time report is triggered.
So this means that if this money_received is greater or equal to the drink_cost, then we're going to
add to this variable called profit that we have up here, which starts out at 0,
but we're going to add the drinks_cost to profit.
So we're going to say profit += drinks_cost.
And now you'll see an error under the profit because this is acting inside a local scope and profit
is outside in the global scope.
So in order to reach it, we have to say global profit.
And the final part of checking the transaction is seeing if the user has inserted too much money, then
the machine is going to offer change.
For example, here is however many dollars in change and the change should be rounded to two decimal
places.
Again, it's going to be inside this if statement.
So the change is going to be equal to the amount of money_received subtracting the drink_cost.
And this of course could be any number of decimal places.
So we can use the round function which you've seen a long time ago to round this number,
and the second input is the number of decimal places.
So if you just hover over the function name then you can see the docs come up.
And this function is basically going to round a number to a given precision in decimal digits.
So the first is the number you want to round, and the second is the number of digits that you want after
the dot, basically.
Now that we've gotten hold of the change, we're going to print and tell the user, basically, "Here is
this many dollars in change..."
And of course I have to add an f to activate that f- string.
So now we're ready to call is_transaction_successful,
and we're going to pass in the money_received and the drink_cost.
So the money_received is of course going to be the payment from the previous step that was calculated
from all the coins,
and the drink_cost is going to be based on the drink,
and it's under the key, cost, which we can confirm up here.
So the drink is this dictionary.
And then there's the ingredients and the cost.
Let's rerun our code and let's test it out with something.
Let's say I want a latte.
"Please insert coins."
Let's say we tried to insert insufficient coins,
it tells us, "Sorry, that's not enough money.
Money is refunded."
But let's try giving it enough coins this time.
And in this case, it accepts it and it tells us,
"Here's $2.42 in change," rounded to two decimal places, and we're ready to take another drink.
So now if we hit report, you can see that we've now earned some money in our machine and all our code
is working as expected.
So we're now ready to tackle the final part, which is to make coffee.
If the transaction is successful and there are enough resources to make the drinks a user selected,
then the ingredients that make the drink should be deducted from the coffee machines resources.
For example, before I purchase a latte, I have 300ml of water.
After I purchase a latte that gets reduced by 200 to 100, and the same happens to the other ingredient
values,
but of course, the money goes up because I've already taken payment in the previous step.
Let's take this into an if statement, because remember, this function returns True when the payment
is accepted, or false if the money is insufficient.
So this is where we're going to call our next function, which is to make coffee.
So let's create a make_coffee().
In order to make coffee, we need to know the drink_name so that we can tell the user here is your particular
drink,
and we'll also need to have the order_ingredients.
The goal of this function is to deduct the required ingredients from the resources.
In order to do that, we're going to get hold of the order_ingredients and we're going to loop through
them.
So for each of the item in the order_ingredients, we're going to look inside the resources for that
particular item,
and we're going to subtract the amount that's in the order_ingredients.
And once all of that is done so the for loop ends, then we can print...
And we can even add an emoji to this.
On a Mac you can insert an emoji by going to Edit, Emoji & Symbols, on Windows,
the easiest thing to do is to just search Google for a coffee emoji and then copy and paste it into
your code.
So now let's call make_coffee() here,
and notice how if we are here, the machine is_on, and it's not any of these other previous choices,
and then the resource is sufficient, and the transaction is successful.
These are all the steps that it took us to get to this particular stage in our code.
So now we're going to make the coffee and we're going to pass in two things.
So let's just see the prompt again.
We need to give the drink_name, which is going to be the choice that the user entered, and the
order_ingredients, which is going to come from the drink,
and it's under the key, ingredients.
So now we're ready to test and run our code once more.
Let's say I want a latte and I'm going to insert lots of money.
And now I have my latte.
If I print report, you should be able to see that a bunch of resources were subtracted, and the money
is increased.
If I try to order another latte, it should fail because there's not enough water and there's not enough
milk.
You can see that it's not going to let me go through as long as one of the ingredients is not enough.
So we've now managed to fulfill all of the requirements of our Coffee Cachine Program.
Now, there's probably a lot more complexity that you could add to your coffee machine,
but basically what I wanted to show you today is how you would program something that exists in real
life, like a coffee machine. And even something that seems as simple as a coffee machine,
it can lead to a lot of errors, a lot of bugs, and a lot of anguish.
But it's good.
The more that you struggle, the closer you get towards your goals, and the clearer the role of the
function, the easier it will be for you to untangle the logic.
If you want to take a look at the completed code that I've written in this lesson, then you can head
over to solution.py in the Beginner's PyCharm Course.
Make sure that you've managed to fix any issues in your code, and that it runs exactly in the same
way as expected in the program requirements.