WEBVTT

0
00:00.000 --> 00:01.960
All right. So in the last lesson,

1
00:01.980 --> 00:06.760
we did a lot of setup and we got our game to have the basic features.

2
00:06.840 --> 00:11.840
It's got a pop-up that asks us for a state's name and when I type a name in

3
00:12.980 --> 00:17.280
here, I can receive it inside my code using this answer state.

4
00:17.959 --> 00:22.959
Now your job is to use that 50_states.csv to check the user's answer against all

5
00:23.959 --> 00:28.959
of the states inside this table and see if it matches one of them.

6
00:31.440 --> 00:36.160
Now the user might spell it with a capital to begin with, say "Ohio",

7
00:36.240 --> 00:40.680
or they might just write "ohio" and it should work for both of these cases.

8
00:41.720 --> 00:46.720
In addition, when the user types in a state that is inside that 50_states.csv,

9
00:46.720 --> 00:51.720
then that state should be written onto the screen at the location where it

10
00:53.779 --> 00:54.619
exists.

11
00:54.720 --> 00:59.119
So remember the location corresponds to the X and Y values that we've already

12
00:59.139 --> 01:01.639
logged inside this data file.

13
01:02.279 --> 01:05.360
But if the user guesses a state that's wrong,

14
01:05.919 --> 01:10.919
then nothing happens and our input box appears again asking for a new input.

15
01:11.599 --> 01:14.639
Now notice how here in the title of the text input,

16
01:14.720 --> 01:19.720
I'm also keeping track of how many states they have guessed correctly out of 50

17
01:20.440 --> 01:25.440
and every time they add a new state then that number updates.

18
01:27.680 --> 01:32.680
This is going to rely on the knowledge that you've learned about reading from

19
01:32.680 --> 01:37.680
CSV data, getting hold of the specific parts of the CSV data,

20
01:37.720 --> 01:42.720
finding for example a particular row or a particular column and working with that

21
01:42.800 --> 01:47.800
data in order to check to see if the user got the state right and then using the

22
01:47.800 --> 01:52.800
data inside that row to figure out where to write some text at which X and Y

23
01:52.800 --> 01:57.800
location so that we can get the actual name of the state written at the location

24
01:57.800 --> 01:59.239
where they appear on the map.

25
01:59.239 --> 02:04.239
So this is quite a challenge and I expect that you'll have to think about

26
02:04.239 --> 02:09.240
it and play around with the code for at least 10 to 20 minutes.

27
02:09.240 --> 02:14.240
So give it the time that it needs and have a think about how you would break down

28
02:14.240 --> 02:18.559
this problem and try and complete this challenge.

29
02:18.759 --> 02:20.160
So pause the video now.

30
02:26.160 --> 02:28.600
All right, so I'm going to walk through the solution with you,

31
02:28.839 --> 02:31.039
but I want you to do a conscience check.

32
02:31.600 --> 02:35.880
If you haven't spent at least 20 minutes working on this problem, fixing it,

33
02:36.039 --> 02:40.320
getting it to do what you want it to do, then go back, try again.

34
02:40.440 --> 02:42.800
You need to feel the struggle in order to learn.

35
02:43.160 --> 02:47.080
I can tell you how to do anything, but if that answer didn't come from you,

36
02:47.320 --> 02:49.520
then you're not actually going to make progress.

37
02:49.919 --> 02:50.800
So I really,

38
02:50.800 --> 02:53.759
really urge you to give it a go before you watch the solution.

39
02:55.160 --> 02:57.240
All right, so back to our code.

40
02:57.720 --> 03:02.240
The first thing I'm going to do is I'm going to import the pandas module.

41
03:02.679 --> 03:04.399
So I'm going to import pandas.

42
03:04.880 --> 03:09.720
Now I've already installed pandas on the starting project that you downloaded,

43
03:10.039 --> 03:14.119
but if you're doing this completely from scratch, from your own starting file,

44
03:14.320 --> 03:18.800
then you'll probably get a red squiggly line under this pandas and it'll ask you

45
03:18.800 --> 03:21.600
to install the package. But if you don't have it,

46
03:21.600 --> 03:24.119
then it means it's already installed and ready to use.

47
03:24.600 --> 03:29.520
Now we're going to get our pandas to go ahead and read our CSV file.

48
03:29.919 --> 03:33.919
And the CSV file is called 50_states.csv.

49
03:34.360 --> 03:36.320
So once the prompt comes up,

50
03:36.600 --> 03:40.520
then I'm going to hit enter to get PyCharm to just insert it automatically.

51
03:41.360 --> 03:45.520
Now I'm going to save that data frame that comes from that reading that CSV to a

52
03:45.520 --> 03:47.080
variable called data.

53
03:47.839 --> 03:52.839
Now our data has 50 rows of data and the first row is the column heading for each of them.

54
03:54.119 --> 03:59.199
So we've got the state, the X and the Y values.

55
04:00.279 --> 04:04.399
Let's have a think about how we might break down this problem that we have.

56
04:04.839 --> 04:07.000
So when the user types an answer,

57
04:07.440 --> 04:11.919
we have to check to see if that answer_state

58
04:13.320 --> 04:18.320
is one of the states in all the states of the 50_states.csv.

59
04:19.160 --> 04:24.160
The first column is a list of all 50 states.

60
04:24.160 --> 04:29.160
So if we could somehow check to see if this state that they've guessed is one of

61
04:29.160 --> 04:32.760
the states in that column,

62
04:33.079 --> 04:36.000
then we'd know whether if they got it right or wrong.

63
04:36.359 --> 04:38.959
If they got it right,

64
04:39.480 --> 04:44.480
then we need to figure out how we can create a turtle to write a list of all 50

65
04:44.480 --> 04:47.600
states. So we need to create a turtle to write

66
04:50.000 --> 04:55.000
the name of the state at the state's X and Y coordinate.

67
04:57.920 --> 04:58.760
For example,

68
04:58.839 --> 05:03.640
if the user guessed South Carolina and indeed South Carolina is one of the 50

69
05:03.640 --> 05:04.480
states,

70
05:04.480 --> 05:08.359
then we should be able to pull out this entire row and then create a turtle,

71
05:08.399 --> 05:13.399
make it go to this X and Y location and to write the name of the state.

72
05:15.279 --> 05:19.000
onto this blank state image in our turtle game.

73
05:20.559 --> 05:22.119
Let's see if we can tackle this.

74
05:22.320 --> 05:26.079
Now the first thing we need to figure out is how do we get hold of all the

75
05:26.079 --> 05:28.200
states of the 50_states.csv?

76
05:28.600 --> 05:32.600
So we've got our data frame and if I go ahead and say data,

77
05:32.839 --> 05:34.880
then I can pull out one of the columns.

78
05:35.279 --> 05:40.279
So the column name is state and I can either use that as a key with a set of

79
05:41.079 --> 05:45.119
square brackets or I can use it as simply a attribute name.

80
05:46.440 --> 05:51.200
This gets me the data series, which is that first column.

81
05:52.119 --> 05:54.799
And if I want to be able to turn that into a list,

82
05:55.079 --> 06:00.079
remember that we saw that method to_list() and that means we can work with it just

83
06:00.720 --> 06:04.640
like any other list. So let's call this all_states.

84
06:06.079 --> 06:08.519
And once we've got hold of this all_states,

85
06:08.559 --> 06:13.559
well we can check to see if the answer_state is in the all_states.

86
06:17.160 --> 06:19.600
This is something that you won't be able to do.

87
06:19.600 --> 06:24.600
So checking for membership using the "in" keyword unless you have converted this

88
06:25.119 --> 06:26.359
into a list.

89
06:27.279 --> 06:32.279
So once we figured out that this answer the user provided is in fact one of the

90
06:32.880 --> 06:35.200
states in our 50 states,

91
06:35.519 --> 06:39.160
then the next thing we need to do is to create a turtle.

92
06:39.760 --> 06:41.200
So let's create a new turtle,

93
06:41.200 --> 06:46.200
which we'll call "t" and we're going to use the turtle.Turtle class to construct

94
06:47.239 --> 06:47.880
it.

95
06:47.880 --> 06:52.600
And then we're going to get the turtle to hide the actual turtle shape and we're

96
06:52.600 --> 06:57.480
also going to get it to penup() so that it doesn't actually do any drawing.

97
06:58.119 --> 07:03.119
But what we do need it to do is we need it to go to a particular X and Y

98
07:03.519 --> 07:04.359
location.

99
07:04.839 --> 07:09.839
The X and Y location is going to correspond to the state that the user has

100
07:10.000 --> 07:15.000
correctly guessed and the row of data from our 50_states.csv.

101
07:17.519 --> 07:22.519
So how can we get hold of the actual row of data that corresponds to this state?

102
07:24.320 --> 07:24.640
Well,

103
07:24.640 --> 07:29.640
we can take our data and then inside some square brackets we can check that the

104
07:30.359 --> 07:35.359
data.state is double equal to the answer state.

105
07:37.160 --> 07:42.160
This is going to pull out the row where the state is equal to the answer_state.

106
07:44.880 --> 07:49.880
So I'm going to save that under something called state_data and now I can tell my

107
07:52.160 --> 07:57.160
turtle to go to state_data.x and state_data.y.

108
07:57.160 --> 08:01.679
So because this is a row of data,

109
08:02.279 --> 08:06.640
then I can tap into its attributes using the names of the columns,

110
08:07.040 --> 08:08.839
the X and the Y.

111
08:10.359 --> 08:12.559
And once my turtle gets there,

112
08:12.640 --> 08:16.880
then I want it to write the name of the state.

113
08:17.320 --> 08:21.000
So it's going to be state_data.state.

114
08:22.040 --> 08:27.040
Now when we hit run on this code and guess the name of a state that definitely

115
08:27.279 --> 08:29.359
exists, when we click OK,

116
08:29.399 --> 08:33.280
we're going to get an error and it's really important that you get used to

117
08:33.280 --> 08:36.400
seeing errors because they're going to happen to you all the time.

118
08:36.400 --> 08:37.400
Just as in life,

119
08:37.640 --> 08:41.200
the only certainties are death and taxes. In programming,

120
08:41.200 --> 08:44.159
the only certainty is you will get bugs and you will get errors.

121
08:44.520 --> 08:48.080
The important thing is to figure out what's causing the error.

122
08:48.559 --> 08:51.799
So if we go ahead and copy this error at the end,

123
08:51.840 --> 08:55.679
bad screen distance, that seems to be telling us what is actually going on.

124
08:56.400 --> 09:00.679
And then I go into Google and I search for this particular error.

125
09:01.159 --> 09:04.960
Then I can see other people who've encountered this issue.

126
09:06.280 --> 09:07.919
So if we read through all this,

127
09:07.960 --> 09:12.640
we realize that the issue boils down to a mismatch in data types.

128
09:13.119 --> 09:18.119
It looks like Victor was providing TKInter with strings when he should have

129
09:18.159 --> 09:20.000
provided an integer value.

130
09:20.520 --> 09:23.640
Something similar is probably happening in our code as well.

131
09:24.080 --> 09:26.679
Let's check what we're providing. Well,

132
09:26.880 --> 09:31.880
I typed in "Ohio" and I can see from the error message that my state_data.x

133
09:33.719 --> 09:37.599
had the value "34          175

134
09:38.239 --> 09:40.760
This doesn't look like a number.

135
09:41.039 --> 09:43.400
It looks like a mismatch in data types,

136
09:43.799 --> 09:47.320
but what is "34            175?

137
09:48.000 --> 09:52.000
We wanted to give TKInter a simple integer. However,

138
09:52.239 --> 09:56.760
state_data.x is actually a Panda series from our data frame.

139
09:57.159 --> 10:00.960
You can think of a Panda series as a column from our database.

140
10:01.440 --> 10:05.320
It may look like we've selected the X value of a single state,

141
10:05.599 --> 10:10.000
but we've actually selected a column in our data frame called X.

142
10:10.440 --> 10:15.440
This Panda series contains both an index value, Ohio is at index 34,

143
10:16.239 --> 10:20.320
and the coordinate that we're interested in, which is 175.

144
10:20.960 --> 10:25.960
Let's extract the integer value of the coordinate with state_data.x.item().

145
10:28.039 --> 10:32.679
That way we're accessing the single item contained in our Panda series.

146
10:33.599 --> 10:38.599
So now if we bring back our screen.exitonclick() and then run our code,

147
10:39.359 --> 10:43.000
we can type the name of the state, click OK,

148
10:43.280 --> 10:48.280
and you can see the state data show up on the location that corresponds to that

149
10:48.359 --> 10:49.400
particular state.

150
10:50.000 --> 10:53.880
Now the only problem is we don't want all of this junk to be written here,

151
10:53.880 --> 10:54.559
right?

152
10:54.559 --> 10:59.520
And this is showing up because we're getting this data from our data series.

153
10:59.880 --> 11:02.400
So what's a much simpler way? Well,

154
11:02.440 --> 11:05.919
we've already got hold of the answer that the user typed, right?

155
11:06.239 --> 11:09.960
So why don't we just write the answer_state?

156
11:11.080 --> 11:15.960
So now when I type in the state and it matches one of the states in the 50

157
11:16.000 --> 11:16.799
states,

158
11:16.799 --> 11:21.799
then it's going to go to the X and Y location of that state and print the name

159
11:21.919 --> 11:24.520
of the state that the user has typed in.

160
11:25.039 --> 11:29.679
And because we've made sure that it's a correct state with a correct spelling,

161
11:29.960 --> 11:33.840
then it doesn't actually matter if we use the answer_state or if we use the

162
11:33.840 --> 11:34.679
state_data.

163
11:35.960 --> 11:40.359
Now if you really want to use state_data instead of answer_state,

164
11:40.400 --> 11:44.359
because say you're writing a different program and you need this functionality,

165
11:44.719 --> 11:49.400
then you can actually tap into state_data.state,

166
11:49.960 --> 11:54.919
which will get us the state name from the row corresponding to the matching

167
11:54.919 --> 11:59.799
state. And then we can use a method called item().

168
12:00.679 --> 12:04.039
Now item() is a method on the Panda series.

169
12:04.840 --> 12:09.840
So we know that this is a Panda data series and you can do a type check on that

170
12:10.359 --> 12:11.400
if you want to confirm.

171
12:11.799 --> 12:16.799
But what the item() does is it looks into the underlying data and it basically

172
12:16.960 --> 12:18.719
just grabs the first element.

173
12:19.520 --> 12:24.520
So now if I run the game as it is and I type in the name of a state,

174
12:24.760 --> 12:29.760
you can see it fetches the actual value under state_data.state without any

175
12:30.760 --> 12:34.719
of the index, the zero or any of the other parts of the data series.

176
12:35.359 --> 12:40.039
So I just wanted to show you that you can actually get a row of data from a

177
12:40.080 --> 12:45.080
data frame and then get a particular value from that row and get the actual raw

178
12:45.919 --> 12:49.520
value from that. But personally in this line of code,

179
12:49.559 --> 12:53.919
I prefer using the answer_state because we know it's already been title cased,

180
12:54.200 --> 12:58.400
it's already formatted correctly and it just makes the code look a bit cleaner

181
12:58.440 --> 13:01.520
and it's easier to understand. So I'm going to stick with this.

182
13:02.239 --> 13:03.880
So now that it's working,

183
13:04.080 --> 13:08.760
all we need to do is to get this to repeat itself every single time the user

184
13:08.760 --> 13:10.280
makes a new guess.

185
13:10.679 --> 13:14.239
That means we're probably going to have to put it inside some sort of while

186
13:14.239 --> 13:18.039
loop. What should be our while condition? Well,

187
13:18.080 --> 13:22.320
we know that the user is going to guess all of the states and once they've

188
13:22.320 --> 13:24.919
guessed all of them, then they win, right?

189
13:25.280 --> 13:30.280
So why don't we create a list of guessed states and set that to equal a empty

190
13:31.919 --> 13:36.919
list and we can check while the length of the guessed_states is less than the

191
13:38.760 --> 13:43.520
50, then we can continue rerunning all of this code,

192
13:43.760 --> 13:48.280
getting them to put a new input, checking the input and writing the state name.

193
13:49.119 --> 13:52.520
But every time the user guesses a state correctly,

194
13:52.880 --> 13:57.880
then we're going to add this answer_state to the guessed state.

195
13:58.280 --> 14:03.119
So we can say guessed_states.append and then we're going to append this new

196
14:03.159 --> 14:07.280
answer_state. So now when I run this code again,

197
14:07.760 --> 14:11.320
then you can see that every time I guess a new state,

198
14:11.640 --> 14:16.640
this text input pops up again and I can basically just keep going until I've

199
14:17.719 --> 14:19.039
named all the states.

200
14:19.799 --> 14:24.400
Now the next thing I want to change is the title of this text input window.

201
14:24.960 --> 14:26.520
Instead of saying guess the state,

202
14:26.679 --> 14:31.039
I want it to keep track of the number of states I've guessed correctly.

203
14:31.400 --> 14:36.400
So I basically want to say something like 0 or 10 or whatever out of 50 states

204
14:37.320 --> 14:38.159
correct.

205
14:38.599 --> 14:43.599
This 0 is going to be replaced by a F string and we're going to use the length

206
14:44.559 --> 14:47.599
of our guessed_states in order to get that number.

207
14:48.039 --> 14:49.760
So now when I run this code,

208
14:50.719 --> 14:53.880
you can see that I start out with 0 states, 0 out of 50,

209
14:54.280 --> 14:56.320
and every time I guess a new state,

210
14:57.559 --> 15:01.840
then it adds to that count so I can keep track of how many I've guessed and how

211
15:01.840 --> 15:03.000
many I've got left.

212
15:03.840 --> 15:08.840
Now the next thing you'll realize if you test this a few times is even if you

213
15:08.840 --> 15:10.520
get a state right,

214
15:10.760 --> 15:15.679
but if you actually didn't spell it with a capital C or capital letter to begin

215
15:15.679 --> 15:18.280
with, then it's not going to accept it.

216
15:18.280 --> 15:23.080
We don't see California showing up and this is because in our state_data,

217
15:23.239 --> 15:27.760
they all have title case where the first letter is capitalized.

218
15:28.119 --> 15:33.119
So how can we make sure that our game works if the user types all lowercase or

219
15:34.960 --> 15:38.679
all uppercase or title case? As long as they got the spelling right,

220
15:39.000 --> 15:40.559
we should ignore the casing.

221
15:42.080 --> 15:47.080
So one way of doing this is to take this answer_state which comes from that text

222
15:48.119 --> 15:50.440
input that the user has entered.

223
15:50.799 --> 15:55.280
And then at the very end we can change that to a title case.

224
15:55.520 --> 15:58.159
So this is a method that's on all strings.

225
15:58.559 --> 16:03.559
So that means if I start out with a string which is "Angela" and then I say

226
16:05.960 --> 16:07.719
str.title(),

227
16:08.239 --> 16:12.919
then this will give me the same string back but it'll make the first letter

228
16:12.919 --> 16:13.760
capitalized.

229
16:14.359 --> 16:18.320
This is what we're going to do to the user's answer and then we'll be able to

230
16:18.320 --> 16:23.159
check it against all the states and now it doesn't matter if the user has typed

231
16:23.359 --> 16:28.359
everything in all caps or if they have typed it with all lowercase or if they

232
16:29.679 --> 16:34.320
done something really crazy like this, it will still be accepted.

233
16:35.960 --> 16:39.200
So we've now got most of the functionality of our game.

234
16:39.799 --> 16:44.200
In the next lesson we're going to figure out how we can get this game to become

235
16:44.200 --> 16:49.200
more of an educational tool and for it to create a final CSV when we're ready to

236
16:50.119 --> 16:51.000
exit the game,

237
16:51.239 --> 16:55.440
that's going to tell us all the states that we missed so that we can learn them

238
16:55.679 --> 16:58.799
so that we can come back to the game with more knowledge.

239
16:59.239 --> 17:02.280
For all of that and more, I'll see you on the next lesson.