All right, so I really hope you've given this challenge a good go,
and you've spent at least an hour toiling over it and struggling, and you should be wiping sweat off
your brows before you come and look at the solution.
The struggle is so important and I can't stress it enough, but in this lesson I want to run through
how I would tackle this problem.
Now, it doesn't mean that you have to do the same thing,
there isn't one solution.
There's probably thousands of different solutions for a project like this.
And as long as your program runs exactly the same way, then you've succeeded.
It doesn't matter at this stage how you've done it necessarily,
as long as you managed to organize your thoughts, break down the problem, and write the solution code
and get it to run, then you are victorious.
The real challenge in today's project was for you to break down a big problem into smaller, solvable
chunks.
It isn't even so much the code that matters,
it's this skill that you really need to develop to become a really good programmer.
And so far, I've been breaking down the problem for you, showing you the steps that would take you
to the solution,
but now you're really wearing the big programmer pants and you're doing it all by yourself.
So let's think about this problem and how we would break it down.
There's some easy problems here, right?
We need the art to display...
So let's add a comment for each problem we identify.
We've got the ASCII art showing up here, and we've got the Vs showing up here.
Now the next one is we've got these randomly generated accounts, from the data.
So we've got Camila Cabello and Emma Watson.
How do we get these random accounts to show up,
that's another problem.
Right?
So we know that we've got all of this game data here in the format of a dictionary that's nested inside
a list,
and we need to figure out a way of pulling out a random account from this list.
So that's another problem I've identified.
Now, the next thing you'll notice is that the data contains many key/value pairs, the name of the account,
the description, et cetera, but when we display it, it's all nicely formatted, the name, and then what they
do, and then where they're from.
We'll have to add that as probably another problem to solve.
How do we format the account data into a printable format?
Okay,
so let's say we solve that and we've got A and B.
Now we have to ask the user for a guess.
Guess who has more followers.
So that's another problem to solve.
And when they do type an answer, let's say we think maybe A has more followers, then it's going to
have to check that answer and see if it's correct or if it's wrong.
So that's going to be a big problem,
"Check if user is correct," because that's going to require a couple of things, right?
We're going to probably have to break down this problem into smaller problems if we want to solve it.
So for example, we probably need to figure out the follower count of each account,
and then we'll probably need to use an if statement to check if user is correct.
Now, if we get it right or if we get it wrong, the game is always going to give us some feedback.
"Sorry, that's wrong..." or "You're right!"
So let's add to our problem list.
Now, in addition to giving them feedback, whether if they got it right or whether if they got it wrong,
it also has a way of tracking score, right?
Every time they get an answer right, the score goes up by one.
In addition to all of that, the game repeats itself when the user gets it right.
So let's say in this case, I guess a Dwayne Johnson, then you see how the game repeats itself, right?
It goes back and it takes Dwayne Johnson, puts it in position A and generates a new account in position
B for me to go again.
So I get another round because I got it right.
So we'll need to address that in our code as well.
Have some sort of way of, "Make the game repeatable."
And it's not just repeatable actually, because we also have to move the previous B up to the A position
if they do get it right for the next round.
So I think Khloe Kardashian maybe has less,
oh. So let's say I guess Dwayne Johnson again in this case.
Now if I get it right, Taylor Swift, who used to be at position B, now gets moved to position A ready
for the next round.
So this is another problem we have to tackle. So not only does the game have to be repeatable, we also
have to have some sort of way of making the accounts at position B become the next account at position
A.
That's it, I think, for now.
I've broken down this large problem, which is build this game into a bunch of smaller problems,
and as we code along, we're probably going to break them down even further.
This really was the key skill that I wanted to test you on,
being able to take a big project, turn it into smaller problems, and then tackle them one by one.
So if you managed to get this far, and you've managed to identify all the problems that you need to solve,
you're ready to consider yourself successful.
Now the next stage, we're going to try and tackle each of these one by one and be able to create the
final version of the game.
Let's get started.
Now the first thing is probably the easiest, so I'm going to start from there to display the art,
which is going to be the logo to begin with.
I'm going to have to import that art file, and I'm going to use the, 'from art import logo',
this way I don't have to write art.logo every time I want to use it.
Now I can simply just write, print(logo).
So that's the first one tackled.
That was pretty easy.
Some of them are going to be a lot harder than that.
The next one is to generate a random account from the game_data.
And remember the game_data is here in a separate file,
and the data is held inside a variable called data.
So let's go to the top and let's do the same thing,
so, 'from game_data import data'.
And now we can use that data to generate a random account.
In order to generate a random item from that list we have to use the Random Module.
So I'm going to import the random module.
And I can use that random module to tap into the choice() function and pass in my data, which is a list.
So this function is going to take this list and then find a random entry in there, which will give
me a random account.
Let's call this account may be, account_a and set that equal to the output from this random.choice()
function.
Now I'm probably going to need more than one random account, because I need to compare A against B.
By calling random.choice() on data
again, I make sure that I get a different random account.
So at this point, we've got account_a and account_b, which hopefully are different from each other,
but if you wanted to, you could in fact check and just make sure.
So if account_a == account_b, then, in this case, you make sure that account_b is regenerated.
Often as you're coding along tackling the problems,
smaller problems arise and you start thinking about what could happen, and you start addressing that
with code as well.
So I think we're now done for this second problem, and we're ready to move on to the next one.
Let's format the account data so that we can print it out in this format.
So the account name, and then 'a', and then whatever it is that they do, and finally from and where they're
from.
So we know that the data of each of these accounts is basically a dictionary,
and we know that we access dictionaries using the key/value pair,
so we could, for example, access the account_name by tapping into the random account, let's say,
account_a,
and then we use that square bracket,
and then we put in the key in here, which let me just check, is the name.
So let's put that right here.
And this will go into that dictionary, and pull out the value under the key name, and save it to this
variable.
And we can do the same thing for the other two pieces of data we need.
And just make sure that you don't have any typos in your keys here,
because remember they need to match these precisely in order for it to not error out.
Now that we've got all of these pieces of data, we can now print the final version.
So we're probably going to use an f-string to insert all of these pieces of information.
And we'll probably start off with the account_name and then a comma,
we can write 'a' and then put in the account_descr.
And finally, put 'from' and the account_country.
That's pretty much it.
But notice how I've done this just for account_a,
and I actually have to do it for both account_a, and account_b.
So instead of repeating all of this code, it might be a lot easier if I actually pull this out into
a separate function.
So let's create that here.
Let's create a function that does this.
I'm going to turn this into a docstring to explain the function,
and I'm going to call the function format_data().
And it's going to take an input which is the account.
And now using this account we can make this more reusable by deleting the _a part of it.
And of course we need to indent everything over so that it's actually within this function.
And instead of printing the final outcome I'm going to return it as the output.
So now we can call that function down here,
and we can pass in each account in turn.
For example, we could say print, Compare A, which is going to be the first account.
So we're going to use our f-string to insert the data that we get back from our function call,
and I'm going to call it within the print statement.
You can of course take it out and create a separate variable,
but I think this should be clear enough to see what's going on.
So we're going to call format_data,
and we're going to pass in the account_a for this first line,
and then I'm going to do the same for B.
So in this case I'm going to pass in account_b,
and it's going to format the data and then print it out.
So as I always say it's a good idea to run your code frequently,
probably any time you solve a problem you should probably run it and see if it works the way you expect
it to.
So the first one, the logo gets printed.
The second one, we've managed to get some random accounts because every time I run it, the accounts
should be different.
And finally, we format the account into this format, with their name, their description, and their
country all written out from the print statement,
using this lovely format_data() function we've created.
We've already done really well, so let's keep going.
Now, at the moment it just says compare A, compare B, but instead it'd be much nicer if we can put
in that art the Vs ASCII art in between the A and B.
Now you could write the line again, 'from art import vs,' but instead, you could also just add a comma
here and write vs.
So now it's going to import both the logo and that Vs art.
And we're going to put it right here.
So we're going to use a print statement.
And instead of using a string inside double quotes we're just going to write the name of the variable
which is called vs.
And if we take a look at the final version you can see it also says, Compare A Against B,
so we'll change the second word to Against.
And now when we run the code, it should look pretty much identical to the starting point of our final
game.
Let's tackle the next problem.
We need to ask the user for a guess to see who has more followers.
Right?
So I'm actually just going to copy this string right here.
And I'm going to put that into an input.
"So who has more followers?
A or B: "
And this input is going to come back as a string,
and I'm going to save it inside a new variable called guess.
Now because it asks them for A or B, they might type A like this 'a',
or they might type A like this 'A'.
Ideally, we should make it so that it doesn't matter what they typed,
it'll still be valid as long as they typed an A. So we can turn this all into a lowercase format.
So if they typed it capital like this, it'll become lower if they typed it lowercase then it's already
lower and it will be fine as well.
So that way it's more consistent.
So now our final product actually looks pretty much exactly identical, but it doesn't really have much
gaming functionality yet.
To do that, we have to move on to the next problem and check if the user got it right.
In order to check if they got it right, the first thing we'll need is to know how many followers they
each have, right?
Each of the accounts A and B. Let's get an a_follower_count and that is going to be using the account_a
and then pulling out the data under the key, follower_count.
So I'm actually just going to copy it to make sure I definitely don't make a typo.
And I'm going to tap into account_a and then pass in that key, follower_count,
remember as a string because our key is a string,
so when we use it, it also has to be a string inside double quotes, and I'm going to do the same for
the b_follower_count from account_b.
Now I've tackled that mini step inside the problem.
The next step is to use an if statement to check if the user is correct.
Now again, I think this piece of functionality would be really nice if it was reusable.
So I'm actually going to pull out of this main, sort of flow of the game and define a separate
function at the top.
And this function is going to be called check_answer(),
and it's going to get, the guess, the a_followers, and the b_followers count,
and I'm going to add some docstrings.
So the docstrings are really important especially when your function returns something.
For example, in this case, it should actually say, """"Takes the account data and returns the printable format."""
That makes it so much clearer what this function actually does, what are its inputs and what are its
outputs. In our check_answer(), then it's going to take the user's guess and the follower counts of
A and B, and then returns if they got it right.
So how might we write this?
Because the logic is actually a little bit difficult.
We need to check which account has more followers, and then we need to check if the user actually got
it right.
So it's almost a two step process.
And I think in these cases, it's actually really worth sort of sketching it out.
You can use a pen and a piece of paper,
I'm just using Skitch right here, so I can show it to you more easily.
So let's just construct a simple sort of two by two matrix.
And at the top, we've got the...let's say the user guess is A, and an alternative is they guess B.
Now these are the user's guesses,
but then it's going to be compared against the actual reality or the answer, which is that A has more
followers than B, and the alternative is that B has more followers than A.
If the user guessed A and A indeed has more followers than B, then they got it right.
And similarly, if they guessed B and B did indeed have more followers than A, then they would have also
gotten it right.
But if it was the opposite case, as in they guessed A, but actually B had more followers than they
would be wrong.
And also if they guessed B and A has more followers, then they would be wrong as well.
Now using this table, we can now construct our if statement.
There is a very, very long version of it, and there is a much shorter version of it. So the very long
version would check for something like if the a_followers is greater than the b_followers, so
A has more followers than B, and the guess is equal to A.
Now you can go through this kind of way and create four of these if and elif, else statements, but it's
very easy to get lost in some of the logic.
And also it means you have to type a lot of this out instead of using the else as the alternative.
So I think a much easier way would be to first check if A has more followers than B, and in this case
you can then check,
well, if the guess is equal to 'a', well then that means they got it right,
so I should return True,
but if this was not right then I should return False.
An alternative and a much easier way of expressing this is to simply return guess == a, because
when this is evaluated, is guess == 'a', then it's going to return True,
but if guess is not 'a', if it's 'b', then it's going to return False.
So that's a little bit mind bending,
but if you actually go through it enough times, especially using a debugger to just see how it works,
then it should become pretty clear pretty quickly.
In my case, all I need to do to express my table of possibilities is to first check if A is greater
than B,
now else,
namely, if the opposite was true, B was greater than A, then I'm going to return, user_guess is equal
to "b".
So now basically the code says, if A has more followers and they guessed A, then return True.
If B has more followers and they guessed B, then return True, and if the opposite happens, then return
False.
Basically, it's going to return whether if the user got the answer right.
Now we can basically check that in here.
And we could create a new variable called is_correct and set that to equal the output of our check_answer()
function.
So we're going to call it and pass in all the necessary things, the guess, the followers from A and B.
So guess, and then the a_follower_count, and the b_follower_count.
Now once we know whether if they got it right or not, we can tackle the next step which is give user
some feedback on their guesses. So we can check well if is_correct,
well, in this case, we should probably print something like, "You're right!",
but if they didn't get it right, then we're going to print,
"Sorry.
That's wrong."
Now, in addition to giving them feedback, we should probably also keep track of the score, so we can
start off our game with a score of 0,
but as they play on, and if they get it correct, then the score should be incremented by one each time.
And in addition to printing out, "You're right," we should also give them some feedback on the current score.
And if "Sorry they got it wrong," then we should also give them the final score because at this point
the game is going to end and they should know how well they did.
So now let's go ahead and play our game and see if it works.
So compare Cardi B against Kourtney Kardashian.
I think it's probably going to be B and it tells me, "You're right."
If we get it right, we get the feedback,
"You're right!"
and the current score.
If we get it wrong, then we get the answer,
"Sorry.
That's wrong."
And the final score as
well. That's all working so far.
Now we have to figure out some sort of way of making the game repeatable.
And as you might remember, that's usually going to require some sort of while loop.
But it's important to think about which part of our game actually repeat themselves.
Right?
Because when we play the game, it looks like everything is kind of static,
but if we think about it, the score is set to 0,
probably can't be repeated, but the accounts probably do need to be generated and they do need to be
randomized again.
And then we need to ask the user again Compare A Against B, and then ask them for an input and then
check the answer.
So all the rest of this probably needs to be repeated.
So I would say everything from here probably should be within our while loop.
So what is our while loop going to check?
Well, maybe we could create a flag like game_should_continue, and start out as True,
and then while that's still True, then we'll repeat all of this code below.
Now, at which point should this become False?
Well, they get to keep going as long as they get the answer right, but the game ends as soon as they
get it wrong.
This is the point where we're going to change,
game_should_continue to False, so that once it prints,
"Sorry.
That's wrong,"
it's going to end the game.
Now let's try and run the game and see if we can get our loop to repeat itself.
I'm going to choose 'A', and you can see, "You're right! Current score 1."
And now it's telling me to Compare A which is a new random person Against B a new random person.
As long as I get it right, it will allow me to keep playing the game, but as soon as I get it wrong...
So I'm pretty sure that National Geographic sadly doesn't have as many followers as Kim Kardashian,
so I think this is going to get me to exit the game.
"Sorry,
that's wrong.
Your final score was 3," and as you can see, my game has now ended.
But notice how in the final version of the game, the count at position B actually becomes the one at
position A in the next round.
So the game kind of continues like this.
And then once I guess this, Kim Kardashian is now going to become the one at position A, and it keeps
on going as long as I got it right.
So we now need to code this functionality into our program.
At the very beginning, we generate a random account_a and a random account_b, but instead what we want
to happen is we want to make sure that the accounts at position B becomes the next account at position
A.
So once this game has run its course and we're looping back to the beginning again, the account_a should
become the previous version of account_b, but this obviously will give us an error because there is
no previous account_b.
So what we could do is we could actually take this out of the loop, and say account_b is equal to a random
choice() of data, and account_a, becomes that account_b, but then the actual account_b, is going to be
a new random account.
Let's play this through in our heads as a computer.
The first thing that happens when the game starts for the very first time is we generate a random account_b,
now that account becomes the account_a, and then account_b becomes a new random account.
Now when the game loops back, it's not going to touch these parts of the code.
It's going to start from here.
So now the account_a is going to be replaced by the previous account_b.
And this new account_b is going to be a new random account,
and this way when we run our code you can see that as long as I get the answer correct,
then the previous B becomes the new A, and B now becomes a new random account.
That's pretty much all of the functionality sorted, right?
But we've got a couple of things to tidy up.
One is we need to clear the screen in between the rounds of our game,
but when do we want that to happen?
Well, let's take a look at the final game.
When we type any sort of answer after we give our input,
that's when the screen is supposed to clear.
So that means in our code it's going to be right below where we give the input.
So here we can clear the screen.
And we're going to use that usual trick that we've been practicing, which is just the \n symbol
multiplied by 20 times in order to clear the screen.
Now the other thing you notice is that every time the screen clears, we get the logo reprinted.
So let's go ahead and do that as well.
Right after we clear the screen, let's print the logo once more.
And now if we rerun our code, we should hopefully have more or less the same functionality as our final
demo.
And it took quite a bit of code at the end, but as long as you broke it down into these smaller components,
each of the components and each of the problems are much, much easier to tackle.
I hope you enjoyed building this game and I'll see you on the next lesson.