﻿1
00:00:04,592 --> 00:00:07,880
It is time for us to start
handling the player controls

2
00:00:07,905 --> 00:00:11,133
by determining the rules
that apply to players' guesses.

3
00:00:11,600 --> 00:00:13,977
Let's go from top to bottom.

4
00:00:14,467 --> 00:00:20,200
Since we want to enforce that a player
guess is limited to five letters,

5
00:00:20,433 --> 00:00:24,783
we can start by having a test in which,
during the act phase,

6
00:00:24,800 --> 00:00:28,333
our player types a guess
that is longer than five characters,

7
00:00:28,672 --> 00:00:34,333
but in which the first five characters
of that guess match the word of the day.

8
00:00:36,590 --> 00:00:37,900
When this happens,

9
00:00:37,925 --> 00:00:42,400
since our application will only
be considering the first five characters,

10
00:00:42,485 --> 00:00:47,692
the player should be seeing
the victory message being rendered.

11
00:00:47,717 --> 00:00:49,500
So let's write this assertion.

12
00:00:54,167 --> 00:00:59,433
If we run our tests, we can see
that this new test is failing,

13
00:01:00,567 --> 00:01:03,700
because the victory message
is not being rendered.

14
00:01:04,133 --> 00:01:06,543
Instead, we're seeing the defeat message.

15
00:01:07,257 --> 00:01:09,267
Okay, let's get it to pass.

16
00:01:10,937 --> 00:01:15,667
The HTML input has a built-in
attribute called maxlength,

17
00:01:16,413 --> 00:01:21,900
that would limit the amount of characters
the player can type at that input command.

18
00:01:22,206 --> 00:01:27,733
However, if I run the test right now,
you can see that we are still failing.

19
00:01:28,046 --> 00:01:32,933
The reason for that is due
to how vue test utils works.

20
00:01:33,300 --> 00:01:34,746
You can take a look over here

21
00:01:34,771 --> 00:01:38,400
and see that it is through
the invocation of such value

22
00:01:38,433 --> 00:01:42,200
that we emulate the user
typing their guess,

23
00:01:42,233 --> 00:01:46,300
but this function
bypasses the protection of maxlength.

24
00:01:47,643 --> 00:01:51,000
With that said, right after
we're done with this feature,

25
00:01:51,025 --> 00:01:53,990
we'll be going over
even more input controls

26
00:01:54,015 --> 00:01:59,400
that will go beyond what the native
HTML input helpers can assist us with.

27
00:01:59,826 --> 00:02:04,000
For that reason,
going straight towards using Vue.js

28
00:02:04,025 --> 00:02:09,070
to manipulate the input maxlength,
is not a big deal in our case.

29
00:02:11,230 --> 00:02:13,633
Vue offers an amazing way

30
00:02:13,658 --> 00:02:18,033
for you to control
and transform user input on the fly,

31
00:02:18,300 --> 00:02:22,733
and this is through
a writable computed ref.

32
00:02:24,163 --> 00:02:27,533
You start by defining it
like you would a regular ref.

33
00:02:27,607 --> 00:02:30,567
I'm going to call this
formattedGuessInProgress.

34
00:02:32,383 --> 00:02:34,067
In a computed ref,

35
00:02:34,253 --> 00:02:36,130
you would pass a callback

36
00:02:36,155 --> 00:02:39,967
that returns the value
that you are calculating.

37
00:02:40,867 --> 00:02:45,867
Okay, now, if you want to make
a writable computed ref,

38
00:02:46,099 --> 00:02:51,067
what you have to do is,
instead of passing just a single callback,

39
00:02:51,300 --> 00:02:55,167
we're going to pass an object
that has two callbacks inside of it,

40
00:02:55,640 --> 00:02:59,300
a getter and a setter.

41
00:03:01,337 --> 00:03:04,667
The getter will behave
just like the usual callback

42
00:03:04,900 --> 00:03:06,833
of a regular computed property,

43
00:03:07,267 --> 00:03:11,633
but the setter will be having
whatever is the raw value

44
00:03:12,960 --> 00:03:15,600
that we'll be receiving from our v-model,

45
00:03:18,020 --> 00:03:22,733
and in here we can manipulate
that raw value in whatever way we want.

46
00:03:23,100 --> 00:03:24,567
For our situation right now,

47
00:03:24,592 --> 00:03:29,600
what we need is to limit the raw value
to only the first five characters,

48
00:03:29,667 --> 00:03:31,600
and we can do it like this.

49
00:03:33,669 --> 00:03:38,616
Great! If we run our tests,
we can see that we're passing.

50
00:03:39,893 --> 00:03:41,826
Alright, let's make a commit.

51
00:03:42,586 --> 00:03:44,467
I think a good name for this commit

52
00:03:44,540 --> 00:03:49,733
could be
Limit player guesses to 5 characters.

53
00:03:53,150 --> 00:03:54,963
For our refactor phase,

54
00:03:55,100 --> 00:03:58,100
I think we can reduce
the complexity of the code base

55
00:03:58,125 --> 00:04:01,333
by extracting this number 5
into a constant.

56
00:04:01,766 --> 00:04:04,367
What does this number 5 mean?

57
00:04:04,773 --> 00:04:10,100
Well, it's the size of the words
we're going to be playing with,

58
00:04:10,480 --> 00:04:15,776
so why don't we create
a new constant in here called WORD_SIZE.

59
00:04:18,850 --> 00:04:21,263
And now,
whenever we're typing the number 5,

60
00:04:21,288 --> 00:04:23,200
we can make use of this constant.

61
00:04:28,823 --> 00:04:31,233
Same with our tests as well.

62
00:04:32,783 --> 00:04:35,100
I can turn this into a template string

63
00:04:35,507 --> 00:04:39,000
and then make use
of the WORD_SIZE constant right here.

64
00:04:41,220 --> 00:04:43,933
Great! Our tests are still passing.

65
00:04:43,958 --> 00:04:46,900
This is a great opportunity for us
to make another commit.

66
00:04:47,776 --> 00:04:49,533
Extract constant.

67
00:04:51,870 --> 00:04:55,000
Okay, it's time for us to move
to our next test.

68
00:04:55,253 --> 00:04:58,800
In this case,
we want to prevent the player

69
00:04:58,833 --> 00:05:02,567
from submitting guesses
that are not real words.

70
00:05:03,213 --> 00:05:05,800
In this case, I think in our act phase,

71
00:05:05,825 --> 00:05:08,356
we could have our user
typing a guess

72
00:05:08,381 --> 00:05:09,737
that is not a real word.

73
00:05:09,767 --> 00:05:11,867
For example, QWERT.

74
00:05:12,707 --> 00:05:16,167
And in this case, because this guess
is going to be rejected,

75
00:05:16,200 --> 00:05:19,473
the player should not
be seeing the victory message

76
00:05:19,498 --> 00:05:24,533
nor the defeat message
because no guess was truly submitted.

77
00:05:24,767 --> 00:05:28,167
So let's just copy this assertion
from this prior test over here

78
00:05:28,200 --> 00:05:32,133
and just change it to have
the NOT keyword beforehand.

79
00:05:32,267 --> 00:05:34,956
And we're going to do the same thing
for the defeat message.

80
00:05:35,893 --> 00:05:37,933
If we run all of our tests again,

81
00:05:37,967 --> 00:05:40,267
we can see
that this brand new test is failing

82
00:05:40,333 --> 00:05:42,633
because we're seeing the defeat message.

83
00:05:43,233 --> 00:05:46,242
This is expected
because our application right now,

84
00:05:46,267 --> 00:05:48,800
is accepting any kind of guesses.

85
00:05:49,367 --> 00:05:51,267
So let's try to limit this.

86
00:05:51,586 --> 00:05:53,417
And one way we can achieve it,

87
00:05:53,500 --> 00:05:58,433
it is by refining
our keydown.enter handler.

88
00:05:59,200 --> 00:06:04,100
So what I'm going to do is I will start
by extracting this into a method.

89
00:06:09,510 --> 00:06:11,167
And what this method
is going to be doing

90
00:06:11,192 --> 00:06:13,267
is just exactly what we have in here.

91
00:06:18,130 --> 00:06:20,770
Great.
So we're still failing and that's okay.

92
00:06:20,795 --> 00:06:22,823
Now what I'm going to do is,

93
00:06:23,233 --> 00:06:26,943
before assigning the value
of the guess in progress

94
00:06:26,968 --> 00:06:28,057
to the guess submitted,

95
00:06:28,067 --> 00:06:32,733
I'm going to check to see if the guess
in progress is a real English word.

96
00:06:33,046 --> 00:06:36,250
And if it isn't,
I'm going to early return.

97
00:06:36,300 --> 00:06:37,533
So let's do this.

98
00:06:42,650 --> 00:06:47,533
If our collection of English words
do not include the guess in progress,

99
00:06:48,070 --> 00:06:49,400
do an early return.

100
00:06:49,646 --> 00:06:55,267
If we run our tests, we can see
that we're back to the green stage.

101
00:06:56,977 --> 00:06:58,667
Let's make another commit.

102
00:06:59,633 --> 00:07:03,467
Prevent guesses that are not
English words from being submitted.

103
00:07:08,367 --> 00:07:10,100
For our refactor phase,

104
00:07:10,125 --> 00:07:12,787
I honestly don't see
anything at the moment

105
00:07:12,812 --> 00:07:14,300
that I would like to refactor.

106
00:07:14,333 --> 00:07:15,567
And that's okay.

107
00:07:15,853 --> 00:07:17,390
So let's keep that in mind

108
00:07:17,415 --> 00:07:22,100
that even though the TDD loop
is red-green refactor,

109
00:07:22,313 --> 00:07:26,361
sometimes we do come across scenarios
like this one

110
00:07:26,386 --> 00:07:29,710
in which we end up skipping a phase.

111
00:07:31,123 --> 00:07:33,867
So let's go to our next test.

112
00:07:34,967 --> 00:07:38,333
To enforce that guesses
are not case-sensitive,

113
00:07:38,606 --> 00:07:42,300
we could have the user type a guess
that is in lowercase,

114
00:07:42,400 --> 00:07:46,800
but that would otherwise perfectly
match the word of the day.

115
00:07:46,873 --> 00:07:48,690
So let's type this act phase.

116
00:07:50,270 --> 00:07:52,977
If the user were to type
the word of the day right now,

117
00:07:53,002 --> 00:07:54,667
they would win the game, right?

118
00:07:54,693 --> 00:07:56,033
But what I'm going to do, is,

119
00:07:56,058 --> 00:08:00,346
I'm going to have the user type
the word of the day in lowercase.

120
00:08:00,866 --> 00:08:04,890
And we still want the user
to be winning the game,

121
00:08:04,915 --> 00:08:07,767
so they should see the victory message.

122
00:08:09,690 --> 00:08:12,963
If we run our tests, we can see, however,

123
00:08:13,033 --> 00:08:17,100
that the player
is not seeing the victory message.

124
00:08:17,125 --> 00:08:19,457
In fact, they are not seeing
any messages at all

125
00:08:19,482 --> 00:08:22,267
because their guess got rejected

126
00:08:22,566 --> 00:08:25,833
due to not being in the list
of English words that we have.

127
00:08:26,279 --> 00:08:31,067
Because remember, our list
of English words are all in uppercase.

128
00:08:32,473 --> 00:08:34,800
Okay, let's get it to pass.

129
00:08:36,133 --> 00:08:38,800
There are different approaches
that we can do over here,

130
00:08:38,826 --> 00:08:44,900
but what I want to do is emulate
what happens in the real wordle game.

131
00:08:45,300 --> 00:08:49,742
And that is, regardless
if you're typing a lowercase character

132
00:08:49,767 --> 00:08:51,567
or an uppercase character,

133
00:08:51,760 --> 00:08:56,900
the output in the game board
will always be in uppercase.

134
00:08:57,500 --> 00:09:00,433
So we can do the same
in our version over here.

135
00:09:01,133 --> 00:09:04,800
To do this, we can go back
to our writable computed ref,

136
00:09:05,333 --> 00:09:08,700
and as part of the transformation
in the setter,

137
00:09:08,813 --> 00:09:14,300
we can cast the raw value
to uppercase, like this.

138
00:09:14,933 --> 00:09:16,600
So let's run our tests,

139
00:09:17,253 --> 00:09:20,100
and we can see
that we're back to passing.

140
00:09:20,312 --> 00:09:22,567
Great! Let's make another commit.

141
00:09:23,133 --> 00:09:26,033
A good commit message
for this case would be,

142
00:09:26,113 --> 00:09:29,900
make player guesses case-insensitive.

143
00:09:31,943 --> 00:09:35,557
Once again, I don't see anything in here
that I would like to refactor,

144
00:09:35,767 --> 00:09:39,533
so I think we're good to move on
to our next test.

145
00:09:40,059 --> 00:09:41,967
Now, what we want to do

146
00:09:42,000 --> 00:09:46,367
is prevent our players from typing
anything that is not a letter.

147
00:09:46,700 --> 00:09:49,217
Well, a good way for us to start this test

148
00:09:49,267 --> 00:09:53,860
is by having our act phase
involving our user typing a guess

149
00:09:53,885 --> 00:09:58,433
that contains numbers
and special characters, like this.

150
00:09:58,946 --> 00:10:01,342
And what we want to assert in this case

151
00:10:01,367 --> 00:10:06,930
is that the player input will contain
only the H, R, and T.

152
00:10:06,955 --> 00:10:08,075
Let's do this.

153
00:10:23,490 --> 00:10:28,233
Okay, if we run our tests,
we can see that we're failing,

154
00:10:28,267 --> 00:10:31,500
because the number
and the special character

155
00:10:31,899 --> 00:10:35,567
have gone through our input.

156
00:10:36,280 --> 00:10:37,960
Alright, so once again,

157
00:10:37,985 --> 00:10:44,491
we're going to be refining
our setter in the writable computed ref.

158
00:10:45,679 --> 00:10:50,786
And for this point, whenever I want
to do this more complex filtering,

159
00:10:50,967 --> 00:10:53,233
I like to rely on RegEx.

160
00:10:53,672 --> 00:10:56,767
I'm going to explain the RegEx
that I'm going to be using here,

161
00:10:56,833 --> 00:11:00,133
but if you're not comfortable
with RegEx in general,

162
00:11:00,167 --> 00:11:04,317
I strongly recommend
checking out regex101.com.

163
00:11:04,333 --> 00:11:07,467
It provides an amazing resource
for you to know the rules

164
00:11:07,633 --> 00:11:09,633
and how to test your RegEx.

165
00:11:10,767 --> 00:11:12,257
But okay, let's continue.

166
00:11:12,267 --> 00:11:16,667
In this case, I'm going to use
a RegEx to define my target,

167
00:11:17,539 --> 00:11:20,733
and I will replace it for an empty string.

168
00:11:23,310 --> 00:11:26,467
Alright, so let me explain
what I've typed so far in here.

169
00:11:27,067 --> 00:11:29,533
Typing anything between slashes

170
00:11:29,567 --> 00:11:36,167
is one of the ways in which you can define
RegExes in JavaScript or TypeScript.

171
00:11:36,900 --> 00:11:41,067
After the last /
we can pass configuration options.

172
00:11:41,133 --> 00:11:47,267
"g" means global, and it makes the RegEx
not return after the first match.

173
00:11:47,500 --> 00:11:53,500
The "i" flag means that our RegEx
is going to be case insensitive.

174
00:11:55,200 --> 00:11:58,300
I'm going to be looking
for anything that is not a letter,

175
00:11:58,325 --> 00:12:04,200
so one way that you can define it
is by doing this RegEx over here.

176
00:12:04,480 --> 00:12:05,680
Let me explain.

177
00:12:06,073 --> 00:12:09,400
The brackets allow me to represent
a single character

178
00:12:09,425 --> 00:12:13,633
of whatever set I want to define
inside the brackets.

179
00:12:14,633 --> 00:12:18,700
The ^ inside of the bracket means not,

180
00:12:18,800 --> 00:12:23,028
therefore, it represents a set
of all the characters

181
00:12:23,053 --> 00:12:26,267
that are not the letters from A to Z.

182
00:12:27,187 --> 00:12:30,108
By adding a + after this set,

183
00:12:30,133 --> 00:12:36,633
I'm determining that I'm looking for one
or more occurrences of a character

184
00:12:36,658 --> 00:12:38,000
that matches this set.

185
00:12:39,200 --> 00:12:42,300
Okay, so effectively
what I'm doing on line 23

186
00:12:42,420 --> 00:12:48,567
is replacing anything that is not
a letter to an empty string.

187
00:12:48,600 --> 00:12:51,767
Effectively removing them
from the raw value.

188
00:12:51,900 --> 00:12:56,390
If we run our test,
we can see that we're passing.

189
00:12:58,003 --> 00:13:00,067
Great! Let's make another commit.

190
00:13:02,490 --> 00:13:06,200
Only allow player to type letters.

191
00:13:07,777 --> 00:13:13,008
Awesome! Together, we've practiced
how to write tests for player inputs.

192
00:13:13,033 --> 00:13:17,683
We also had a great opportunity
to leverage Vue writeable computed refs

193
00:13:17,700 --> 00:13:21,667
to allow us to manipulate
player input during a v-model.


