How did he get on?
Hopefully, you managed to complete the project and you're just here to check through the solution.
Now, if you haven't given it a proper go and I mean at least an hour tackling this, then go back,
keep going,
it's only when you struggle that you actually get better.
You can watch me type code all day long, and it's not going to make you a better programmer.
So I know you're going to try really hard,
and I want you to try really, really extra hard and make sure that you can complete each of these projects
by yourself.
Now, when you're creating a new project from scratch, like we're doing right now, it can seem a little
bit intimidating staring at a blank screen.
So the first thing to do is to just divide up the project into individual components.
So while you're playing this game, you can see that there are different bits of it that we need to
complete, right?
The first one is printing all the starting parts of the game.
The next one is trying to figure out how to set this difficulty level, getting the user to type in
a word easy or hard, and then changing the number of attempts based on that.
We can already start thinking about maybe we need to make a function to set difficulty, and then we
need to let the user make a guess, right?
So they're going to guess a number.
So let's say I'm going to type in 50.
And then we have to somehow check that guess against the number that was originally selected, and then
check to see if it's too low or too high.
So now we have some additional parts of our program.
Right?
We need some sort of way of choosing a random number between 1 and 100.
So that's the first thing that's probably going to happen in our code.
We need to have a function to set difficulty.
We probably need some sort of functionality to let the user guess a number.
And we'll also want to check that number that they've guessed against the number that we originally
had to see if it's too high or too low.
So probably a function to check users' guess against actual answer.
Now notice how every single time I make a guess, my number of attempts go down.
So we also need to track that, right?
Track the number of turns and reduce by 1 if they get it wrong.
Now it's looping back again to this stage where we're making another guess.
So if 50 was too high, then maybe we'll guess 25.
We have to have some sort of way of repeating this part of the code, right?
We're going to repeat it as long as they have attempts left and they are wrong.
Now if, however, they get it right, so I think I have a good chance of getting it right,
so if 25 is still too high, let's try 12.
And there we go.
When I get the answer right, it tells me, "You got it!
The answer was 12."
So now we've got some of the basic parts of our code down in comments, and we can start thinking about
how to write it out.
Right?
Let's start by tackling the easiest one, which is choosing a random number between 1 and 100.
All we have to do for this one is just to import the Random Module, or even better yet, from the random
module, import the randint function.
Now inside our code we can simply just use randint.
We can say the answer is equal to a randint() that is between 1 and 100.
And of course, remember that randint() includes A and B, so both 1 and 100 can show up.
In addition to this, we probably have to give the user some of these messages.
So I'm just going to copy some of these messages.
So I'm going to print, "Welcome to the Guessing Game!"
And also I'm going to print that "I'm thinking of a number between 1 and 100," like that.
So now we've got an answer that they need to guess,
and we've got a little bit of starting text for them.
The next easiest thing in this is to figure out a way of letting the user guess a number.
So we know that we'll need an input to ask them to make a guess, and we can use that as the prompt.
And then we're going to have to save their guess and convert it to an integer.
So they're going to be typing a number here right.
And we'll call this guess.
Now the user is able to guess a number.
And we now have to figure out some sort of way of checking the user's guess against the actual answer.
This is probably a good time to create a function, so why don't we go up to the very top and create
our function here?
We'll call this check_answer(), and we're going to pass in the user's guess and the actual_answer() in
order to achieve this checking functionality.
So in this case we're going to check to see if the guess is greater than the answer,
well in this case it's too high, right?
So we'll just print, "Too high."
Now what if the guess was actually less than the answer?
Still not equal to the answer, but in this case it's too low.
So now the final condition is they actually got it right.
So you could write elif guess is equal to answer, but you could also just use else because there's
no other possibilities.
This else statement catches the moment when they actually get it right.
So in this case, we're going to print what we have here,
and then we're going to print out the answer.
So of course we're going to replace that with whatever the actual answer is and turn this into an
f-string.
So now that's that step done,
let's think about what else is easy that we can knock off the list.
Let's make a function to set the difficulty.
So up here, in addition to our check_answer() function, I'm going to create this other function, some
way of setting the difficulty.
So let's call this set_difficulty().
And it's probably not going to take any inputs,
it's just going to do some sort of action.
So when we first start off the game it already asks us to choose a difficulty.
So I'm going to copy this text and I'm going to put that into an input.
Choose a difficulty, easy or hard.
And then we're going to save this probably into a variable which I'll call level.
So the level of difficulty that they want.
Now if this level that they chose was equal to easy,
well, in this case, we want to set the number of attempts that they have to ten,
So they have 10 attempts.
But on the other hand, if they chose hard, then they only have 5 attempts.
So this is probably a really good time for creating a global constant.
So we really saw this in the previous lesson on scope,
but this is a really nice thing because it means if we create this global constant at the very top,
then if we want to switch around how our game works, we can really easily access these constants by
just scrolling to the top of the page.
Let's call the first one, EASY_LEVEL_TURNS.
So the number of turns you get on easy, which is going to be 10, and then we'll have HARD_LEVEL_TURNS,
and this is going to be equal to 5.
Now I've got these two constants which is global,
And I can use it inside any of my functions or basically anywhere on this page.
If the level is easy, I'm going to set the number of turns to equal the EASY_ LEVEL_TURNS.
So this is going to be a number, right?
Else,
so if they chose hard instead then turns should probably be the HARD_LEVEL_TURNS.
Now setting it here is no use,
I actually need it inside my game.
So now going back in my game, I need to let the user know how many number of attempts, how many turns
they actually get.
To start off, I'm going to use a print statement that just prints the number of attempts they have
remaining, and it's not always going to be 5,
sometimes it's going to be 5, sometimes it's going to be 10.
So what I'll need is some sort of way of tracking this number of turns.
Right?
But how do we know how many turns they get?
Well, it depends on what they chose here, right?
If they had chosen hard, then turns should be equal to the HARD_LEVEL_TURNS.
If they chose easy, it should be equal to the EASY_LEVEL_TURNS.
So instead of using this as some sort of global variable which I have to change inside here, which
would require me saying global and then turns so that I can access this particular variable and change
it inside these steps,
it would be much, much better if I just returned these values as an output from this function.
If this is set as return, then I can simply call this function set_difficulty(), which is going to trigger
this input.
And then once the user is set it, then the output is going to be the actual number of turns they have,
and I can now use it inside this print statement to show them how many turns they have.
Now, I've already written quite a bit of code actually, and it's probably a good time to run the code.
While I'm testing my code, it's probably a good idea to actually see what the answer is, so we can
add a bit of testing code that just prints out what the actual answer was selected as.
And if we run the code now, you can see we've got the starting part pretty much down.
Welcome to the number guessing game.
I'm thinking of a number between 1 and 100.
And then we've got our little hint here.
So we have to make a guess.
So let's say I guessed 50.
Now it's asking us to choose a difficulty.
So I've already got a little bit of a problem here.
I should actually have this, before the other part, so I should choose the difficulty and then make
a guess.
So now let's stop and run and see if we've fixed that bug.
And you can see,
yep, indeed.
It asks us for a difficulty first.
So I'm going to choose easy.
And it tells me that I've got 10 attempts remaining.
And then to make a guess.
And if I choose hard instead, then it tells me I've got 5 attempts.
Now, if while you're playtesting this game and you realize that actually 5 is not enough, then
all you have to do is scroll to the very top of the game, change this one global variable here, and
all your changes you know will be reflected in the code below.
Now let's get back to our game.
Let's say I make a guess and our code ends, right?
Even though I've got my check_answer(), it's not actually being called anywhere.
So let's go ahead and call that function, check_answer(),
and then we can pass in the user's guess that they made at this step,
and we can also pass in the correct answer which comes from here.
So let's run our code again.
So I'm going to choose the easy mode
and I'm going to make a guess.
Now 50 is too high because I can actually see the answer.
So that works,
but I can't guess
again, it's not letting me.
It's actually ended the program.
So we probably have to tackle this particular TODO if we actually want to get the right functionality.
How do we get the guessing functionality to repeat if they get it wrong?
So that, as you might have guessed, is probably going to require some sort of while loop.
While they've gotten it wrong, we probably should go and let them make a guess again.
These parts will definitely need to be repeated.
So let's create a while loop.
What are we going to check in our while loop to make sure that it keeps on going?
Well, the thing that we're trying to aim for is to get the user to guess the actual answer.
If we set the while condition as while guess is not equal to answer, then that pretty much guarantees
that these lines of code will keep going until the user actually gets the right answer.
Now however, when we do this, we get an error.
Well, because guess hasn't been declared yet, so why don't we declare it outside of the while loop
and simply just create it as a variable?
So we'll set that to equal 0
Now at the moment this is a global variable.
This is a global variable.
So it's probably a good idea to put our game functionality inside its own function.
So we can create a new function here which I'll call game(),
and now we'll need to call and trigger this game() inside the global scope if we actually want this to
be carried out.
So now that we've done all of this hard work, let's run our code and let's try it out.
Let's go for easy.
And I'm going to start off by guessing 50
as always, 50 is too low, so I'm going to go for the next number.
Let's try a number that's a bit too high 95, Too high.
Now what if I actually get it right?
Well it tells me you got it.
So the only thing that we're not really doing is tracking the number of turns so that we tell them you
have 10 attempts, you have 9 attempts, you have 0 attempts.
And if they get 0, then they're going to lose,
right? Here we have this print statement that runs only once because it's not inside the while loop.
So let's tackle our final TODO to track the number of turns and reduce it by 1 if they get it wrong.
Now where do we know that the user got it wrong?
Well, inside the check_answer() function, if it's too high, if it's too low, then we have to deduct
the number of turns they have.
But if they got it then we don't.
One way of tackling this is again creating a global variable called turns,
set it to start off at 0,
and then inside this function, we simply just say, turns - = 1, and also turns - = 1,
when it's too low or too high.
Now because this is a global variable, we again would need to say global turns in order to use it inside
our function.
But as I mentioned, this is not a good idea because it means that you're modifying the global function
within a local scope.
How can we achieve the same functionality without having to use a global variable?
Well, we could instead, just pass in the number of turns that we currently have,
and then inside our function, we can return the number of turns- 1.
And we can do the same down here.
So now when we call this function check_answer(), we can pass in the current number of turns, which remember
got set by the set_difficulty() function,
and we can pass that in into here. Because it's not immediately obvious that this function actually
has an output,
it's probably a good idea to add a docstring to this function.
Remember the three quotes?
And then in between we're going to say, """Checks answer against guess, returns the number of turns remaining."""
Now when we actually call check_answer(), you can see that this is what actually happens and that we
have a return that we can be aware of. If this is going to be the number of turns remaining, then we
can save that to this variable turns so that we update this local variable every time we check the answer.
Now this part is a little bit mind blowing.
So you might actually want to put this through Python Tutor and step through it, step by step, to see
what's actually going on and how this turns variable is being updated by the output from this function.
If you're totally happy with what's going on, then feel free to keep going.
So now let's check out our code.
Now what if I actually ran my number of turns down to 0?
So let's try hard because this is only going to give us 5 attempts.
So let's say I guessed 50 and then 70, and then I'm just going to put in some random numbers so that
I end up with no remaining guesses.
You can see it's actually not stopping me, right?
And also for some reason, we have a bug where the number of attempts we have remaining is not actually
being printed.
So let's address that issue.
Well, if we want it to happen every time and repeat, it's going to need to go into the while loop.
So instead of printing our number of turns here, why don't we print it here inside the while loop instead?
So let's make sure the indentation is correct.
And now let's try it again.
So I have 5 attempts remaining,
let's make a guess.
I have 4 attempts remaining. And notice how it's counting it down,
3,
2,
1.
This should be my last guess, but notice how it actually keeps on going,
It doesn't stop the game.
I can keep going and it's going into negatives now.
So how can we fix this?
We need some sort of way of tracking when this number of turns goes down to 0,
and when that happens, we have to stop the game and tell them that they've lost.
Why don't we create an if statement, check if the number of turns is equal to 0, and print something.
Let's check the actual final version.
Let's see what happens in this case.
When I run out of goes, I make a guess,
it's too low, and it tells me, "You've run out of guesses.
You lose."
We can print that here as well,
but notice how if we run the code as it is,
so let's just keep guessing the same number until I run it down to 1.
So now I make a guess,
it tells me, "You've run out of guesses, you lose," but it's still letting me keep going even though I've
lost.
How can we make our game end? Well, luckily we've got our game inside a function which is being called
at the very beginning.
Now remember that with functions you have the return keyword you can return with an output, or you
can just write return for it to exit and end the function.
So now with that return keyword in place once I run out of turns, see what happens.
It stops and it doesn't
let me guess anymore.
Perfect.
We've managed to get that right.
The final thing that we're still missing is this prompt for the user to guess again.
Now, this is kind of optional.
It depends on your own feel for the user experience.
I think it makes sense to say, "It's too low.
Guess again," because it's kind of telling them to do something.
Although this, 'Make a guess' also prompts them to make a guess so you can have it,
you don't have to.
If you wanted to have that, then you probably actually have to check that they still have turns remaining,
and if they do, then make sure that the guess is not equal to the answer so they haven't got it right
within this turn.
And then to print that guess again.
So now every time they get it wrong, but they still have remaining guesses,
it should say, 'Too low. Guess again,' or 'Too high. Guess again.
But if they actually get it right then it says you got it without asking them to guess again.
Now we've pretty much completed this code.
Of course, you could have added additional art, so you could have created an art.py, and then
used the text to ASCII generator to create an ASCII art.
And then back in here we could have imported it,
and we could put that at the very beginning of the game.
But the rest of the customization is basically your own, right?
You're free to do whatever it is that you want to and to change the wording, to change the text.
The really important part was that you were able to play this game, understand how it worked, and
then break down the problem into smaller pieces that you could tackle one by one.
And if you had trouble actually completing this program by yourself, then you should have noticed when
we were walking through it, when I just broke down that big problem into smaller chunks, how much
easier it became tackling each of the smaller things, right?
Choosing a random number between 1 and 100.
You can definitely do parts of this.
And as you built up the game towards the end, you realized, uh, this was missing or that might be
nice, then you could start adding more and more bits to it.
But hopefully you've actually managed to build out your own version, and it's even better than what
I've done.
And if you're particularly proud of it, be sure to share it so that the rest of us can take a look
and have a play with it as well.
So I hope you enjoyed the project today and I'll see you tomorrow.