All right.
So in the last lesson we did a lot of setup and we got our game to have the
basic features.
It's got a popup that asks us for a states' name,
and when I type a name in here, I can receive it inside my code
using this answer_state.
Now your job is to use that 50_states.csv
to
check the user's answer against all of the states inside this table and see if
it matches one of them. Now,
the user might spell it with a capital to begin with say, Ohio,
or they might just write ohio and it should work for both of these cases.
In addition,
when the user types in a state that is inside that 50_states.csv,
then that state should be written onto the screen at the location where it
exists.
So it remember the location corresponds to the X and Y values that we already
logged inside this data file.
But if the user guesses a state that's wrong,
then nothing happens and our input box appears again
asking for a new input.
Now notice how here in the title of the text input
I'm also keeping track of how many states they have guessed correctly out of 50.
And every time they add a new, um,
new state, then that number updates.
his is going to rely on the knowledge that you've learned about reading from
CSV data,
getting hold of the specific parts of the CSV data,
finding for example, a particular row or a particular column,
and working with that data in order to check to see if the user got the state
right,
and then using the data inside that row to figure out where to write some text
at which X and Y location
so that we can get the actual name of the state written at the location where
they appear on the map. So this is quite a challenge
and I expect that you'll have to think about it and play around with the code
for at least 10 to 20 minutes. So give it the time that it needs,
have a think about how you would break down this problem and try and complete
this challenge. So pause the video now.
Okay.
All right. So I'm going to walk through the solution with you,
but I want you to do a conscience check.
If you haven't spent at least 20 minutes working on this problem, fixing it,
getting it to do what you want it to do, then go back, try again.
You need to feel the struggle in order to learn.
I can tell you how to do anything, but if that answer didn't come from you,
then you're not actually going to make progress. So I really,
really urge you to give it a go before you watch the solution. All right.
So back to our code, the first thing I'm going to do is
I'm going to import the pandas module.
So I'm going to import pandas.
Now I've already installed pandas on the starting project that you downloaded,
but if you're doing this completely from scratch from your own starting file,
then you'll probably get a red squiggly line under the pandas
and it will ask you to install the package. But if you don't have it,
then it means it's already installed and ready to use.
Now we're going to get our pandas to go ahead and read our CSV file, and the
CSV file is called the 50_states.csv.
So once the prompt comes up,
then I'm going to hit enter to get PyCharm to just insert it automatically.
Now I'm going to save that data frame that comes from reading that CSV to a
variable called data.
Now our data has 50 rows of data and the first row is the column headings
for each of them. So we've got the state, the X and the Y values.
Let's have a think about how we might break down this problem that we have.
So when the user types an answer,
we have to check to see if that, um,
answer_state is one of the states in all the states of the 50_states.csv.
The first column is a list of all 50 States.
So if we could somehow check to see if this state that they've guessed is one of
the states in that column, then we know whether if they got it right or wrong.
If they got it right,
then we need to figure out how we can create a turtle to write
the name of the state at the state's X and Y coordinate.
For example, if the user guessed
South Carolina and indeed South Carolina is one of the 50 States,
then we should be able to pull out this entire row and then create a turtle,
make it go to this X and Y location,
and to write the name of the state onto this blank state image in our turtle
game. Let's see if we can tackle this. Now,
the first thing we need to figure out is how do we get hold of all the states of
the 50_states.csv? So we've got our data frame
and if I go ahead and say data, then I can pull out one of the columns.
So the column name is state,
and I can either use that as a key with a set of square brackets,
or I can use it as simply a attribute name.
This gets me the data series which is that first column.
And if I want to be able to turn that into a list,
remember that we saw that method to_list,
and that means we can work with it just like any other list.
So let's call this all_states.
And once we've got whole of this all_states, well,
we can check to see if the answer_state is in the all_states.
This is something that you won't be able to do,
so checking for membership using the in keyword
unless you have converted this into a list.
So once we've figured out that this answer of the user provided is in fact,
one of the states in our 50 States,
then the next thing we need to do is to create a turtle.
So let's create a new turtle, which we'll call t,
and we're going to use the turtle.Turtle class to construct it.
And then we're going to get the turtle to hide the actual turtle shape,
and we're also going to get it to pen up so that it doesn't actually do any
drawing.
But what we do need it to do is we needed to go to a particular X and Y
location.
The X and Y location is going to correspond to the state that the user has
correctly guessed and the row of data from our 50_states.csv.
So how can we get hold of the actual row of data that corresponds to this state?
Well, we can take our data and then inside some square brackets,
we can check that the data.state is double equal to the answer_state.
This is going to pull out the row where the state is equal to the answer_state.
So I'm going to save that under something called state_data.
And now I can tell my turtle to go to state_data.x and state_data.y.
So, because this is a row of data,
then I can tap into it's attributes using the name of the columns,
the X and the Y.
And once my turtle gets there,
then I want it to write the name of the state.
So it's going to be state_data.state. Now,
when we hit run on this code and guess the name of a state that definitely
exists, when we click OK, we're going to get an error.
And it's really important that you get used to seeing errors
because they're going to happen to you all the time. Just as in life
the only certainties are death and taxes, in Programming the only certainty
is you will get bugs and you will get errors.
The important thing is to figure out what's causing the error.
So if we go ahead and copy this error at the end, bad screen distance,
that seems to be telling us what is actually going on.
And then I go into Google and I search for this particular error,
then I can see other people who've encountered this issue.
So if we read through all of this, between all of the subtext,
it tells us that the issue is actually that our coordinates are stored as
strings. We need to get the coordinates into actual numbers.
So the one oversight that you might've made which is really common
is to simply tell it to go to date state_data.x,
state_data.y without first converting them into integers.
So now if we bring back our screen.exitonclick and then run our code,
we can type the name of the state click OK,
and you can see the state data show up on the location that corresponds to that
particular state. Now,
the only problem is we don't want all of this junk to be written here, right?
And this is showing up because we're getting this data from our data series.
So what's a much simpler way? Well,
we've already got hold of the answer that the user typed, right?
So why don't we just write the answer_state?
So now when I type in the state and it matches one of the states in the 50
states,
then it's going to go to the X and Y location of that state and print the name
of the state that the user has typed in.
And because we've made sure that it's a correct state with a correct spelling,
then it doesn't actually matter if we use the answer_state
or if we use the state_data. Now,
if you really want to use state_data instead of answer_state
because say you're writing a different program and you need this functionality,
then you can actually tap into state_data.state,
which will get us the state name from the row corresponding to the matching
state. And then we can use a method called item.
Now, item is a method on the pandas series.
So we know that this is a Panda data series
and you can do a type check on that if you want to confirm.
But what the item does is it looks into the underlying data and it basically
just grabs the first element. So now, if I run the game
as it is and I type in the name of a state,
you can see it fetches the actual value under state_data.state without any
of the index, the zero or any of the other parts of the data series.
So I just wanted to show you that you can actually get a row of data from a data
frame and then get a particular value from that row,
and get the actual raw value from that. But personally, in this line of code,
I prefer using the answer_state because we know it's already been title cased, its
already formatted correctly
and it just makes the code look a bit cleaner and it's easier to understand.
So I'm going to stick with this. So now that it's working,
all we need to do is to get this
to repeat itself every single time the user makes a new guess.
That means we're probably going to have to put it inside some sort of while loop,
what should be our while condition? Well,
we know that the user is going to guess all of the states. And once they've
guessed all of them, then they win, right?
So why don't we create a list of guessed states and set that to equal a empty
list.
And we can check while the length of the guessed_states is less than 50,
then we can continue rerunning all of this code,
getting them to put a new input, checking the input and writing the state name.
But every time the user guesses a state correctly,
then we're going to add this answer_states to the guessed_state.
So we can say guessed_states.append,
and then we're going to append this new answer_state.
So now when I run this code again, then you can see that every time
I guess a new state, this text input pops up again
and I can basically just keep going until I've named all the states.
Now, the next thing I want to change is the title of this text input window.
Instead of saying Guess the state,
I want it to keep track of the number of states I've guessed correctly.
So I basically want to say something like zero or 10 or whatever, out of 50
states correct.
This zero is going to be replaced by a f-string
and we're going to use the length of our guessed_states in order to get that
number. So now when I run this code, you can see that
I start out with zero states, 0/50, and every time I guess
a new state, then it adds to that count
so I can keep track of how many I have guessed and how many I've got left.
Now,
the next thing you'll realize if you test this a few times is even if you get a
state right
but if you actually didn't spell it with a capital C or capital letter to begin
with, then it's not going to accept it. So we don't see 'california' showing up.
And this is because in our state data,
they all have a title case were the first letter is capitalized.
So how can we make sure that our game works
if the user types all lower case or all upper case or title case?
As long as they got the spelling right we should ignore the casing.
So one way of doing this is to take this answer_state
which comes from that text input that the user has entered,
and then at the very end, we can change that to a title case.
So this is a method that's on all strings.
So that means if I start out with a string, which is,
um, angela, and then I say str.title,
then this will give me the same string back
but it will make the first letter capitalized.
This is what we're going to do to the user's answer.
And then we'll be able to check it against all the States.
And now it doesn't matter if the user has typed everything in all caps,
or if they have typed it with all lower case,
or if they've done something really crazy like this,
it will still be accepted.
So we've now got most of
the functionality of our game. In the next lesson,
we're going to figure out how we can get this game to become more of an
educational tool and for it to create a final CSV
when we're ready to exit the game
that's going to tell us all the states that we missed so that we can learn them,
so that we can come back to the game with more knowledge. For all of that and
more, I'll see you on the next lesson.