Coding Challenge #121.2: Logo Interpreter Part 2

– Hello, welcome to Coding Challenge: Logo Interpreter, part 2, I’m a little bit scared of this (clears throat) All right, so what’s going on? Where are we, why am I here? You might remember me from Logo Interpreter Coding Challenge number 121, look that’s me, I’m almost wearing the same clothes This is a challenge where I looked at the Logo programming language, a language from designed in 1967, turtle graphics, you might be familiar with, I talked a bit more about it in that video I encourage you to read about the history and also to check out the Logo Foundation which is the foundation that supports a variety of wonderful initiatives, including Scratch Day So check that out but what I did was I made this Logo interpreter that is able to interpret simple commands like forward 60, left 90, forward 100 So while this implementation of Logo interpreting these Logo commands like forward, left, forward, et cetera works, it’s missing crucial components And so there are many commands in Logo and I implemented pen up, pen down, some of these, but one of the most important ones that I did not implement is repeat So this is a tutorial from a Brown University page about the history of Logo that I’ll also link to in this video’s description, but what I want to attempt to do is add the repeat functionality which you would think would be a really simple thing, but it’s a little bit more complicated than, well, there are some simple ways probably to do it, and I will point out, in fact, that when I posted this code, 16 pull requests came in with suggestions and techniques for how to implement repeat, and I would encourage you to go check all these out I want to highlight one of them that was pretty interesting to me, I’m going to look for it, Regex implementation, is this the one I’m looking for? Yeah, this one, oh yeah, I love this, which is just basically using a regular expression to search for the repeat command and then just replace the repeat command in the string itself with what’s the thing to repeat multiple times So kind of like unrolling the string recursively with a regular expression Pretty wild implementation I’m not going to use that one, I’m going to try to spin up my own So this is my idea So, one thing that I think will help is object oriented programming What if I have this idea of a command class? So I make this idea of a command class and it has the name of the command That could be forward, left, picks the pen up, et cetera It has an argument so if the command is forward, maybe I would have an argument like 100 And by the way, the command could be repeat and I know I’m about to leave your view here Repeat and then the argument could be a number also ’cause you’re going to repeat something a certain number of times So you have this idea of a command class And then maybe what I think would be useful is to create a parser object And actually, instead of using split, so I used split as a way of looking at the Logo instructions and just splitting it into a big array, but I think what I want to try to do in the most absurd thing ever is just actually step through the string one character at a time so that I have the idea of a parser is keeping track of a index So the parser is always has basically a pointer into the command and can step through and if it finds repeat, it can then pull out a chunk, it can do all sorts of stuff So, if what I’m kind of thinking about here is this idea of a command A command could just be a thing that you execute with an argument but if the command is repeat, then it could also have a list of, it could have an array of its own commands, that those are the things you repeat And then inside of this array, there could be a command that is a repeat command so it could nested and recursive So this is my idea, I have not actually, I thought about this quite a bit and probably helped by looking at everybody’s pull requests so I don’t know to what extent this is an original idea or it just came from suggestions, but it through osmosis, my brain has come up with this idea but I have not tried to implement it so what you are about to watch is me actually trying to implement this for the first time, and it might be a terrible idea and things will go wrong and you’ll probably notice this video is 342 hours long, but if you want to stick with me, here we go Okay, so let me go to the code I’m going to keep the code that I had before, I’m going to add a new JavaScript file called parser Maybe it should be interpreter, I don’t know why I’m going to call it parser Parser.js, I’m going to write a parser class and the idea is that when you create the parser, you give it some text So this is the full text that needs to parse

and then also it has an index which starts at 0, okay And, one of the functions that I would have here is nextToken so it could maybe look and sort of find the next token or something in this text by stepping through it with the index, okay That’s what I’m thinking about Now, I am also going to then create another JavaScript class called command, and this would be, this is what I’m talking about, it would have a name and an argument And then it could also have potentially subcommands Recursively, a command could also include a list of other commands So this is my idea, now, let’s go to sketch.js and basically, this go turtle function, I’m actually going to just basically take out what I did before ’cause I don’t think this, I’m not going to use split anymore and I’m not going to have my own index here I’m going to say let parser = new parser with that code So let’s just for example say console.log and parser.nextToken So let me at least see if I can get parser.nextToken to work, and so And this should probably return the token so return “test” So if I just run this now, parser’s not defined, right, I always forget this I’ve added a bunch of new JavaScript classes so I want to make them separate, reference those files here Probably should get into bundling and building and all that sort of stuff at some point Parser and command Let me go back to sketch, refresh, okay, so, great, I see test there I have got my command but I didn’t really get the token What I need to do is here, I really need to say all right, so I’m going to step through the text one character at a time So what I mean by that is I’m going to say let char = this.text charAt this.index, okay So, while the character is not a, I guess I could use a regular expression here So, I want to Let me just say, let me just do it this way for a second While the character is not a space What I want to do is I’m going to start with an empty token, and I am going to say, oh I don’t need a While the character is not a space, token += the character, character = this.text.charAt, charAt ++this.index So what’s going on here? The idea here and, again, I could use regular expression and substring but I’m trying to do this in a very manual way to understand it What I’m doing is I’m saying let me look at the first character and as long as that character is not a space, I’m going to add that character to my token and then look at the next character And this is basically, remember, this is something I covered in the first part of the challenge This.index ++ this.index is increasing the index by 1 and giving back that new value So now if I say return token, let’s see what happens Refresh This text chatAt, charAt, a little typo there There we go, look (bell dings) I got the first token, that’s great Now, what if I now want to say here next token? Ooh, it got a space, so look at this, a space is not a valid token so what I can actually do here, back into parser, is I can actually say if, if char = a space, return next, increase the index, go to the next one and return this.nextToken So this is a way of basically skipping and, again, this is definitely a clear example of I’ll refactor this later, I need a little theme music there for that, but, this is a start, okay, so this is basically saying ignore the space and so now, we can say I’ve got forward 60, but here’s what I want to do really

Here, I want to say And let me actually, let me use a regular expression here So I’m going to say, there’s a category of command which is like a movement command, forward, backward, right, left, so I’m going to say that would be a regular expression that is forward or backward, this is fb followed by d or left or right followed by a t and probably, I should probably also make sure it’s the full string, so put this beginning and end So now I could say let token = parser.nextToken if movement test(token) so if it’s a movement command, then create a new command with token and token and parser.nextToken Right, ’cause I think I said the command is, I said the name of the command and the argument and the argument always comes next So, again, I’m not doing a lot of error checking for people making mistakes in their Logo code but we’ll get to that later, I suppose Okay, I’m setting myself up for hopefully being able to do a repeat Where am I here? So let’s just see and actually let’s make an array of commands, I mean I might want to put all the commands into an array or I might want to process them one at a time, there’s various ways of doing this but let’s actually put it into an array right now, I think that’ll be helpful Oops, okay, so let’s see and now let’s look at commands Okay, refresh, look at that, I’ve got a command with arguments, the name is forward, the argument is 60 and it doesn’t have any subcommands because it’s not a repeat Woo, I like this so far So now, hmm, this is where I’m going to get into trouble Let’s do something like while parser is not empty, while parser has remainingTokens, I don’t know, come up with a better name for that While parser has remainingTokens, keep doing this So what does it mean here in the parser to say remeainingTokens, well, on the one hand, I can just return this.index is less than this.text.length because if the index has moved past the end of the text, then there’s nothing left Hmm I’m wondering if this is going, I bet you I’m going to get an infinite loop here but let’s just give it a try anyway Yes So I have an infinite loop, I could tell because everything went blank, this is just there, so I’m going to actually, unfortunately, have to kill this page, whoops, ah Next token, there are situations where if it hits the bracket, bracket is not a space, bracket is not a So, ah, I guess what I could do here is if char, I mean this is really terrible or if it’s one of these brackets, then, return, then also go up by an index and return that character So this definitely accounts for another thing So, again, this could be condensed and I could maybe use some more clever ways of doing this but if it’s a space, ignore If it’s a bracket, whoops, if it’s And actually, I’m going to want to do something for it’s a repeat, but anyway, if it’s a bracket, send that back And, otherwise, accumulate until a space or bracket, but, okay, there’s so many problems with this but I have to build it one step at a time If you’re willing to stick with me and keep watching this video, then more power to you, okay Let’s see if I manage to not have an infinite loop Still infinite loop While character’s not a space, keep going up and this could get stuck Or, while character space and this.index is less than this.text.length So I’ve also got to check to make sure I’m not hitting the end, oh there we go, okay (laughing) All right, so that was definitely the problem Now at least my infinite loop is gone Let’s look at these commands So forward 60, right 120, so this is good This is what I wanted it to be

But I need to be able to account for the repeat So this is good, this is giving me a list of commands but what if the token that I get back, now I need to deal with repeat So, if it is a movement, I should also have something for a pen command which would really just be matching a p at the beginning, right, any of the pen commands match just a p so I should say else if pen test token, so a pen command is just a command with just the token, no argument And now I could, in theory, if I added a pen up command, we would see pen up is in there with no argument but that’s fine, so that’s good, so this would work, oh why isn’t it, oh it’s not drawing anything ’cause I’m not bothering to draw, sorry, I keep opening up terminal by accident Okay, so I have now written a parser that can go from token to token and can create commands and knows how to handle any movement command or any pen command Oh and this.remaining tokens Ah, yes, great suggestion from the chat Abdillah Baghat suggests that here, I like this suggestion, that this is already a test which is this.remaining, remaining tokens, ’cause I have that function, right, that already tests that here Great, okay, still working, all right Now it’s time to deal with the repeat So I need to handle the repeat in a very unique way and this is where I’m really going to get lost So repeat is just matching the repeat command So this could be a regular expression here So else if repeat test token So now, what if I get a repeat command? Then what I need to do is say, so let command is a new command with the token Oh, and also the next token So I first get the number, then what I need to do is I need to pull out, hmm, I need to pull out everything within the brackets so then what I want to say is the to repeat is the parser, get repeat So I want to write a new function that then in the parser looks for that starting bracket, looks for the end bracket and just gives everything back (claps), okay So, in the parser now, I’m going to say getRepeat So I should first, basically find that first bracket So I want to, in theory, there could be spaces, so char = this.text, this is really hard, the way that I’ve gotten to this text.charAt this.index I should probably put that in a function and then if while char, I guess I could say, you know what, I could do this While this is not equal to this opening bracket, while it’s not equal to this opening bracket, oh ++, right, I want to go ahead to the next one but stick where I am, then just keep going, and, and I guess need to make sure, and this.remainingTokens Now, I have found Basically I have found I’m going to say index, I’m just going to say this.index This should console.log where the index is So I need to put a repeat in here So let’s start with something really simple like repeat three this And let’s refresh, all right It got forward, it got right

and it got, ooh weird, and it said 10 Is that 0 1 2 3 4 5 6 7 8 9, oh great, so now it’s at index 10, oh, perfect So now, ah, I love this Okay, so Commands push So this is actually a function, I got to make a subparser of the sub thing Ooh Ah, yikes, I mean the recursion aspect of this, right, because a repeat could have a repeat inside of it If a repeat couldn’t have a repeat inside of it, I’d kind of be done, maybe I should do that first This is going to be a really long video I know I keep saying that but it just is So now what I want is to find the last one So Let’s start = this.index Let end, now I need to do this again, move along here, and let end = this.index and then return this.text substring start, end Let’s see if this does what I think it should do And then, let’s see if it does what I think it should do Okay Command, token, whew, parser, nextToken, let’s just console.log this Console.log to repeat, okay Yes, oh okay, look at that, this is the thing to repeat and the command is the repeat, perfect, ah, yes, okay, but minus one, minus one, minus one So here, in parser, end minus one ’cause the index is actually the index past that final bracket So now, there we go The command is repeat, it’s named repeat and now I just need to fill the commands with an array of the stuff that’s inside of that to repeat So this, ah, okay, I have an idea now This function Parse, let commands I’m trying to think here, parse I need to write a recursive function now where I come back and do this, then for those subcommands, okay so let commands equal, this is going to be weird, let me just try to do parse, parser.parse, is this what I want to let commands = parser.parse, should all this be in the parser? And then, this would, I don’t know about putting this in the parser If this is in the parser, parse, oh this is hard Okay While this remaining tokens, next, so this I’m not so sure about putting this in here but I’m going to So everywhere I said parser, I’m now saying this And then, I am saying let commands is be an array and then basically, at the end here, I’m going to say return commands, just give me a second, I’m not going to do the recursion yet So let’s see, let’s see what happens here And then in Sketch, let commands = parser.parse, console.log commands This is crazy All right, sketch All right, that’s good, that’s good, hold on, hold on, hold on, I’m thinking, I’m thinking, oh there’s a console.log here Where is there extra console.log? Uh, it’s 25 and 31 Oh I have it twice, okay Okay, so now, okay, okay, now, now, this is the hard part All right, so I have this to repeat and then what I want to say is command.commands

equals (gasps) parse, this.parse to, this is what I want to do, to repeat Okay So this isn’t exactly going to work, this is the idea of what I want to do But it’s not right yet So close, it’s not right because the parse command inside, it’s working with this particular, the sort of global block of text Maybe it makes more sense for that not to be, oh wait, no, no, no, I think I have an idea (gasps) All I have to do is make a new parser here With the to repeat stuff and then that equals parser.parse, right? Because then it would have, I think this might work Could this really work? Let’s think about this I’m basically saying hey, make a parser with all this code, parse it and give me the commands The parser is going to do that and return that array of commands but internally, oh, wait, wait, wait, wait, yeah, it’s going to make I think this, I mean, it’s so hard to speak this Let’s run it, let’s run it This is going to produce a lot of errors or an infinite loop, for sure (drum roll) (buzzer buzzing) Cannot read property length of undefined parser.js line 7 (vocalizing) This.text, oh whoops, I took that out when I was messing around with this idea Okay, not playing the drums but okay, command, repeat, ah! Ohhh (clapping) I think that worked, okay, so I think this is a case where I was figuring it out, trying to explain it, all at the same time but I don’t know that I did that super successfully so let me take a minute to try to unpack what just happened Okay, and the idea here is that I have something like this, repeat three, forward 60, can you see that? Yes, so the parser finds the first token and makes a command repeat with three Then the parser, because it found a repeat, asks for this as basically a substring and it makes a new parser object with only this So the first parser object started with everything, the new parser object just works on this and makes a command So I really should put this in a json way So the idea here, and let’s add some other stuff The way that it should work, imagine if this had forward 60 here So the idea is that I would have an array with commands and the first command would have name forward, argument 60, then the next command would have name, right, repeat, argument three but it knows it’s a repeat, it then goes and makes a parser for this and the same way that this is a big array, the parser now works on this to put it in an array here with objects like forward 60, et cetera So in theory, this could even have another repeat inside and that repeat would be in this array with its own subcommands Hopefully that helps a little bit more But let’s actually test this theory So let me go now to, let me, I’m afraid to type stuff in here and break so I think what I’m going to do is just, so let’s start with forward 60, repeat, let’s just start with that first So we can see we got a forward 60, no commands and a second command that says repeat three with two other commands Okay

Now what if I then put in here, let me do it out here ’cause, what if I do another repeat forward, oh so repeat four, forward 10 Let’s look at this Okay, so There’s still forward 60, then there’s a repeat and the repeat argument is three, there are three commands, one of which is a repeat which has a subcommands in it (bell dings) (train whistle) All right, I think this works, I mean I’m sure this needs error handling but the basic idea is actually working, wow this is very exciting to me All right, so what I need to do now is to follow the instructions This should be, in theory, this should be the easy part So now that I have this commands, I can just say for let command of commands and now I forgot how I did this in the first place ’cause I have this, oh boy, this is bad, I have a, I have this dictionary thing that I made to execute these different functions, hmm, so what do I want to do, this is called commands, so I’m going to call this command dictionary Well I’ll just call this commands, command list Command list, it’s not a list Command lookup Command look up, boy that’s a awkward variable name So what I want to do is now I want to say the name is command.name and the argument is command.argument and then I’m going to say, I have to figure out if it’s a repeat If name = repeat, then for let i = 0, i is less than arg, i++, right, ’cause I want to do whatever is, and then I’m going to go through its commands I guess I could say, oh boy, oh, ah, I need another recursive function to traverse it Aah Let me go back to something simpler Without anything nested Forward 60, repeat three times, okay so this idea works But This needs to be a function, I need more recursion or maybe I should be just doing this as I’m going So I’m going to call this execute and executes a list of commands So if you execute a list of commands and then you get the repeat, you need to execute, command.commands Right, so in other words, I’m looking at the commands If it is a repeat, then I want to execute the sub commands that are in these sub commands list a certain number of times Otherwise, I can now say basically what I did in the very first version of this challenge which is to do what? Command list name arg So the idea is I’m looking up the command list, in the command list, by the name with an argument So that will then go here and say if it’s forward, it will execute this function, moving the turtle forward by an amount I think there’s a lot of redundant extra code now but this is fine Let’s see what happens Syntax error Oh this has to say function I’m not in an object anymore All right, mm, so, hmm, what is that 100 100, so what’s, oh, oh I didn’t execute anything Execute commands Command list is not defined Command lookup, okay, I can’t remember what I call anything, command lookup Hey! (clapping) (bell dings) This is working Wow, okay Dare I say this is complete? Does anybody have access to the code that produces this design? I’m going to take a break and try to find it (train whistle) Okay, I’m back What you don’t realize is about an hour passed of me doing some horrific debugging and if you want to find that, I will link to the livestream version of this edited challenge

in the video description, the thing that you’re watching right now, which is not, even though I am live, it’s not this, ah, okay, this, this is the code using only repeats, left, pen up and pen downs that will create this particular pattern and if I go and grab this, I’ve pasted it here and if I go back to my example and I paste it in (drum roll) (buzzer buzzing) It doesn’t work What’s wrong? Well, weirdly, I’m going to show you something weird If I put a space here and a space here, ah, all of a sudden (horns playing) We have the pattern we were looking for all long But there’s some weird buggy stuff going on, why is it a space but no space, here is the issue So it took a while to debug, I will show you a way of finding, the way that I found the error was by looking through, first of all the chat found this way before me and kept suggesting it and I had to look and look and look Where I found it all of a sudden in this last repeat here, this command right, right, it didn’t pick up the argument three, it’s blank so that’s certainly why I’m not getting the pattern that I’m expecting to get Now why is it doing that? Well the secret to that, it’s not a secret so much, lies in the fact of the way that I parsed this bracket, right, remember if I have a repeat, if I go here, right, I look for the first opening bracket, that’s the start, the first ending bracket and that’s the end but what if there’s a nested repeat? If there’s a nested repeat, this is the starting bracket, this is the ending bracket So it completely ignores, it pulls it off here and then loses the way it’s parsing, it loses that three and somehow having a space in between there, it kind of is able to still get that three by accident So what I really need to do is match the number of brackets All right, I have a different idea now What if, I think this finding the first one and finding the last one in this weird double wild loop way is kind of silly because all I need to do is keep track of, I mean I do need to find the first one, so let’s stick with finding the first one and then basically once I found that first one, bracket, bracket count, ah, equals one So now, what I want to do is while bracket count is greater than zero, I’m going to look at the character If character = and opening bracket, then, ah, then increase the bracket count, else if it = a closing bracket, then decrease the bracket count And then I should have, end should just now be wherever the index is, wherever it last left off, I might need to do minus 1, I’m not sure, right, so this should be like, I’m basically finding the first bracket, in this case, there’s noise and spaces there and then I’m going to pull out, I’m going to, I’m basically looking for where that last bracket is and the last bracket is and as the last bracket comes, bracket count will be zero, I’ll be done but if there are other brackets, it’s got to keep counting, okay (drum roll) I should never use my drum sound because it always means it’s not going to work (clapping) (train whistle) All right, there we go All right so this is complete, it works, I’m very excited about that People have pointed out some examples that I found, for example, I could try to make this design, let’s see what happens if I post this in here Right, we could say, oh I’m kind of off where my starting point is of but now, I could start to really be creative and the line is sort of thick here so I also feel like now that I’m doing more complex stuff, I probably want to change the stroke weight back to one And we can see that looks a little bit nicer I just want to show you something though amazing If we go back to the Logo repo which this is the state before I’ve done this video and I go to pull requests and I go, for example, to pull request number three from TheTastefulToastie, you can see here are a whole bunch of other ones that you can see that I could now try that should work with my, and I’m going to show you something that’s going to blow your mind, this Ah, let’s make this work, we have to make this work So I’m going to go, just before I leave, think about other creative things you could add These are all the commands I am going to now go into index and HTML,

I’m going to put that in here, hold on, what’s going on here? Let me give a carriage return here, let me paste in all of those commands Now I could now go back to here and do this We don’t see anything So one thing that I really definitely need to do is give it a much bigger canvas So let’s go back to create canvas Have to finish with this 900 by 900, something like that, refresh (gasps) There it is Oh my goodness, this is nuts But it’s a little off center, oh let’s change it to 20 20 or zero, let’s actually just change it to 0, 0 And make it a little bit wider Whoops There we go (train whistle) it is The Coding Train logo made with literally with Logo and all of these numbers here I hope you enjoyed this video, there’s so many things missing, right, there are all these Logo, if you look at the history of Logo and you look at the language of Logo, there are lots of commands that I missed So I’ll list some of those in the video’s description, try to implement those or also, color, how would you incorporate color with this? How would you think of other clever ways to make this interactive in realtime to allow people to play with it? So, we now have a full interpreter here and I’m finished with this project I can’t wait to see what you make, I’m going to add this code to the This Coding Train Logo repository and I will accept pull requests for implementing other commands, bug fixes, adding things like color, making the interface a little nicer so I’m probably going to close out most of those pull requests that were implementations of repeat, I thank you for them but this will be now a community Logo interpreter project that will start from the code that is in this video Goodbye, everyone, and see you in future coding challenges (upbeat music)