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 coffee machine. Again,
making sure that I've got the latest version of Python as the interpreter I'll
click
create.
Now that 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 Repl.it 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 were looking at this
video on an iPad or an iPhone, all the code 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 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 probably going to have to embed this input in some sort of while
loop. So I'm just gonna 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've put an input,
it'll keep asking me until eternity, basically,
because that there's currently no way of turning that true into a 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 code 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 dialogue 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 key word, 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 zero 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 a dynamic instead of hard-coded. 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 are 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 out 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 multiline 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 fstrings because I want to change
these numbers instead of being hard-coded,
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 4. 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 200 ml of water
but there's only 100ml left in the machine,
it should not make the drink because it actually can't make the drink
and it's going to print out, 'Sorry, there's not enough water' or not enough milk,
not enough coffee, whatever it may be.
So let's tackle this particular checkpoint.
Now that I've got the if choices equal off, if choice 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
it 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_efficient is going to take the order ingredients as a
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 other ingredients will be from the drink and then getting hold of
the values under the key ingredients.
All right.
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 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 know is that there's a difference between decorative
double quotes, like these,
which looked 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 fstring
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 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's 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, um,
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 it was 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 input,
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 10 cents,
nickels are worth 5 cents,
and pennies are worth 1 cent. Now,
instead of just setting the totals of 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 onto 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 a input in terms of the amount of money that was received,
and it's also going to have another input, which is 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.
Uhm
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 you 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.
Right.
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 zero,
but we're going to add the drinks cost to profit.
So we're going to say profit += drink_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 around 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 fstring.
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.
Right.
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
the user selected, then the ingredients to make the drink should be deducted from
the coffee machine's resources. For example, before I purchased a latte
I have 300ml of water.
After I purchased the 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 their money is insufficient.
So this is where we're going to call on next function
which is to make coffee. So let's create
make_coffee. In order to make coffee
we need to know the drink name so that we can tell the user here's your
particular drink.
And it will 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 items 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.
Right.
On a Mac
you can insert an emoji by going to edit, emoji, and 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 hit 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 is 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 machine
program. Now,
this 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 its 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 simply head over to the link that's in the resources and you'll be able to
see it in
Repl.it. Make sure that you've managed to fix any issues in your code
and that it runs exactly the same way as expected in the program requirements.