Would you like to inspect the original subtitles? These are the user uploaded subtitles that are being translated:
1
00:00:00,000 --> 00:00:03,030
[Treehouse Workshops]
2
00:00:03,030 --> 00:00:04,900
[Randy] Hello, my name is Randy.
3
00:00:04,900 --> 00:00:07,520
In today's workshop I'm going to walk you step-by-step
4
00:00:07,520 --> 00:00:10,260
through how I would solve a particular programming problem.
5
00:00:10,260 --> 00:00:12,310
We'll be writing object-oriented JavaScript,
6
00:00:12,310 --> 00:00:14,860
so if you're new to that, this will be a great introduction.
7
00:00:14,860 --> 00:00:18,270
But even if you already know how to write constructors and prototype functions,
8
00:00:18,270 --> 00:00:22,130
this workshop will show you how another programmer, me, thinks and works.
9
00:00:22,130 --> 00:00:25,050
This should show you ways to improve your own workflow and code—
10
00:00:25,050 --> 00:00:26,930
whatever language you're working in.
11
00:00:26,930 --> 00:00:29,480
Hopefully you'll end up thinking more like a programmer.
12
00:00:29,560 --> 00:00:32,130
[Step 1. | The Problem]
13
00:00:32,130 --> 00:00:33,930
Let's start with the problem.
14
00:00:34,880 --> 00:00:39,110
Write a program that represents a robot in this maze
15
00:00:39,110 --> 00:00:41,480
and leads the robot to the exit.
16
00:00:41,480 --> 00:00:43,720
Let's get started.
17
00:00:43,720 --> 00:00:46,420
You might be tempted to open up a text editor and start coding,
18
00:00:46,420 --> 00:00:49,540
but I highly recommend spending some time planning out your code.
19
00:00:49,540 --> 00:00:52,800
I'll often at least sketch out ideas with pencil and paper first.
20
00:00:52,800 --> 00:00:56,370
For a problem like this, I'd probably create a simple model.
21
00:00:59,480 --> 00:01:02,800
Spending a little time moving a physical robot around a maze
22
00:01:02,800 --> 00:01:04,890
can give you a better grasp of the problem
23
00:01:04,890 --> 00:01:07,490
and give you a better chance of finding the solution.
24
00:01:07,490 --> 00:01:10,480
[Step 2. | Identifying Objects]
25
00:01:10,480 --> 00:01:13,660
Let's start by identifying what objects we'll need.
26
00:01:13,660 --> 00:01:15,660
An object is a pretty robust type of variable.
27
00:01:15,660 --> 00:01:17,660
[Object - Type of Variable Containing Properties (Data) and Methods (Behavior)]
28
00:01:17,660 --> 00:01:20,230
It's essentially a collection of variables and functions all wrapped up together.
29
00:01:20,230 --> 00:01:24,020
In the context of an object, these variables are usually called properties
30
00:01:24,020 --> 00:01:26,410
and the functions are usually called methods.
31
00:01:26,410 --> 00:01:29,340
The properties contain information about the particular object
32
00:01:29,340 --> 00:01:31,930
and the methods perform various actions.
33
00:01:31,930 --> 00:01:34,050
I spent some time earlier today with Ben
34
00:01:34,050 --> 00:01:37,990
talking about what objects, properties, and methods we'd need for this program.
35
00:01:40,570 --> 00:01:43,500
Hey, Ben. >>[Ben] Oh. Hey, Randy. What have you got there?
36
00:01:43,500 --> 00:01:47,080
It's a model I built to help me think through a computer programming question.
37
00:01:47,080 --> 00:01:50,930
I'm trying to write a program that represents a robot in a maze.
38
00:01:50,930 --> 00:01:53,810
Do you have a few minutes to chat about it? >>Yeah, sure.
39
00:01:53,810 --> 00:01:58,490
All right. So I assume I'm going to need a robot object and a maze object at the very least.
40
00:01:58,490 --> 00:02:03,350
Yeah. If it's a real-life object like that, chances are it's probably going to need to be an object in code too.
41
00:02:03,350 --> 00:02:06,610
Okay. Cool. >>So is your maze going to always be this exact same size?
42
00:02:06,610 --> 00:02:08,729
Ooh. I guess it doesn't need to be.
43
00:02:08,729 --> 00:02:11,720
We could write the object so that it could be an arbitrary height or width.
44
00:02:11,720 --> 00:02:16,180
Okay. So you want to set up those 2 properties when you actually code the maze object. >>Okay.
45
00:02:16,180 --> 00:02:19,720
You'll also need a way to identify each space in the maze
46
00:02:19,720 --> 00:02:22,810
so you can track the robot's current position, something like coordinates.
47
00:02:22,810 --> 00:02:28,060
Okay. So we can make the spaces here a grid and then add X and Y coordinates here.
48
00:02:28,060 --> 00:02:30,740
So across the bottom I'll have my X coordinates
49
00:02:30,740 --> 00:02:33,720
and across the side I'll have my Y coordinates.
50
00:02:33,720 --> 00:02:38,440
Okay. So this starting space over here would be X coordinate of 1, Y coordinate of 1?
51
00:02:38,440 --> 00:02:40,620
Okay. That sounds good. >>Okay.
52
00:02:40,620 --> 00:02:42,370
Now I'll need him to move forward.
53
00:02:42,370 --> 00:02:47,570
So I guess when I move him this way, his Y coordinate will increase from 1 to 2. Is that right?
54
00:02:47,570 --> 00:02:49,510
Yeah, that's right.
55
00:02:49,510 --> 00:02:54,250
You'll probably want to move him forward using a method like moveForward or something like that.
56
00:02:54,250 --> 00:02:59,340
You don't want to change his coordinate properties directly from within your main program. >>Okay.
57
00:02:59,340 --> 00:03:03,160
If I move him forward another space, he hits a wall.
58
00:03:03,160 --> 00:03:06,850
I'll need him to go right now. Do I need another method for move right?
59
00:03:06,850 --> 00:03:08,460
Well, you could.
60
00:03:08,460 --> 00:03:12,450
Or maybe you could have him turn right instead and then use that same moveForward method again.
61
00:03:12,450 --> 00:03:14,380
Okay. That makes sense.
62
00:03:14,380 --> 00:03:16,460
Now I need him to turn left here.
63
00:03:16,460 --> 00:03:20,410
Would you maybe have a turn method that I could pass in a parameter of left or right?
64
00:03:20,410 --> 00:03:24,100
You know, I'd probably have 2 different methods—turnLeft and turnRight—
65
00:03:24,100 --> 00:03:26,600
although that doesn't mean that's necessarily the right answer.
66
00:03:26,600 --> 00:03:29,730
Software programming is more of an art than a science sometimes.
67
00:03:29,730 --> 00:03:33,590
If you ask somebody one day, they may give you a different answer than another day.
68
00:03:33,590 --> 00:03:36,860
Got it. All right. So I'll move him forward here.
69
00:03:36,860 --> 00:03:39,470
Hmm. Let's see.
70
00:03:39,470 --> 00:03:43,890
If I turn him left or right, I guess he's going to need to know which way he's facing.
71
00:03:43,890 --> 00:03:47,390
Yeah, yeah. He'll need a property for his orientation.
72
00:03:47,390 --> 00:03:51,160
The moveForward method will need to know which way is forward for the robot.
73
00:03:51,160 --> 00:03:54,860
Okay. And that orientation will probably need to be an absolute direction then.
74
00:03:54,860 --> 00:03:58,480
Yeah. You could use maybe north, south, east, and west.
75
00:03:58,480 --> 00:04:00,390
Okay. That makes sense.
76
00:04:00,390 --> 00:04:04,250
So if he's facing north and he moves forward, the moveForward method
77
00:04:04,250 --> 00:04:07,700
would increase his Y coordinate by 1. >>Yeah.
78
00:04:07,700 --> 00:04:13,780
And if I turn him to face east and he moves forward, that would increase his X coordinate by 1 then.
79
00:04:13,780 --> 00:04:16,060
Precisely. >>Okay. Got it.
80
00:04:16,060 --> 00:04:18,610
Will I need a method to check if there's a wall in his way?
81
00:04:18,610 --> 00:04:23,970
Does he have a blaster? >>No blasters, Ben. He's got to go around the walls of the maze.
82
00:04:23,970 --> 00:04:26,620
Well, if you're moving him manually, then you'll know where to go.
83
00:04:26,620 --> 00:04:29,470
But if you want him to be able to move around the maze by himself,
84
00:04:29,470 --> 00:04:32,830
then yeah, you need to ask the maze a question: Can I move forward?
85
00:04:32,830 --> 00:04:35,330
Yeah. That is the plan eventually.
86
00:04:35,330 --> 00:04:39,250
I guess that will need to be a method then. What parameters? Let's see.
87
00:04:39,250 --> 00:04:44,810
I guess I could ask the maze if he could move forward from his X and Y coordinate and which direction he's moving.
88
00:04:44,810 --> 00:04:46,940
Yeah, exactly. >>Okay.
89
00:04:46,940 --> 00:04:49,760
But we don't have the walls or the location of the walls stored anywhere.
90
00:04:49,760 --> 00:04:51,760
Where would we store those?
91
00:04:51,760 --> 00:04:56,000
Let's see. Each space in the maze is mapped to X and Y coordinates.
92
00:04:56,000 --> 00:04:59,260
So maybe we could have a 2-dimensional array of spaces.
93
00:04:59,260 --> 00:05:03,500
That makes sense. The maze would then have that 2D array as one of its properties.
94
00:05:03,500 --> 00:05:05,960
What about the walls?
95
00:05:05,960 --> 00:05:09,340
Each space has 4 possible spots for walls.
96
00:05:09,340 --> 00:05:11,700
So I guess a space would need to be an object with 4 properties.
97
00:05:11,700 --> 00:05:17,500
Okay. So then I could ask the maze something like, does space 4-4 have a wall on its south side?
98
00:05:17,500 --> 00:05:23,800
Yeah. >>So I'll need an addWall method then somewhere, and I can pass in an X and Y coordinate and a direction.
99
00:05:23,800 --> 00:05:25,600
I think you'll want that on the maze.
100
00:05:25,600 --> 00:05:27,880
The space objects can be internal to the maze object,
101
00:05:27,880 --> 00:05:31,810
but your main program is only going to call methods from the robot object or the maze object.
102
00:05:31,810 --> 00:05:33,210
Okay. That makes sense.
103
00:05:33,210 --> 00:05:36,530
So I'll call the addWall method when I instantiate the maze.
104
00:05:36,530 --> 00:05:42,780
I suppose it's worth mentioning that the north wall of this space is the same as the south wall of that space.
105
00:05:42,780 --> 00:05:44,310
Is that going to be a problem?
106
00:05:44,310 --> 00:05:48,950
You could automatically add a wall to one spot whenever you add one on the other spot,
107
00:05:48,950 --> 00:05:52,330
or you could instead act like there are 2 separate spots for walls,
108
00:05:52,330 --> 00:05:55,800
one on the north side of this space and one on the south side of that space.
109
00:05:55,800 --> 00:06:00,460
So you'd have to check both spots in the canMoveForward method for the robot
110
00:06:00,460 --> 00:06:03,270
to make sure there's not a wall in either of them.
111
00:06:03,270 --> 00:06:09,690
So here the canMoveForward method would have to check if space 4-4 had a south wall
112
00:06:09,690 --> 00:06:13,990
or if space 4-3 had a north wall. >>I like that.
113
00:06:13,990 --> 00:06:17,660
I'd like to keep the logic about shared walls in the canMoveForward method.
114
00:06:17,660 --> 00:06:20,070
I'd like the spaces to stay independent of each other.
115
00:06:20,070 --> 00:06:21,970
They don't even really know where they are on the maze,
116
00:06:21,970 --> 00:06:24,000
and it would be nice if someday I could shuffle them around
117
00:06:24,000 --> 00:06:25,810
like in the board game The aMAZEing Labyrinth.
118
00:06:25,810 --> 00:06:28,900
It would definitely be better if each wall was on a particular space.
119
00:06:28,900 --> 00:06:30,280
Yeah. Seems reasonable.
120
00:06:30,280 --> 00:06:32,610
All right. So what else am I missing?
121
00:06:32,610 --> 00:06:35,680
The robot asks the maze a question: Can I move forward?
122
00:06:35,680 --> 00:06:40,390
So we need to establish a relationship between the robot and the maze that it's in. >>Okay.
123
00:06:40,390 --> 00:06:42,660
We could store that as a property of the maze object then
124
00:06:42,660 --> 00:06:45,120
with a reference to the robot object.
125
00:06:45,120 --> 00:06:48,190
Theoretically, a maze could have multiple robots in it at one time,
126
00:06:48,190 --> 00:06:50,410
but a robot is only going to be in one maze.
127
00:06:50,410 --> 00:06:53,320
So instead, we should probably store that as a property of the robot object.
128
00:06:53,320 --> 00:06:57,520
Okay. That makes sense. Then we'll need a method to place the robot in the maze.
129
00:06:57,520 --> 00:06:59,840
I suppose the maze needs to know its starting coordinates,
130
00:06:59,840 --> 00:07:02,840
and it can pass that back to the robot so we'll know where to set him when we start.
131
00:07:02,840 --> 00:07:05,700
Yeah, and the maze should probably know its ending coordinates too,
132
00:07:05,700 --> 00:07:08,100
so when the robot gets over here he knows he's done.
133
00:07:08,100 --> 00:07:10,480
Cool. I think that covers what I need to know.
134
00:07:10,480 --> 00:07:13,100
I'm going to head back and code up these objects. Thanks a lot, Ben.
135
00:07:13,100 --> 00:07:14,660
Sure. Have fun.
136
00:07:18,160 --> 00:07:20,640
[Step 3. | Creating the Maze]
137
00:07:20,640 --> 00:07:23,260
I feel like we have a good grasp of the problem now.
138
00:07:23,260 --> 00:07:24,860
So let's start writing some code.
139
00:07:24,860 --> 00:07:27,070
We could code this program in many different languages.
140
00:07:27,070 --> 00:07:30,480
I'm going to use JavaScript because most of you will have a browser installed.
141
00:07:30,480 --> 00:07:33,010
We'll be editing JavaScript and HTML files
142
00:07:33,010 --> 00:07:36,290
as well as interacting with our JavaScript objects through the console.
143
00:07:36,290 --> 00:07:37,960
I'll be using Google Chrome on a Mac,
144
00:07:37,960 --> 00:07:41,480
so to open up the console I'll press Command-Option-I.
145
00:07:43,500 --> 00:07:46,620
I'll post some instructions to this workshop for accessing the console
146
00:07:46,620 --> 00:07:49,090
in other browsers and other operating systems.
147
00:07:49,090 --> 00:07:52,900
After talking with Ben, we determined that we'd need 3 types of objects:
148
00:07:52,900 --> 00:07:56,690
a robot, a maze, and an array of maze spaces.
149
00:07:56,690 --> 00:08:00,470
Let's create 3 JavaScript files, one for each of the objects.
150
00:08:19,760 --> 00:08:21,870
Let's start with the maze object.
151
00:08:21,870 --> 00:08:26,200
The first thing to put in every JavaScript file is the "use strict" declaration.
152
00:08:28,410 --> 00:08:32,450
This causes newer browsers to run JavaScript code in a stricter context,
153
00:08:32,450 --> 00:08:35,750
which can help us prevent common mistakes that can be hard to troubleshoot.
154
00:08:35,750 --> 00:08:39,360
I'll link to an article on this by John Resig. [ECMAScript 5 Strict Mode - http://trhou.se/usestrict]
155
00:08:39,360 --> 00:08:42,880
To create an object definition, you define a constructor function.
156
00:08:48,130 --> 00:08:51,890
You set the properties of an object using the keyword "this."
157
00:08:53,790 --> 00:08:56,680
That keyword references the current context.
158
00:08:56,680 --> 00:09:00,670
Inside the constructor function, that context is the object itself.
159
00:09:00,670 --> 00:09:06,320
So this will create a new property in the maze object named width and assign it a value of 7.
160
00:09:06,320 --> 00:09:08,900
We'll also add a property for height.
161
00:09:12,510 --> 00:09:15,780
Before we get much further, let's get this JavaScript file in the browser.
162
00:09:15,780 --> 00:09:19,080
I've created an HTML document with some basic structure already.
163
00:09:19,080 --> 00:09:22,600
I'll refer to the code in this HTML document as our main program.
164
00:09:22,600 --> 00:09:25,260
Most of the code we'll write will be in our object definitions,
165
00:09:25,260 --> 00:09:27,600
and then we'll have a little bit of code in the main program
166
00:09:27,600 --> 00:09:30,180
that creates the objects and interacts with them.
167
00:09:30,180 --> 00:09:35,080
Let me paste in the code here to include the 3 JavaScript files we'll need at the head of the document.
168
00:09:37,380 --> 00:09:39,940
Let's load this page up in the browser.
169
00:09:39,940 --> 00:09:43,670
The JavaScript code we've written defines what a maze object would look like,
170
00:09:43,670 --> 00:09:46,480
but I haven't actually created a maze object yet.
171
00:09:46,480 --> 00:09:50,460
If you've worked with objects before, you might be familiar with the concept of a class.
172
00:09:50,460 --> 00:09:55,630
Most web languages have classes that define the properties and methods available in an object.
173
00:09:55,630 --> 00:10:00,180
JavaScript is a little different, but this constructor function works a bit like a class.
174
00:10:00,180 --> 00:10:04,800
We can call that function in the console to create a real maze object.
175
00:10:13,570 --> 00:10:17,140
This creates a new maze object and loads it into the variable M.
176
00:10:17,140 --> 00:10:22,660
In the console you can just type a variable name and it will display all the information about that variable.
177
00:10:22,660 --> 00:10:25,300
The console tells us that we have a maze object.
178
00:10:25,300 --> 00:10:28,060
We can expand it to see the properties of the object.
179
00:10:28,060 --> 00:10:30,240
So far we have a height and a width.
180
00:10:30,240 --> 00:10:34,510
Ben suggested we allow mazes to have an arbitrary height and width.
181
00:10:34,510 --> 00:10:37,360
Once you create a maze, there's no need to change it,
182
00:10:37,360 --> 00:10:41,940
but we should allow programs to call the constructor and create mazes of different sizes.
183
00:10:41,940 --> 00:10:44,540
We can add arguments to our constructor to handle that.
184
00:10:45,290 --> 00:10:47,180
The first argument will be for the width.
185
00:10:47,180 --> 00:10:52,300
Let's just always keep the X coordinate and the horizontal access first in this list of arguments.
186
00:10:52,300 --> 00:10:54,240
The second will be for the height.
187
00:10:55,690 --> 00:11:00,080
Instead of 5 and 7, let's load the values from these arguments into our properties.
188
00:11:05,760 --> 00:11:09,340
Let's refresh the page and create the maze object again.
189
00:11:12,610 --> 00:11:15,630
This time we'll specify the height and the width.
190
00:11:21,490 --> 00:11:25,260
Any code we run in the console gets executed just that one time.
191
00:11:25,260 --> 00:11:27,640
We lose it when we refresh the page.
192
00:11:27,640 --> 00:11:30,180
We'll use the console to explore the objects we create
193
00:11:30,180 --> 00:11:32,150
and to troubleshoot some different scenarios.
194
00:11:32,150 --> 00:11:35,920
But we want our program to create a maze object each time we load it.
195
00:11:35,920 --> 00:11:38,500
Let's put that code in the HTML file.
196
00:11:53,200 --> 00:11:56,840
If we refresh the page now, the maze object should be created.
197
00:11:56,840 --> 00:11:59,660
We can type M and see that it exists.
198
00:12:01,170 --> 00:12:03,110
Let's add the other properties to our maze.
199
00:12:03,110 --> 00:12:05,400
We could add more arguments to the constructor,
200
00:12:05,400 --> 00:12:08,970
but I feel like these properties could be set after the maze is created.
201
00:12:11,910 --> 00:12:14,860
Let me paste in some code here to create the next 5 properties:
202
00:12:14,860 --> 00:12:19,510
the X and Y coordinates of the start space, the direction the robot should be facing when he starts—
203
00:12:19,510 --> 00:12:24,810
the start orientation—and the X and Y coordinates of the exit or the end point of the maze.
204
00:12:24,810 --> 00:12:28,430
Our main program could set these properties directly,
205
00:12:28,430 --> 00:12:31,140
something like this.
206
00:12:38,330 --> 00:12:41,380
You can see how that sets the start X.
207
00:12:41,380 --> 00:12:44,170
But it's a better practice to provide what are known as setter methods.
208
00:12:44,170 --> 00:12:47,710
This allows you to provide validation before the properties get set.
209
00:12:47,710 --> 00:12:52,410
It would be a good idea with this property to make sure it's actually within the bounds of the maze.
210
00:12:55,390 --> 00:13:01,260
You can create a method in a JavaScript object by adding a function to its prototype property.
211
00:13:14,790 --> 00:13:18,410
It can be a little confusing, especially if you've worked with other languages that have classes.
212
00:13:18,410 --> 00:13:21,250
JavaScript doesn't have classes exactly,
213
00:13:21,250 --> 00:13:26,870
but this code block defines a method called setStart that will be available in all of our maze objects.
214
00:13:28,000 --> 00:13:31,110
Technically speaking, the robot would start outside of the maze,
215
00:13:31,110 --> 00:13:34,870
but it will be easier to track if we assume he starts on a particular space.
216
00:13:34,870 --> 00:13:40,110
We'll pass into this method an X and Y coordinate as well as a starting orientation.
217
00:13:47,950 --> 00:13:52,150
When we put a robot in the maze later, this will tell us what its starting X and Y coordinates should be
218
00:13:52,150 --> 00:13:54,140
and which way he should be facing.
219
00:13:54,140 --> 00:13:57,230
We can set the maze's properties inside here.
220
00:13:57,230 --> 00:14:01,320
Once again, the "this" keyword will refer to the current object.
221
00:14:16,730 --> 00:14:19,840
Next we'll create a similar method for the exit point.
222
00:14:32,890 --> 00:14:37,040
This method will receive 2 arguments: the X and Y coordinate of the exit.
223
00:14:47,950 --> 00:14:50,950
Once again, the exit is technically outside of the maze,
224
00:14:50,950 --> 00:14:54,660
but it will be easier if we think of it as one of the spaces at the end.
225
00:14:54,660 --> 00:14:56,680
Let's go back to our main program.
226
00:14:56,680 --> 00:15:00,390
We can call these 2 setter methods to set all 5 of these properties.
227
00:15:29,780 --> 00:15:32,380
Once again, let's take a look at this in the browser.
228
00:15:35,860 --> 00:15:39,120
Looking at our maze object, you can see the start and the end points have been set
229
00:15:39,120 --> 00:15:41,400
as well as the starting orientation.
230
00:15:41,400 --> 00:15:46,000
The last property we need for the maze object is the 2-dimensional array of spaces.
231
00:15:46,000 --> 00:15:48,820
When the maze is constructed, we'll have a height and a width.
232
00:15:48,820 --> 00:15:51,100
Based on that, we'll need to create our array.
233
00:15:51,100 --> 00:15:54,950
This maze is 7 by 5, so we'll have 35 spaces.
234
00:15:56,460 --> 00:15:59,660
I'll first create an empty array called spaces.
235
00:16:02,750 --> 00:16:06,980
I'll keep using the X coordinate first, and I'll write a for loop that goes through each column
236
00:16:06,980 --> 00:16:09,620
and creates an array element for it.
237
00:16:32,210 --> 00:16:36,090
This for loop goes through each column and creates an array element for it.
238
00:16:36,090 --> 00:16:39,360
That array element will be another empty array.
239
00:16:39,360 --> 00:16:42,570
At this point we should have an array with 7 elements,
240
00:16:42,570 --> 00:16:45,580
each element with an empty array inside of that.
241
00:16:45,580 --> 00:16:50,930
For each column we'll also loop through each Y coordinate and add an element to the array.
242
00:17:17,839 --> 00:17:21,930
This for loop will add one element to the array for each space in the column.
243
00:17:21,930 --> 00:17:24,599
Let's set this to a placeholder value for now,
244
00:17:24,599 --> 00:17:27,810
maybe a text representation of the coordinates.
245
00:17:41,070 --> 00:17:43,570
Let's take a look at all this in the browser.
246
00:17:45,570 --> 00:17:48,260
We're creating a maze object, and let's take a look at it.
247
00:17:48,260 --> 00:17:51,360
You can see now we have an array of spaces.
248
00:17:51,360 --> 00:17:56,550
This spaces array has 8 elements, one for each column and also one that specifies the length.
249
00:17:56,550 --> 00:17:59,950
Inside each column we have another array with 6 spaces,
250
00:17:59,950 --> 00:18:03,220
one for each of the 5 rows and another one that sets its length.
251
00:18:03,220 --> 00:18:07,590
Each element at the lower level here is a string with the coordinates.
252
00:18:07,590 --> 00:18:12,840
We really want each element in the array to be another object, a maze space object.
253
00:18:12,840 --> 00:18:15,190
Let's work on that object definition next.
254
00:18:15,190 --> 00:18:18,310
Each maze space object should have only 4 properties,
255
00:18:18,310 --> 00:18:21,150
one for each side of the space that could contain a wall.
256
00:18:24,690 --> 00:18:28,320
When we first create the object, let's give these properties a value of false.
257
00:18:29,520 --> 00:18:32,490
We can set walls and change them to true a little later on.
258
00:18:42,640 --> 00:18:47,290
Let's now change our maze object to create an array of maze space objects.
259
00:19:05,340 --> 00:19:10,380
In the browser you can now see that each of these elements in the array is now a maze space object,
260
00:19:10,380 --> 00:19:13,470
no longer just a piece of text with the coordinates.
261
00:19:13,470 --> 00:19:16,750
Let's create a method we can use for setting a wall.
262
00:19:16,750 --> 00:19:19,880
We could create 4 methods, one for each wall spot,
263
00:19:19,880 --> 00:19:23,050
but I'd rather create one function and pass it an argument.
264
00:19:23,050 --> 00:19:29,390
This one argument should be which spot—north, south, east, or west—should get the wall.
265
00:19:30,110 --> 00:19:33,730
If we know a property's name, we can set it like this.
266
00:19:38,220 --> 00:19:40,510
We could also use this syntax.
267
00:19:45,090 --> 00:19:49,590
When we have the name of the property in a variable, then we actually have to use this syntax.
268
00:19:49,590 --> 00:19:55,050
We receive the direction in a variable and then set the corresponding wall to true.
269
00:19:58,890 --> 00:20:00,360
Now let's set a wall.
270
00:20:00,360 --> 00:20:04,510
Our main program needs to set the walls, but Ben suggested that we keep our main program
271
00:20:04,510 --> 00:20:07,110
from interacting with the maze spaces directly.
272
00:20:07,110 --> 00:20:08,870
Let's create a method on the maze.
273
00:20:08,870 --> 00:20:11,790
We'll pass in an X and a Y coordinate for the space
274
00:20:11,790 --> 00:20:14,530
as well as the direction for the wall.
275
00:20:15,060 --> 00:20:20,510
To set an east wall here on space 1-1, that method call should look something like this.
276
00:20:27,660 --> 00:20:31,570
Let's add that method to our maze object so we can set this wall.
277
00:20:57,500 --> 00:21:00,810
The maze keeps track of the spaces array, where the walls are,
278
00:21:00,810 --> 00:21:02,790
and where the robot can move.
279
00:21:02,790 --> 00:21:07,490
This method will in turn call the setWall method on the proper space.
280
00:21:16,220 --> 00:21:18,600
Our main program creates a maze object.
281
00:21:18,600 --> 00:21:22,800
Behind the scenes, the maze object creates an array of 35 maze space objects,
282
00:21:22,800 --> 00:21:25,130
but our main program doesn't need to worry about that.
283
00:21:25,130 --> 00:21:28,280
Our main program then adds a wall to the maze.
284
00:21:28,280 --> 00:21:32,050
Again, behind the scenes, the maze adds that wall to a specific maze space,
285
00:21:32,050 --> 00:21:34,740
but our main program doesn't need to worry about that.
286
00:21:34,740 --> 00:21:37,660
Let's refresh the page and take a look in the console.
287
00:21:39,120 --> 00:21:41,250
Hmm. It seems we have an error here.
288
00:21:41,250 --> 00:21:44,710
Mazespace.js, line 11.
289
00:21:44,710 --> 00:21:49,370
I should have removed that dot when I was changing the way we were accessing the property.
290
00:21:49,370 --> 00:21:51,730
Let's give this another try here.
291
00:21:54,290 --> 00:21:57,000
Let's take a look at the spaces.
292
00:21:58,720 --> 00:22:01,980
In element 1-1 here you'll see we've set the east wall to true.
293
00:22:03,450 --> 00:22:06,200
[Step 4. | Adding Validation]
294
00:22:06,200 --> 00:22:10,730
Before we get too much further, we should put some validation in place for the setWall method.
295
00:22:10,730 --> 00:22:14,400
We should make sure that the X and Y coordinates are within the bounds of the maze,
296
00:22:14,400 --> 00:22:18,190
and we should check that the direction is one of the 4 valid directions.
297
00:22:19,340 --> 00:22:20,550
Let's start here.
298
00:22:20,550 --> 00:22:24,490
To check if the X coordinate is in bounds, we should check that it is greater than zero
299
00:22:24,490 --> 00:22:27,480
and that it is less than or equal to the width.
300
00:22:47,630 --> 00:22:50,020
We want to make sure that both conditions are met,
301
00:22:50,020 --> 00:22:52,050
so we're using the ampersands here.
302
00:22:52,050 --> 00:22:57,810
To check if the Y coordinate is in bounds, we should check that it is less than or equal to the height.
303
00:22:59,250 --> 00:23:04,040
We'll keep using ampersands here because we want to check if all of these conditionals are true
304
00:23:04,040 --> 00:23:06,130
before setting the wall.
305
00:23:12,800 --> 00:23:16,860
To check if the direction is valid, we can create an array of valid directions
306
00:23:16,860 --> 00:23:20,290
and make sure that this direction variable is in that array.
307
00:23:29,210 --> 00:23:34,260
The indexOf method on an array finds an element and returns the index of it.
308
00:23:34,260 --> 00:23:39,610
In this array with 4 elements, that index will be between 0 and 3 if the item is found.
309
00:23:45,260 --> 00:23:49,860
If the item is not found, indexOf returns -1.
310
00:23:49,860 --> 00:23:53,760
We can check here if the indexOf method does not return -1.
311
00:23:53,760 --> 00:23:59,010
If not, then we know we've found the direction in the array of valid directions.
312
00:24:01,160 --> 00:24:05,300
If this whole conditional evaluates to true, then we can set the wall.
313
00:24:05,300 --> 00:24:08,170
If not, then we don't need to do anything.
314
00:24:08,170 --> 00:24:13,700
Actually, it might be nice to tell the main program if the call to setWall was successful or not.
315
00:24:13,700 --> 00:24:16,900
Inside the conditional let's return true.
316
00:24:19,910 --> 00:24:24,040
Outside the conditional let's return false if we don't set the wall.
317
00:24:26,070 --> 00:24:29,450
Let's take a look at all of this in the console.
318
00:24:32,090 --> 00:24:36,490
Our next wall is on the north side of 1-3, so let's set that here.
319
00:24:42,070 --> 00:24:46,090
That returns true, which means the wall was set successfully.
320
00:24:46,090 --> 00:24:49,280
Let's take a look at the maze object here.
321
00:24:49,280 --> 00:24:53,480
Under 1-3 you'll see the north wall was set to true.
322
00:24:57,110 --> 00:25:00,100
Let's try to put a wall on an invalid space.
323
00:25:06,720 --> 00:25:10,340
10-10 is out of bounds for this maze, so it returns false.
324
00:25:10,340 --> 00:25:14,530
Let's also try an invalid direction.
325
00:25:19,940 --> 00:25:22,700
That also returns false.
326
00:25:23,440 --> 00:25:27,880
As we keep adding, keeping track of all this in the console might be a bit tough.
327
00:25:27,880 --> 00:25:29,870
I went ahead and coded up an interface for it.
328
00:25:29,870 --> 00:25:32,750
I won't go over how to build the interface in this workshop,
329
00:25:32,750 --> 00:25:35,320
but let me move all the files into place here.
330
00:25:40,920 --> 00:25:44,060
The interface is another object.
331
00:25:44,060 --> 00:25:47,560
Our main program can access it by including the JavaScript file
332
00:25:47,560 --> 00:25:51,240
and then by creating this RobotMazeInterface object.
333
00:25:52,090 --> 00:25:54,490
In the constructor we reference the robot, which we'll add later,
334
00:25:54,490 --> 00:25:57,810
the maze, and a selector for the HTML element.
335
00:25:57,810 --> 00:26:04,080
Then we can call the render method and it puts a visual representation of the maze in that HTML element.
336
00:26:06,840 --> 00:26:11,360
There. We have our maze with one wall, the east side of spot 1-1.
337
00:26:11,360 --> 00:26:17,430
You'll also see an icon for the start space, which looks to me something like a helicopter pad where you might land,
338
00:26:17,430 --> 00:26:22,070
and an icon for the exit space, an X for X marks the spot.
339
00:26:23,670 --> 00:26:28,290
One thing that already troubles me is that we have the list of directions in 2 places.
340
00:26:28,290 --> 00:26:32,040
This array has them and the maze space object has them as properties.
341
00:26:32,040 --> 00:26:36,740
One of the great programming principles is don't repeat yourself, or DRY. [DRY - Don't Repeat Yourself]
342
00:26:36,740 --> 00:26:41,640
An obvious way to violate this principle is to copy and paste the same code in multiple places.
343
00:26:41,640 --> 00:26:45,190
But code like this violates the principle in more subtle ways.
344
00:26:45,190 --> 00:26:48,170
How could we put these directions in one place?
345
00:26:48,170 --> 00:26:49,630
Let's see.
346
00:26:49,630 --> 00:26:53,030
If we put them as a property of the maze, would that work?
347
00:26:53,030 --> 00:26:56,650
Let's try that with an array of valid directions.
348
00:27:17,010 --> 00:27:20,540
Okay. We can easily use that array down here.
349
00:27:28,530 --> 00:27:32,420
But what about in the maze space object? Let's see.
350
00:27:32,420 --> 00:27:35,850
The maze space object constructor creates the 4 properties.
351
00:27:35,850 --> 00:27:41,810
If it could get the 4 valid directions from the maze, we could create these properties dynamically.
352
00:27:41,810 --> 00:27:45,260
But the maze space doesn't really know anything about the maze it's in.
353
00:27:45,260 --> 00:27:47,050
Let's see.
354
00:27:47,050 --> 00:27:51,210
We could pass in the list of valid directions when we create the maze space.
355
00:27:52,000 --> 00:27:53,980
Yeah, let's try that.
356
00:27:59,530 --> 00:28:03,120
We'll set up the maze space constructor to receive these directions.
357
00:28:03,120 --> 00:28:06,380
Then instead of creating these 4 properties here,
358
00:28:06,380 --> 00:28:11,260
let's loop through the array of directions and dynamically create properties for each direction.
359
00:28:31,030 --> 00:28:35,350
Inside the for loop we can go through each element in the array one by one
360
00:28:35,350 --> 00:28:40,630
and create a corresponding property in the maze space object and set its property value to false.
361
00:28:41,990 --> 00:28:46,470
Let's now change the maze object to pass in these directions when it creates a new maze space.
362
00:28:52,730 --> 00:28:56,930
Let's go back to the console and make sure we still have our 4 correct properties.
363
00:29:10,120 --> 00:29:14,880
It still looks good. Each space still has an east, north, south, and west property.
364
00:29:16,200 --> 00:29:19,060
Now, to be honest, when I first tried to code the maze,
365
00:29:19,060 --> 00:29:21,180
I didn't have all this in place.
366
00:29:21,180 --> 00:29:23,260
The 4 directions were repeated all over my code.
367
00:29:23,260 --> 00:29:26,850
That's pretty common in a first pass at programming something.
368
00:29:26,850 --> 00:29:30,640
Experienced programmers know that they have to make the time to iterate on their code,
369
00:29:30,640 --> 00:29:34,550
improving it and eliminating the inefficiencies in duplication.
370
00:29:34,550 --> 00:29:37,790
Often I find I don't really understand the complexity of a problem
371
00:29:37,790 --> 00:29:40,790
until I've tried to implement it all the way through at least once.
372
00:29:40,790 --> 00:29:44,860
You aren't finished when you get your code to produce the right output the first time.
373
00:29:44,860 --> 00:29:46,800
Plan time for revisions.
374
00:29:46,800 --> 00:29:51,320
We also need to validate the direction in our setStart method.
375
00:29:51,320 --> 00:29:53,470
We could copy this code from the setWall method,
376
00:29:53,470 --> 00:29:59,020
but it's probably a good idea here to create a new method that checks if a given direction is valid.
377
00:30:09,770 --> 00:30:12,160
This method would receive a direction.
378
00:30:12,160 --> 00:30:17,690
It would then look for the direction in the array of valid directions, just like we did up here.
379
00:30:24,290 --> 00:30:28,170
This conditional told us if a direction was valid or not.
380
00:30:30,380 --> 00:30:34,880
We can now reference this new isValidDirection method here in the setWall method.
381
00:30:48,610 --> 00:30:52,400
We can reference that same method here in the setStart method.
382
00:30:52,400 --> 00:30:56,710
We only want to set the start X, Y, and orientation properties on the maze
383
00:30:56,710 --> 00:30:59,890
if the orientation is a valid direction.
384
00:31:13,520 --> 00:31:18,810
While we're at it, I suppose we need to validate that the X and Y coordinates are in bounds.
385
00:31:18,810 --> 00:31:22,610
We also wrote some code in the setWall method for that check.
386
00:31:22,610 --> 00:31:27,050
Let's not duplicate that code either, so let's create another new method.
387
00:31:27,050 --> 00:31:30,470
Oh, actually, it looks like I didn't set up that last one correctly here.
388
00:31:30,470 --> 00:31:33,980
Let's see. Set that to a function.
389
00:31:35,420 --> 00:31:40,300
And in our call to the isValidDirection method, we have to type this. first.
390
00:31:40,300 --> 00:31:43,680
This is a method of the maze object.
391
00:31:50,280 --> 00:31:55,170
Let's create an isInBounds method that receives an X and a Y coordinate.
392
00:32:03,610 --> 00:32:07,270
We can use the same conditions from the setWall method.
393
00:32:11,630 --> 00:32:17,810
If all 4 of these conditions evaluate to true, then it's true that the space is in bounds.
394
00:32:17,810 --> 00:32:21,820
We can simply return the result of those conditions.
395
00:32:22,140 --> 00:32:27,240
Let's update the setWall method to call this isInBounds method instead.
396
00:32:35,230 --> 00:32:38,280
Let's also call that method from the setStart method.
397
00:32:43,550 --> 00:32:47,500
If the X and Y coordinates are in bounds and the direction is valid,
398
00:32:47,500 --> 00:32:51,260
then let's set the start X, Y, and orientation properties.
399
00:32:54,020 --> 00:32:57,180
Let's also return true here when we set the properties.
400
00:32:57,180 --> 00:33:02,380
Outside the conditional we can return false to indicate that we did not set the properties.
401
00:33:03,930 --> 00:33:07,110
Let's add the same validation when setting the end point.
402
00:33:09,410 --> 00:33:11,600
Let me show you a slightly different way to do this.
403
00:33:11,600 --> 00:33:14,520
With setStart we checked if the inputs were valid
404
00:33:14,520 --> 00:33:18,120
and then executed the code inside the conditional.
405
00:33:18,120 --> 00:33:23,190
You'll often see the process reversed, with a conditional that first checks if the inputs are invalid.
406
00:33:28,060 --> 00:33:31,000
If they are invalid, then return false.
407
00:33:31,660 --> 00:33:36,720
With this early return method, you can then execute the main code block in the root of the function
408
00:33:36,720 --> 00:33:39,350
instead of nested inside a conditional.
409
00:33:41,550 --> 00:33:44,860
If we get here, then we had valid inputs that got past this trap.
410
00:33:44,860 --> 00:33:47,970
So we can set our values and return true.
411
00:33:54,370 --> 00:33:57,180
Let's go back and take a look in the browser.
412
00:33:58,010 --> 00:34:03,270
Hmm, isInBounds is not defined, line 36.
413
00:34:04,430 --> 00:34:07,900
Oh, I forgot the this. again.
414
00:34:07,900 --> 00:34:10,330
Since isInBounds is a method of the maze object,
415
00:34:10,330 --> 00:34:13,250
you always have to reference the object first.
416
00:34:16,010 --> 00:34:17,480
There we go.
417
00:34:18,170 --> 00:34:22,170
Just for kicks, let's call the setEnd method and move the exit.
418
00:34:24,429 --> 00:34:27,580
Let's move it to the top right corner.
419
00:34:27,580 --> 00:34:30,139
It moved the exit and returned true.
420
00:34:30,139 --> 00:34:35,230
I'll need to call the render method inside the interface object to redraw the page.
421
00:34:35,230 --> 00:34:38,449
You can see now the exit has been moved up to 7-5.
422
00:34:38,449 --> 00:34:42,239
Let's try to set it in an invalid spot.
423
00:34:43,969 --> 00:34:49,880
The setEnd method will return false because 10-10 is an invalid space for the exit to go.
424
00:34:54,900 --> 00:34:56,840
Let's put it back where it was.
425
00:34:56,840 --> 00:35:00,860
I'll hit the up arrow in the console to see a list of previously executed commands,
426
00:35:00,860 --> 00:35:03,590
and I'll call the i.render method again.
427
00:35:03,590 --> 00:35:07,520
You can see the exit has been moved back to 7-1.
428
00:35:07,520 --> 00:35:11,820
All right. Let's now paste in the code for all the rest of the walls.
429
00:35:11,820 --> 00:35:13,170
We've added the one wall already.
430
00:35:13,170 --> 00:35:15,980
I won't make you watch me add the code for all the rest of them;
431
00:35:15,980 --> 00:35:18,720
I'll just paste it in here.
432
00:35:20,340 --> 00:35:23,430
Back in the browser now you can see our full maze.
433
00:35:24,140 --> 00:35:27,610
[Step 5. | Creating the Robot]
434
00:35:28,150 --> 00:35:31,590
I think we've got all the properties of the maze and the maze spaces set.
435
00:35:31,590 --> 00:35:34,140
So let's next work on the robot.
436
00:35:45,880 --> 00:35:52,820
The properties we identified with Ben were an X coordinate, a Y coordinate, an orientation, and a related maze.
437
00:35:57,290 --> 00:36:00,280
When we first create the robot, these should all be set to null.
438
00:36:01,260 --> 00:36:04,750
They will get set when we place the robot in a maze.
439
00:36:18,830 --> 00:36:22,490
Back in our main program let's create the robot.
440
00:36:31,560 --> 00:36:35,580
I'll need to pass the robot into my interface object here.
441
00:36:40,750 --> 00:36:43,190
There's the robot, outside the maze.
442
00:36:43,190 --> 00:36:47,520
Now let's create the robot's setMaze method and place the robot in the maze.
443
00:37:03,210 --> 00:37:07,240
We'll set the robot's maze property equal to that maze object.
444
00:37:14,110 --> 00:37:16,250
We want him to start at the beginning of the maze.
445
00:37:16,250 --> 00:37:19,800
We can get that information from the maze's properties.
446
00:37:35,000 --> 00:37:39,670
We'll also face him in the direction of the maze's starting orientation.
447
00:37:53,210 --> 00:37:56,980
Back in the browser you'll see a new button here added to the interface.
448
00:37:57,850 --> 00:38:02,060
This button corresponds to the setMaze method we just created on the robot.
449
00:38:02,060 --> 00:38:04,280
Clicking it will call that method.
450
00:38:05,260 --> 00:38:11,060
You see that calling this method moves the robot from over here on the side to the starting point of the maze.
451
00:38:11,060 --> 00:38:13,840
The robot is also facing north.
452
00:38:13,840 --> 00:38:17,550
In the console let's pull up the robot object.
453
00:38:18,860 --> 00:38:22,340
You'll see that his X, Y, and orientation properties have been set.
454
00:38:22,340 --> 00:38:25,960
You'll also see that he's related to the maze object.
455
00:38:30,630 --> 00:38:34,440
Talking with Ben, we identified 3 methods that we'll need for movement:
456
00:38:34,440 --> 00:38:37,520
turnLeft, turnRight, and moveForward.
457
00:38:37,520 --> 00:38:40,500
Let's code the 2 turning methods first.
458
00:38:41,160 --> 00:38:46,020
This method will change the robot's orientation from what it is to something else.
459
00:38:46,020 --> 00:38:49,880
The new orientation depends entirely upon the current orientation.
460
00:38:49,880 --> 00:38:54,300
Let's create a list of rights that we can look up using one orientation as the key
461
00:38:54,300 --> 00:38:57,690
and the direction to its right as the value.
462
00:39:03,550 --> 00:39:07,400
If he's facing north, then a right turn would leave him facing east.
463
00:39:14,290 --> 00:39:18,380
If he's facing east, a right turn would leave him facing south.
464
00:39:28,450 --> 00:39:33,920
We can then set his orientation property equal to the direction on his right.
465
00:39:39,010 --> 00:39:40,540
Let's add some validation at the top.
466
00:39:40,540 --> 00:39:45,140
The robot might not be in a maze, so let's make sure he's in one before we turn him right.
467
00:39:55,150 --> 00:39:58,860
If he's not in a maze, we can return false here.
468
00:40:04,780 --> 00:40:10,230
As we did before, let's return true at the end of this method if we turned him right successfully.
469
00:40:10,230 --> 00:40:14,180
We should also check that the robot is facing a valid direction.
470
00:40:16,390 --> 00:40:21,560
If he's not in the maze or if he's not facing a valid direction, we can return false.
471
00:40:32,640 --> 00:40:37,310
We'll use an or here because either of these conditions makes the turnRight method invalid.
472
00:40:37,310 --> 00:40:40,630
The turnLeft method works a lot like turnRight but it's reversed.
473
00:40:40,630 --> 00:40:43,030
I'll go ahead and copy this code here.
474
00:40:43,030 --> 00:40:45,570
Oh. It looks like I did that again.
475
00:40:45,570 --> 00:40:50,020
Here, let me create that as a function properly.
476
00:40:54,000 --> 00:40:59,790
We'll copy this down here, change the function name to turnLeft.
477
00:40:59,790 --> 00:41:04,560
We still want to check if he's not in a maze or if he's facing an invalid direction.
478
00:41:04,560 --> 00:41:08,970
We'll change this list from a list of rights to a list of lefts.
479
00:41:10,010 --> 00:41:13,010
If he's facing north, a left turn would be to the west,
480
00:41:13,010 --> 00:41:16,940
if he was facing west, a left turn would be to the south and so on.
481
00:41:16,940 --> 00:41:21,090
If it is a valid turn left, we want to look up the orientation on his left
482
00:41:21,090 --> 00:41:24,900
and assign that to the robot's orientation property.
483
00:41:25,790 --> 00:41:28,350
Let's go back to the browser.
484
00:41:30,090 --> 00:41:33,440
The interface adds 2 new buttons that correspond to these 2 methods.
485
00:41:33,440 --> 00:41:35,470
We can place the robot in the maze.
486
00:41:35,470 --> 00:41:37,230
Now we can turn him left.
487
00:41:39,240 --> 00:41:41,130
We can also turn him right.
488
00:41:41,370 --> 00:41:43,470
That seems like a good place to take a break.
489
00:41:43,470 --> 00:41:48,430
We have code in place to create our maze object, our maze space objects, and our robot.
490
00:41:48,430 --> 00:41:51,580
We can place the robot in the maze and turn him left or right.
491
00:41:51,580 --> 00:41:56,370
Next time we'll pick up here and write the code to move him through the maze and find the exit automatically.
492
00:41:56,370 --> 00:41:59,000
[Treehouse Workshops]
47319
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.