 In this video, we're going to look at another nice application of why loops, in particular when it comes to games. So let's create a new file, and let's call it simply games.ipif notebook. And games, an example of what we are going to call indefinite loops. So loops for which we don't know how long they run. And we have seen in the previous video, when we talked about collet conjecture, that there are problems where we cannot say when the end will be reached. We can say that there will be an end, but we cannot say how many steps will there be until we reach the end. And for games, this is often the case. So let's say application games. So let's pretend that we are going to write a game where some hypothetical user plays with, and the game is about this. The computer tosses a coin, and the user simply has to, or the player, has simply to guess correctly. So whatever site comes up top, this is basically the one, the site, that the user has to guess. So let's go ahead and see how we can do that. So first of all, we need to find a way of how a user, a player, can enter some text, and then the program uses whatever the player entered and does something with it. Python comes with a built-in function called input. And the input function works like this. It takes one argument, which is a text object. And this is going to be a so-called prompt. So let's write guess if the coin comes up heads or tails. And if I execute this, then what's going to happen is I get this text box here. And let's say if I write in there random text and I enter, then the return value of the entire cell, so the return value of this function call is going to be another text object with the value of random text. So if I go ahead and say, for example, heads, then it simply gives me back heads. Note also that this function, the input function, always gives you back text. So even if I go ahead and say I enter the number one, the integer one, if I click Enter, then I get back the number one with quotes as we see. So the number one also comes as a text object, a so-called string object, which we'll see in a future video what the string data type is all about. So for now, let's take this here and let's try to make a game out of it. So now you may wonder, what is the condition? So obviously this game has some looping nature built in. The computer first tosses the coin, then the player guesses. And if the guess is wrong, then what should happen is the game should start all over. So in other words, it's a guessing game. So the player will guess until he's right. So how can we model a loop for which we don't know how long it's going to run? So in the previous example, the college example, we at least had some condition. The condition was when we reached the number one. But here we don't even have a condition. We have nothing to work with. And there is a trick. So the trick goes like this. We will go ahead and we will write a Y loop. And as a condition, we will simply write true. And now you may wonder, the condition true, isn't that always true? And the answer is, of course, yes. So in other words, this loop would technically run forever. So if I go ahead and execute this, now the computer asks me, guess if the coin comes up heads or tails? I guess something. And then the next round starts. And the next round starts, and so on. So this game, this loop here, does never stop. So for now, I have to click the stop button in order to interrupt this cell manually. So we have to find another way of how we can get out of the loop. And let's do the following. Just to illustrate a command, there is a so-called break statement. And break is a statement that when it is hit, Python breaks out that is where it got its name from. It breaks out of the innermost loop. In this case, we only have one loop, the y loop. So if I execute this, and if I enter anything here in the text box, that basically the cell immediately is done. Because after the input function has been called, the break statement is executed, and break simply ends the loop. So this is a trick here. So we loop at first. That's why we call it an indefinite loop, because we have no condition. We don't know what condition needs to be fulfilled. So we loop at first forever, so to say. And at some point, we manually break out of the loop. And of course, we will break out of the loop once the user made a correct guess, of course. So let's go ahead and change the code a little bit. So first of all, whatever the user enters, we will store into a variable called guess. And now we have to come up with some idea, some model of how we can model a coin. So what we will do is, we will do the following. I'm going to import the random module. And you know that the random module has a function in it, which is called the random function. And if I call the random function in the random module, I get a random number between 0 and 1. And the value that I get back is a floating point number. And of course, it is uniformly distributed. So this is a distribution that you would learn in a statistics course. Now let's go ahead and compare the return value of the random function to, let's say, 0.5. So in how many percent of the cases is this true? Well, of course, it is true in 50% of the cases. Why? Because I just told you that the random function gives you back a uniform distribution. So in other words, in 50% of the cases, the number here will be between 0 and 0.5. And in another 50% of the cases, the number returned from the random function will be between 0.5 and 1. So by using this comparison here, I get now back either true or false with 50-50% chance. And if I want to model an unfair coin, I would simply go ahead and, for example, make it 90%. And then in 90% of the cases, I get back true. But for now, let's keep it as a fair coin, 50-50. And now let's use this expression inside the Y loop. So now let's put together some idea here. So let's first go ahead and say, maybe let's go ahead and write if and copy paste in the expression. So and then enter the line with a colon. So what does that mean? So if this condition is true, so if this condition is true, well, what this means for now, let's just make this up. This means the coin comes up heads. And then we are also going ahead. And we will write the else clause here. And the else clause basically means the coin comes up tails. OK? So now we have a way to execute code dependent on if either heads come up or tails come up. And now we have to continue. So now let's go ahead and say, let's write another if statement in there. And let's say if guess double equals, let's say heads, because we are modeling heads up here, then what we are going to say is we're going to print a nice message and say, yes, it was heads. And of course, the user one. And because the user one, we are going ahead and we are simply going to write break in here. OK? First we get a nice success message, then we say break. Otherwise, if the user gets us wrong, then we will say print. And then we are going to say, oops, it was heads. So this is the branch here where the user guessed tails, but the coin came up heads. And then we don't go ahead and write a break here, because the user did not win. Similarly, let's get rid of that here. Now I go ahead and simply copy and paste the entire logic down here. And now I will simply replace the heads with tails. OK? And let's see if the game works like this. So let's go ahead and execute the code cell. And now I get some message here. And it says guess if the coin comes up heads or tails. So let's go ahead and say heads. And I won. Let's play the game again. Let's make it heads again. And now it was tails. And now I get another text box. So let's go ahead and guess a second time, heads. And the coin came up tails again. And let's guess heads one more time. It came up head, tails again. OK? And in the fourth time, now we guess correctly. OK? So now this is how this is now an early version of a guessing game. However, this code here is not good in several aspects, actually. So one aspect is the following. Let's go ahead and let's maybe enter heads with an uppercase H. OK? Heads with an uppercase H. OK? Now the computer, the coin was tails. So let's guess again with heads was again tails. And now it says I get the error message. Oops, it was heads with lower case. And my guess heads with uppercase was not accepted. OK? And this makes sense because Python, as any other programming languages, basically is case sensitive. So in other words, if I input something that is not spelled in heads in all lower case, then I can spell heads in whatever capitalization I want, but then I just won't win, even if I made the correct guess. That is one reason why this program here is not so good. Another one is the following. And observe how I am basically have the same code in both clauses here, right? And this makes sense because we created the second clause basically by copy pasting. But whenever you find yourself copy pasting, then this is not good. And the reason why is because if ever you have to make some change up here, let's say maybe you have to write oops with, let's say, four O's instead of just three, well, you have to make the change a second time further below. And you must not forget to do so. So you have a certain redundancy, and that is very bad when it comes to maintaining code. OK, so let's look how we can improve the situation here. Let's first finish the game. OK, it's still tailed, so it seems to be like an unfair coin here, but it's not really unfair. This is actually a fair coin. So sometimes it happens that we get three or four tails after each other. So now I will leave that in here so that later on you can compare this. So that's the bad solution. And let's now make a cleaner solution. So let's say alternative solution. And let's say this is modular design. So what I'm basically doing is I'm taking different steps apart into individual steps. And instead of writing everything in one cell, I will basically spread the logic of the program into several cells and also into functions to make it easier to read and also easier to maintain in the long run. So let's see what we can do. So the first thing we are going to do is we will go ahead and we are going to define a function, which we call getGas. And getGas will do what it names already suggest. It will basically get the gas of the user. So in other words, the function takes no input. And then for the doc string, let's be clear what the function should do. So let's go ahead and say process the player's input. No arguments, but only returns now. And it's going to return a get. And it is going to be either a string, so a text object. SDR is just the abbreviation for text string, or none. OK, so the special value none that we have seen in a couple of previous videos. And now we are going to say either in lower case, heads or tails, if the input can be parsed, so understood in other words, otherwise none. OK, so let's implement this function. So let's go ahead and maybe go back to the top and simply go ahead and copy paste this line here. So we don't have to write it again. Guess if the coin comes up heads or tails. OK, so this works. Maybe we should also put a colon here. And now let's continue. And we know for sure that guess is definitely a string object. We saw that above. By using the input function, we always get back a string. So what can we do with the string function? Well, what we can do with strings, we saw that in one of the videos regarding chapter one, where we talked about different data types and that different data types imply different behavior of objects. And one functionality that any text object implies is we can call certain methods on it. And we saw the lower and upper methods. And we will also use it here. So guess.lower will basically take whatever word guess is and simply lowercase all the letters in it. And then we will do something else before. We will use another method, which is called strip. And the strip method will basically remove all the white space to the left and the right end of the word, of the guess variable. So in other words, maybe to show this to you in another code cell. Let's say I write long text here, just like this. And let's put two spaces here and maybe one space here. If I say dot lower, then of course I get back lowercase text. And if I say dot strip first, then we see that not only do I get back lowercase text, but also the leading and ending white space has been removed, stripped away. That is where the term comes from. So that is what strip does. And now one thing you have to understand when you use the string data type is the string data type always gives you back a new string. So in other words, we have to assign the return value of this method call into the variable guess again. So in other words, we get some first guess object here, some first text object that is stored in the guess variable. And then using this expression here, we get back possibly another text object and we simply override the old guess. So maybe let's also document this and write here simple input validation logic. So this makes sure that guess is basically that we can basically work with guess here. Now let's also make sure that guess is one of either heads or tails. And how can we do that? So what we can do is we can use the so-called in operator. So what we can do is I can say if guess in and the in operator takes on the right hand side as its operand, for example, a list. And let's make this a list where I specify two text objects inside. One is going to be heads, of course. The other is going to be tails. And then I'm simply going ahead and we'll say return guess. So what these two lines do is it checks if the guess, which we know down here, it has to be lowercase. It has no leading and ending white space. And also it is lowercase. We know for sure that if guess is in this list here, then we know it's a good guess. So we simply return it. Otherwise, so we could use else here. We say return none. But then we learned in a couple of videos before that whenever we have a pattern like this with several return statements, we can simply leave away the else clause. This is called the early exit pattern. And this does exactly the same. So this function now is kind of nice to us because now if I go ahead and say get guess and I call it, if I write in, for example, the number one, it does not raise an error, but it gives me nothing back. And the reason why I don't see anything here is because I get none back and none is basically invisible in JupyterLab. However, if I execute this and I write heads, then I get back heads. And also, one thing that's very nice, if I write heads in totally uppercase, I also get back heads in lowercase. So the function does what its doc string promises. It takes some input from a user and it gives back either heads or tails in lowercase or none. Okay, so that is the pattern. So there are only three different objects that can come out of this function. Lowercase heads, lowercase tails, or none, nothing else. And of course we could play with this function. So one thing we could do is we could basically also model common spelling mistakes or maybe make it even support several languages. So for example, let's do the following. Let's remove tails here. And let's replace it with head without an S. And also maybe with a German name cop which is the German translation for heads, okay? And then let's copy paste this entire line below and connect it to together using the elif clause. And then here we are going to say tails and maybe let's simply write tail here and the German word would be thal. Okay, so now we could actually go ahead and specify simply head and we still get out. I did one mistake, of course. That was almost, I was one step ahead of me. So of course I also have to change the guess here into heads in lowercase. So maybe let's write heads in lowercase here and tails in lowercase. And you see also I'm using single quotes here just know their perfect synonyms doesn't matter. I should have been, I should have used them uniformly here but it's okay for now. So let's define the function one more time and call it. And if I now go ahead and write simply head without the S, I still get back heads with an S, okay? Similarly, if I write thal, the German word, I still get back tails, okay? So this is kind of nice here because now you see that this function only concerns one thing, namely taking input and giving back one of three objects, lowercase heads, lowercase tails or none, nothing else. Okay, so that is one part. This is the get guess part. And now let's look at what else can we do here? So what else can we do here is we can pull out this part here and basically write a function that tosses the coin. So let's go down here and write a new function and let's call it simply toss coin and this function. Now just to illustrate a point, this is something that is now in addition to the previous version above. So this function will now take a parameter, let's call it p heads for the probability that heads comes up top and let's give it a default value of 0.5. And let's go ahead and specify also a doc string. So simulate the tossing of a coin. And then now here, let's write, it takes an argument. Let's call it p heads. This is going to be a float. And that is simply the probability that the coin comes up heads. And of course, because it's a probability, it must be between zero and one. Otherwise it would not be probability. Now in one of the previous videos, I talked about input validation in detail. Here I will not implement input validation because I'm assuming that the person who uses the toss coin function is just me, the author himself. So therefore I know for sure that I can only put any number, any float between zero and one in there and nothing else. So let's go ahead and let's say if and copy paste down the expression and now let's replace the 0.5 with simply p heads. And this is of course the case where heads comes up. So in this case, the function is going to return heads simply. And let's also put that of course in a doc string. So let's go ahead and write returns here as well. And let's call this simply the size on top. This is going to be a string. And this is going to be either, so let's say either heads or tails and nothing else. And so let's also include the other case here. So let's simply write return tails. And again, we could have written that with an else clause, but again, the else clause is not needed here. And now if I go ahead and I call the toss coin function without an argument, I get back either heads or tails in lower case, 50% chance for each of them. And I can also of course go ahead and play with the parameter. I can set it to 0.9 and now I will almost always get back heads, okay? So now what have we achieved? Well, basically we have made, we have pulled out two things from this big code cell here, namely the getting the input and also tossing the coin. We have parameterized them and also what is more important, we have made clear what we have to, what we can expect from both functions. So the first function can give us back one of three possible objects, either heads lower case, tails lower case or none. The second function will give us back one of two objects, either lower case heads or lower case tails. There's nothing else that can come back. So now we have to write some so-called clue code that puts the two functions together and implements the game. So let's go ahead and go ahead with the same approach as above. Let's write an indefinite loop while true. And now in the first line, we simply will go ahead and say, let's get the guess. So it simply goes ahead and works like this. So first let's get the guess from the user. And in the second step, we could go ahead and let's say we get the result from the user and the result is the result of the function toss coin. And now what we know because of the way we decided to functions is that we have for guess, we have three different options, for result we have two different options and two of them overlap. So in other words, we only have to care about lower case here. So in other words, everything that comes down here in terms of code can be case insensitive because we have made sure that everything is lower case anyway. So we don't have to care about that anymore. So now let's do the following. The get guess function gives us back, none in the case the user gives us back something not meaningful or enter something non-meaningful. We can check for that right here. If guess is none, then we'll say print, please enter either heads or tails, exclamation mark. So this is an error message, okay? Because the user entered something wrong. However, we could now, and now of course, if the user does not enter something wrong, we could write an else clause and then the program would simply go ahead. However, this would be a little bit too much here. So there's an easier way instead of going ahead on, of course we are not yet done here. There's still some code to come here. What we could do now is, we could do the following, instead of using this else clause here, where the alternative is the user entered something correctly. So if anything other than none means the user entered something correctly. So, but instead of modeling that with an else clause, what we are going to do, we're going to introduce another statement that we have not seen before, the so-called continue statement. And what the continue statement does, is it basically jumps right to the top of the loop again. So basically whenever Python hits the continue statement, we jump right into the next iteration of the loop. And because we are in a while loop, that also means we simply go back to the first line, okay? So that's what continue means. So maybe I'll write here as a comment, jump back to the top of the loop, okay? So now, down here, we now know that the player entered something meaningful. And with meaningful, I mean of course either heads or tails, something that could be understood as either heads or tails. So that means down here, we don't even have to bother with any misspellings, and also we don't have to bother with the user entering something wrong, or so this is already taken care of. So now let's continue and write code here. So after the coin toss has been done, let's go ahead and simply write if the guess the user made, double equals the result, which is basically, yeah, also either heads or tails. Then we know the player must have made the correct guess. So now what we can do is, we can print our success message from above. So the message was here, yes it was heads, but now what we can do is, we will simply copy paste this here, and instead of hard coding the word heads, what we are going to do is we are simply going ahead and we will say we will use the result variable here. And then of course we know that the game has been won, so we are going to break out of the loop again. And now we also have to model the case where the user guessed something meaningful but still incorrect. We could use an else clause here, and we could say print, and of course we can also copy paste the error message from above. And then instead of hard coding the word tails in here, we are simply going ahead and also refer to simply the result variable. And also because the break statement breaks out of the loop right away, what we can do is, we know for sure that no code after the break statement will be executed. Therefore, we can simply get rid of the else clause and unindent the print here as well. Okay? So this is now a solution that should do the same as before. So let's try. Let's play the game, and let's go ahead and maybe let's first enter some random text. And now I get back an error message saying, please enter either heads or tails. So let's go ahead and enter heads with an uppercase h. And it was tails. So now let's go on and say head with an uppercase h, but let's forget the f here. It was still tails. So let's do it one more time and still tails. So something is wrong here with this computer, but this is of course randomization. So sometimes random events are just random and I wanted to head to come up a lot further, a lot earlier, but it didn't. But now we see that at some point when I entered head I win the game. Okay? At some point after a couple of iterations you have to win no matter what you guess. Just a question of probability. And what we see here is now it doesn't matter how I spell the word. I can even leave away the s. Why? Because we just taught our program a little bit of variation regarding the spelling. Lower and uppercase does not play any role here. We get now a nice error message if we enter something incorrectly. And we have to assume that the player who plays this game is not a programmer. The idea is that we want to create a game that someone else plays that does not know how to program. And also we could parametrize everything here. And also the code is very easy to read because there is no redundancy. So I first get a guess. And if I care about how I get the guess well then I just go to the function and I can read up. But if I'm reading this code down here, the Y loop, maybe I don't care what get guess does. I simply say, okay, I'm getting the guess. I can live with that. Then what I do is I first check here if the user entered something meaningful. And let's maybe get rid of this comment as well. So does the user or did the user enter something the computer can understand at all? If not, then we give an error message and jump back to the top. So this is just input validation basically. Input validation regarding what the user entered. And then down here, we know that both variables result and guess. So first we toss a coin. So there was no need to toss a coin up here. We only toss a coin when the computer, when the user entered something correctly, so it makes a good guess. And then here, we parametrized the entire logic. So we don't care if the correct result is heads or tails, we have only one message and we parametrize it using the result variable. Also for the case where the user gets something that is not correct, of course. So now we have no redundancy anymore. So there is no situation where we change one logic and we forget to change the other logic, which could easily happen in a situation like here when we make some changes above here, we may forget to make the same change in the lower alternative here. So in other words, my feeling is that this function also for beginner may be a lot easier to read here. So this is what good code looks like when you use some of the techniques we learned in this course so far, in particular how to modularize our code using functions. Modularizing means we are giving little pieces of the code its own name and we just call it by its name. And also what we learned in this video is the concept of an indefinite loop, loop for which we don't even have a condition of when it stops. And then we usually remodel that using a while true loop. So we call that an indefinite loop, but while true is also sometimes its name. Okay, so this is how we can further use the while statement. And yeah, so I will see you in the next video then.