Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranî)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
[Treehouse Workshops]
[Randy] Hello, my name is Randy.
In today's workshop I'm going to walk you step-by-step
through how I would solve a particular programming problem.
We'll be writing object-oriented JavaScript,
so if you're new to that, this will be a great introduction.
But even if you already know how to write constructors and prototype functions,
this workshop will show you how another programmer, me, thinks and works.
This should show you ways to improve your own workflow and code—
whatever language you're working in.
Hopefully you'll end up thinking more like a programmer.
[Step 1. | The Problem]
Let's start with the problem.
Write a program that represents a robot in this maze
and leads the robot to the exit.
Let's get started.
You might be tempted to open up a text editor and start coding,
but I highly recommend spending some time planning out your code.
I'll often at least sketch out ideas with pencil and paper first.
For a problem like this, I'd probably create a simple model.
Spending a little time moving a physical robot around a maze
can give you a better grasp of the problem
and give you a better chance of finding the solution.
[Step 2. | Identifying Objects]
Let's start by identifying what objects we'll need.
An object is a pretty robust type of variable.
[Object - Type of Variable Containing Properties (Data) and Methods (Behavior)]
It's essentially a collection of variables and functions all wrapped up together.
In the context of an object, these variables are usually called properties
and the functions are usually called methods.
The properties contain information about the particular object
and the methods perform various actions.
I spent some time earlier today with Ben
talking about what objects, properties, and methods we'd need for this program.
Hey, Ben. >>[Ben] Oh. Hey, Randy. What have you got there?
It's a model I built to help me think through a computer programming question.
I'm trying to write a program that represents a robot in a maze.
Do you have a few minutes to chat about it? >>Yeah, sure.
All right. So I assume I'm going to need a robot object and a maze object at the very least.
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.
Okay. Cool. >>So is your maze going to always be this exact same size?
Ooh. I guess it doesn't need to be.
We could write the object so that it could be an arbitrary height or width.
Okay. So you want to set up those 2 properties when you actually code the maze object. >>Okay.
You'll also need a way to identify each space in the maze
so you can track the robot's current position, something like coordinates.
Okay. So we can make the spaces here a grid and then add X and Y coordinates here.
So across the bottom I'll have my X coordinates
and across the side I'll have my Y coordinates.
Okay. So this starting space over here would be X coordinate of 1, Y coordinate of 1?
Okay. That sounds good. >>Okay.
Now I'll need him to move forward.
So I guess when I move him this way, his Y coordinate will increase from 1 to 2. Is that right?
Yeah, that's right.
You'll probably want to move him forward using a method like moveForward or something like that.
You don't want to change his coordinate properties directly from within your main program. >>Okay.
If I move him forward another space, he hits a wall.
I'll need him to go right now. Do I need another method for move right?
Well, you could.
Or maybe you could have him turn right instead and then use that same moveForward method again.
Okay. That makes sense.
Now I need him to turn left here.
Would you maybe have a turn method that I could pass in a parameter of left or right?
You know, I'd probably have 2 different methods—turnLeft and turnRight—
although that doesn't mean that's necessarily the right answer.
Software programming is more of an art than a science sometimes.
If you ask somebody one day, they may give you a different answer than another day.
Got it. All right. So I'll move him forward here.
Hmm. Let's see.
If I turn him left or right, I guess he's going to need to know which way he's facing.
Yeah, yeah. He'll need a property for his orientation.
The moveForward method will need to know which way is forward for the robot.
Okay. And that orientation will probably need to be an absolute direction then.
Yeah. You could use maybe north, south, east, and west.
Okay. That makes sense.
So if he's facing north and he moves forward, the moveForward method
would increase his Y coordinate by 1. >>Yeah.
And if I turn him to face east and he moves forward, that would increase his X coordinate by 1 then.
Precisely. >>Okay. Got it.
Will I need a method to check if there's a wall in his way?
Does he have a blaster? >>No blasters, Ben. He's got to go around the walls of the maze.
Well, if you're moving him manually, then you'll know where to go.
But if you want him to be able to move around the maze by himself,
then yeah, you need to ask the maze a question: Can I move forward?
Yeah. That is the plan eventually.
I guess that will need to be a method then. What parameters? Let's see.
I guess I could ask the maze if he could move forward from his X and Y coordinate and which direction he's moving.
Yeah, exactly. >>Okay.
But we don't have the walls or the location of the walls stored anywhere.
Where would we store those?
Let's see. Each space in the maze is mapped to X and Y coordinates.
So maybe we could have a 2-dimensional array of spaces.
That makes sense. The maze would then have that 2D array as one of its properties.
What about the walls?
Each space has 4 possible spots for walls.
So I guess a space would need to be an object with 4 properties.
Okay. So then I could ask the maze something like, does space 4-4 have a wall on its south side?
Yeah. >>So I'll need an addWall method then somewhere, and I can pass in an X and Y coordinate and a direction.
I think you'll want that on the maze.
The space objects can be internal to the maze object,
but your main program is only going to call methods from the robot object or the maze object.
Okay. That makes sense.
So I'll call the addWall method when I instantiate the maze.
I suppose it's worth mentioning that the north wall of this space is the same as the south wall of that space.
Is that going to be a problem?
You could automatically add a wall to one spot whenever you add one on the other spot,
or you could instead act like there are 2 separate spots for walls,
one on the north side of this space and one on the south side of that space.
So you'd have to check both spots in the canMoveForward method for the robot
to make sure there's not a wall in either of them.
So here the canMoveForward method would have to check if space 4-4 had a south wall
or if space 4-3 had a north wall. >>I like that.
I'd like to keep the logic about shared walls in the canMoveForward method.
I'd like the spaces to stay independent of each other.
They don't even really know where they are on the maze,
and it would be nice if someday I could shuffle them around
like in the board game The aMAZEing Labyrinth.
It would definitely be better if each wall was on a particular space.
Yeah. Seems reasonable.
All right. So what else am I missing?
The robot asks the maze a question: Can I move forward?
So we need to establish a relationship between the robot and the maze that it's in. >>Okay.
We could store that as a property of the maze object then
with a reference to the robot object.
Theoretically, a maze could have multiple robots in it at one time,
but a robot is only going to be in one maze.
So instead, we should probably store that as a property of the robot object.
Okay. That makes sense. Then we'll need a method to place the robot in the maze.
I suppose the maze needs to know its starting coordinates,
and it can pass that back to the robot so we'll know where to set him when we start.
Yeah, and the maze should probably know its ending coordinates too,
so when the robot gets over here he knows he's done.
Cool. I think that covers what I need to know.
I'm going to head back and code up these objects. Thanks a lot, Ben.
Sure. Have fun.
[Step 3. | Creating the Maze]
I feel like we have a good grasp of the problem now.
So let's start writing some code.
We could code this program in many different languages.
I'm going to use JavaScript because most of you will have a browser installed.
We'll be editing JavaScript and HTML files
as well as interacting with our JavaScript objects through the console.
I'll be using Google Chrome on a Mac,
so to open up the console I'll press Command-Option-I.
I'll post some instructions to this workshop for accessing the console
in other browsers and other operating systems.
After talking with Ben, we determined that we'd need 3 types of objects:
a robot, a maze, and an array of maze spaces.
Let's create 3 JavaScript files, one for each of the objects.
Let's start with the maze object.
The first thing to put in every JavaScript file is the "use strict" declaration.
This causes newer browsers to run JavaScript code in a stricter context,
which can help us prevent common mistakes that can be hard to troubleshoot.
I'll link to an article on this by John Resig. [ECMAScript 5 Strict Mode - http://trhou.se/usestrict]
To create an object definition, you define a constructor function.
You set the properties of an object using the keyword "this."
That keyword references the current context.
Inside the constructor function, that context is the object itself.
So this will create a new property in the maze object named width and assign it a value of 7.
We'll also add a property for height.
Before we get much further, let's get this JavaScript file in the browser.
I've created an HTML document with some basic structure already.
I'll refer to the code in this HTML document as our main program.
Most of the code we'll write will be in our object definitions,
and then we'll have a little bit of code in the main program
that creates the objects and interacts with them.
Let me paste in the code here to include the 3 JavaScript files we'll need at the head of the document.
Let's load this page up in the browser.
The JavaScript code we've written defines what a maze object would look like,
but I haven't actually created a maze object yet.
If you've worked with objects before, you might be familiar with the concept of a class.
Most web languages have classes that define the properties and methods available in an object.
JavaScript is a little different, but this constructor function works a bit like a class.
We can call that function in the console to create a real maze object.
This creates a new maze object and loads it into the variable M.
In the console you can just type a variable name and it will display all the information about that variable.
The console tells us that we have a maze object.
We can expand it to see the properties of the object.
So far we have a height and a width.
Ben suggested we allow mazes to have an arbitrary height and width.
Once you create a maze, there's no need to change it,
but we should allow programs to call the constructor and create mazes of different sizes.
We can add arguments to our constructor to handle that.
The first argument will be for the width.
Let's just always keep the X coordinate and the horizontal access first in this list of arguments.
The second will be for the height.
Instead of 5 and 7, let's load the values from these arguments into our properties.
Let's refresh the page and create the maze object again.
This time we'll specify the height and the width.
Any code we run in the console gets executed just that one time.
We lose it when we refresh the page.
We'll use the console to explore the objects we create
and to troubleshoot some different scenarios.
But we want our program to create a maze object each time we load it.
Let's put that code in the HTML file.
If we refresh the page now, the maze object should be created.
We can type M and see that it exists.
Let's add the other properties to our maze.
We could add more arguments to the constructor,
but I feel like these properties could be set after the maze is created.
Let me paste in some code here to create the next 5 properties:
the X and Y coordinates of the start space, the direction the robot should be facing when he starts—
the start orientation—and the X and Y coordinates of the exit or the end point of the maze.
Our main program could set these properties directly,
something like this.
You can see how that sets the start X.
But it's a better practice to provide what are known as setter methods.
This allows you to provide validation before the properties get set.
It would be a good idea with this property to make sure it's actually within the bounds of the maze.
You can create a method in a JavaScript object by adding a function to its prototype property.
It can be a little confusing, especially if you've worked with other languages that have classes.
JavaScript doesn't have classes exactly,
but this code block defines a method called setStart that will be available in all of our maze objects.
Technically speaking, the robot would start outside of the maze,
but it will be easier to track if we assume he starts on a particular space.
We'll pass into this method an X and Y coordinate as well as a starting orientation.
When we put a robot in the maze later, this will tell us what its starting X and Y coordinates should be
and which way he should be facing.
We can set the maze's properties inside here.
Once again, the "this" keyword will refer to the current object.
Next we'll create a similar method for the exit point.
This method will receive 2 arguments: the X and Y coordinate of the exit.
Once again, the exit is technically outside of the maze,
but it will be easier if we think of it as one of the spaces at the end.
Let's go back to our main program.
We can call these 2 setter methods to set all 5 of these properties.
Once again, let's take a look at this in the browser.
Looking at our maze object, you can see the start and the end points have been set
as well as the starting orientation.
The last property we need for the maze object is the 2-dimensional array of spaces.
When the maze is constructed, we'll have a height and a width.
Based on that, we'll need to create our array.
This maze is 7 by 5, so we'll have 35 spaces.
I'll first create an empty array called spaces.
I'll keep using the X coordinate first, and I'll write a for loop that goes through each column
and creates an array element for it.
This for loop goes through each column and creates an array element for it.
That array element will be another empty array.
At this point we should have an array with 7 elements,
each element with an empty array inside of that.
For each column we'll also loop through each Y coordinate and add an element to the array.
This for loop will add one element to the array for each space in the column.
Let's set this to a placeholder value for now,
maybe a text representation of the coordinates.
Let's take a look at all this in the browser.
We're creating a maze object, and let's take a look at it.
You can see now we have an array of spaces.
This spaces array has 8 elements, one for each column and also one that specifies the length.
Inside each column we have another array with 6 spaces,
one for each of the 5 rows and another one that sets its length.
Each element at the lower level here is a string with the coordinates.
We really want each element in the array to be another object, a maze space object.
Let's work on that object definition next.
Each maze space object should have only 4 properties,
one for each side of the space that could contain a wall.
When we first create the object, let's give these properties a value of false.
We can set walls and change them to true a little later on.
Let's now change our maze object to create an array of maze space objects.
In the browser you can now see that each of these elements in the array is now a maze space object,
no longer just a piece of text with the coordinates.
Let's create a method we can use for setting a wall.
We could create 4 methods, one for each wall spot,
but I'd rather create one function and pass it an argument.
This one argument should be which spot—north, south, east, or west—should get the wall.
If we know a property's name, we can set it like this.
We could also use this syntax.
When we have the name of the property in a variable, then we actually have to use this syntax.
We receive the direction in a variable and then set the corresponding wall to true.
Now let's set a wall.
Our main program needs to set the walls, but Ben suggested that we keep our main program
from interacting with the maze spaces directly.
Let's create a method on the maze.
We'll pass in an X and a Y coordinate for the space
as well as the direction for the wall.
To set an east wall here on space 1-1, that method call should look something like this.
Let's add that method to our maze object so we can set this wall.
The maze keeps track of the spaces array, where the walls are,
and where the robot can move.
This method will in turn call the setWall method on the proper space.
Our main program creates a maze object.
Behind the scenes, the maze object creates an array of 35 maze space objects,
but our main program doesn't need to worry about that.
Our main program then adds a wall to the maze.
Again, behind the scenes, the maze adds that wall to a specific maze space,
but our main program doesn't need to worry about that.
Let's refresh the page and take a look in the console.
Hmm. It seems we have an error here.
Mazespace.js, line 11.
I should have removed that dot when I was changing the way we were accessing the property.
Let's give this another try here.
Let's take a look at the spaces.
In element 1-1 here you'll see we've set the east wall to true.
[Step 4. | Adding Validation]
Before we get too much further, we should put some validation in place for the setWall method.
We should make sure that the X and Y coordinates are within the bounds of the maze,
and we should check that the direction is one of the 4 valid directions.
Let's start here.
To check if the X coordinate is in bounds, we should check that it is greater than zero
and that it is less than or equal to the width.
We want to make sure that both conditions are met,
so we're using the ampersands here.
To check if the Y coordinate is in bounds, we should check that it is less than or equal to the height.
We'll keep using ampersands here because we want to check if all of these conditionals are true
before setting the wall.
To check if the direction is valid, we can create an array of valid directions
and make sure that this direction variable is in that array.
The indexOf method on an array finds an element and returns the index of it.
In this array with 4 elements, that index will be between 0 and 3 if the item is found.
If the item is not found, indexOf returns -1.
We can check here if the indexOf method does not return -1.
If not, then we know we've found the direction in the array of valid directions.
If this whole conditional evaluates to true, then we can set the wall.
If not, then we don't need to do anything.
Actually, it might be nice to tell the main program if the call to setWall was successful or not.
Inside the conditional let's return true.
Outside the conditional let's return false if we don't set the wall.
Let's take a look at all of this in the console.
Our next wall is on the north side of 1-3, so let's set that here.
That returns true, which means the wall was set successfully.
Let's take a look at the maze object here.
Under 1-3 you'll see the north wall was set to true.
Let's try to put a wall on an invalid space.
10-10 is out of bounds for this maze, so it returns false.
Let's also try an invalid direction.
That also returns false.
As we keep adding, keeping track of all this in the console might be a bit tough.
I went ahead and coded up an interface for it.
I won't go over how to build the interface in this workshop,
but let me move all the files into place here.
The interface is another object.
Our main program can access it by including the JavaScript file
and then by creating this RobotMazeInterface object.
In the constructor we reference the robot, which we'll add later,
the maze, and a selector for the HTML element.
Then we can call the render method and it puts a visual representation of the maze in that HTML element.
There. We have our maze with one wall, the east side of spot 1-1.
You'll also see an icon for the start space, which looks to me something like a helicopter pad where you might land,
and an icon for the exit space, an X for X marks the spot.
One thing that already troubles me is that we have the list of directions in 2 places.
This array has them and the maze space object has them as properties.
One of the great programming principles is don't repeat yourself, or DRY. [DRY - Don't Repeat Yourself]
An obvious way to violate this principle is to copy and paste the same code in multiple places.
But code like this violates the principle in more subtle ways.
How could we put these directions in one place?
Let's see.
If we put them as a property of the maze, would that work?
Let's try that with an array of valid directions.
Okay. We can easily use that array down here.
But what about in the maze space object? Let's see.
The maze space object constructor creates the 4 properties.
If it could get the 4 valid directions from the maze, we could create these properties dynamically.
But the maze space doesn't really know anything about the maze it's in.
Let's see.
We could pass in the list of valid directions when we create the maze space.
Yeah, let's try that.
We'll set up the maze space constructor to receive these directions.
Then instead of creating these 4 properties here,
let's loop through the array of directions and dynamically create properties for each direction.
Inside the for loop we can go through each element in the array one by one
and create a corresponding property in the maze space object and set its property value to false.
Let's now change the maze object to pass in these directions when it creates a new maze space.
Let's go back to the console and make sure we still have our 4 correct properties.
It still looks good. Each space still has an east, north, south, and west property.
Now, to be honest, when I first tried to code the maze,
I didn't have all this in place.
The 4 directions were repeated all over my code.
That's pretty common in a first pass at programming something.
Experienced programmers know that they have to make the time to iterate on their code,
improving it and eliminating the inefficiencies in duplication.
Often I find I don't really understand the complexity of a problem
until I've tried to implement it all the way through at least once.
You aren't finished when you get your code to produce the right output the first time.
Plan time for revisions.
We also need to validate the direction in our setStart method.
We could copy this code from the setWall method,
but it's probably a good idea here to create a new method that checks if a given direction is valid.
This method would receive a direction.
It would then look for the direction in the array of valid directions, just like we did up here.
This conditional told us if a direction was valid or not.
We can now reference this new isValidDirection method here in the setWall method.
We can reference that same method here in the setStart method.
We only want to set the start X, Y, and orientation properties on the maze
if the orientation is a valid direction.
While we're at it, I suppose we need to validate that the X and Y coordinates are in bounds.
We also wrote some code in the setWall method for that check.
Let's not duplicate that code either, so let's create another new method.
Oh, actually, it looks like I didn't set up that last one correctly here.
Let's see. Set that to a function.
And in our call to the isValidDirection method, we have to type this. first.
This is a method of the maze object.
Let's create an isInBounds method that receives an X and a Y coordinate.
We can use the same conditions from the setWall method.
If all 4 of these conditions evaluate to true, then it's true that the space is in bounds.
We can simply return the result of those conditions.
Let's update the setWall method to call this isInBounds method instead.
Let's also call that method from the setStart method.
If the X and Y coordinates are in bounds and the direction is valid,
then let's set the start X, Y, and orientation properties.
Let's also return true here when we set the properties.
Outside the conditional we can return false to indicate that we did not set the properties.
Let's add the same validation when setting the end point.
Let me show you a slightly different way to do this.
With setStart we checked if the inputs were valid
and then executed the code inside the conditional.
You'll often see the process reversed, with a conditional that first checks if the inputs are invalid.
If they are invalid, then return false.
With this early return method, you can then execute the main code block in the root of the function
instead of nested inside a conditional.
If we get here, then we had valid inputs that got past this trap.
So we can set our values and return true.
Let's go back and take a look in the browser.
Hmm, isInBounds is not defined, line 36.
Oh, I forgot the this. again.
Since isInBounds is a method of the maze object,
you always have to reference the object first.
There we go.
Just for kicks, let's call the setEnd method and move the exit.
Let's move it to the top right corner.
It moved the exit and returned true.
I'll need to call the render method inside the interface object to redraw the page.
You can see now the exit has been moved up to 7-5.
Let's try to set it in an invalid spot.
The setEnd method will return false because 10-10 is an invalid space for the exit to go.
Let's put it back where it was.
I'll hit the up arrow in the console to see a list of previously executed commands,
and I'll call the i.render method again.
You can see the exit has been moved back to 7-1.
All right. Let's now paste in the code for all the rest of the walls.
We've added the one wall already.
I won't make you watch me add the code for all the rest of them;
I'll just paste it in here.
Back in the browser now you can see our full maze.
[Step 5. | Creating the Robot]
I think we've got all the properties of the maze and the maze spaces set.
So let's next work on the robot.
The properties we identified with Ben were an X coordinate, a Y coordinate, an orientation, and a related maze.
When we first create the robot, these should all be set to null.
They will get set when we place the robot in a maze.
Back in our main program let's create the robot.
I'll need to pass the robot into my interface object here.
There's the robot, outside the maze.
Now let's create the robot's setMaze method and place the robot in the maze.
We'll set the robot's maze property equal to that maze object.
We want him to start at the beginning of the maze.
We can get that information from the maze's properties.
We'll also face him in the direction of the maze's starting orientation.
Back in the browser you'll see a new button here added to the interface.
This button corresponds to the setMaze method we just created on the robot.
Clicking it will call that method.
You see that calling this method moves the robot from over here on the side to the starting point of the maze.
The robot is also facing north.
In the console let's pull up the robot object.
You'll see that his X, Y, and orientation properties have been set.
You'll also see that he's related to the maze object.
Talking with Ben, we identified 3 methods that we'll need for movement:
turnLeft, turnRight, and moveForward.
Let's code the 2 turning methods first.
This method will change the robot's orientation from what it is to something else.
The new orientation depends entirely upon the current orientation.
Let's create a list of rights that we can look up using one orientation as the key
and the direction to its right as the value.
If he's facing north, then a right turn would leave him facing east.
If he's facing east, a right turn would leave him facing south.
We can then set his orientation property equal to the direction on his right.
Let's add some validation at the top.
The robot might not be in a maze, so let's make sure he's in one before we turn him right.
If he's not in a maze, we can return false here.
As we did before, let's return true at the end of this method if we turned him right successfully.
We should also check that the robot is facing a valid direction.
If he's not in the maze or if he's not facing a valid direction, we can return false.
We'll use an or here because either of these conditions makes the turnRight method invalid.
The turnLeft method works a lot like turnRight but it's reversed.
I'll go ahead and copy this code here.
Oh. It looks like I did that again.
Here, let me create that as a function properly.
We'll copy this down here, change the function name to turnLeft.
We still want to check if he's not in a maze or if he's facing an invalid direction.
We'll change this list from a list of rights to a list of lefts.
If he's facing north, a left turn would be to the west,
if he was facing west, a left turn would be to the south and so on.
If it is a valid turn left, we want to look up the orientation on his left
and assign that to the robot's orientation property.
Let's go back to the browser.
The interface adds 2 new buttons that correspond to these 2 methods.
We can place the robot in the maze.
Now we can turn him left.
We can also turn him right.
That seems like a good place to take a break.
We have code in place to create our maze object, our maze space objects, and our robot.
We can place the robot in the maze and turn him left or right.
Next time we'll pick up here and write the code to move him through the maze and find the exit automatically.
[Treehouse Workshops]
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.