BYU logo Computer Science

Hurdles Transcript

[00:00:00] INSTRUCTOR: Howdy! Let’s walk through the hurdles problem together. So in this case, bit starts on the left and he wants to get over all the hurdles into this corner on the right. And so one of the first questions, as you look over a problem, you’re saying which patterns apply to this problem?

[00:00:22] You’re going to learn a lot of different patterns and approaches to something, to programming, and an important skill is figuring out which of the many things I know applies in this situation. And then as you’re breaking the problem down, you’re also going to ask yourself what verbs would make this problem easy to solve?

[00:00:44] So question number one, what pattern fits here? Well, as I look through this, my instinct go to almost always is, can I make this an event string? A lot of problems are solved with that pattern. And so it’s a good one to look at first.

[00:01:03] And you can say, okay, so what is the overall goal and condition that’s moving bit forward? And what are the events bit needs to respond to in the meantime? And so I can see there’s this unique ending position, this little cave.

Start visual description. Text on slide reads:

  • What pattern or strategy best fits this problem?
  • What verbs would make this problem easy to solve?

End visual description.

[00:01:23] It’s the only time in this entire map that bit is blocked on the left side. So maybe we can use that as our ending condition. We can say, well, the left is clear, run forward. So then what’s the next step?

[00:01:43] What’s the event that we would need to respond to? And we see these little bumps, these hurdles in the way, and he needs to jump the hurdles. What tells us we have encountered a hurdle? Well, we know we have a hurdle when the front is blocked and the left is clear.

[00:02:05] We can jump, essentially. That’s different from down here where the front is blocked and so is the left. So we can see the condition that moves us forward and the condition we need to respond to for the separate events.

[00:02:18] Move to the end and let’s jump these hurdles as we need to. So let’s start some code. We know the overall shape of an event stream. You’ve got this outer while loop. While should keep going, bit, bit.move.

[00:02:37] Great. And then the question is maybe jump, bit. Oh, I guess we have a paint in there. Bit.paint green, and a maybe jump. You’ll see this pattern over and over and over. Break out a function for whether or not we should keep moving and break out a function for responding to possible events.

[00:03:00] Identifying the event and responding to it. So, let’s implement these. Create a function should keep going. How do we know we should keep going? Well, we know that we should keep going if bit.front is clear, we should keep going.

[00:03:22] We also know, though, that if the left is not clear, we should stop. So, if the front is clear or bit.leftclear, then we’re good. I guess a moment ago, we considered maybe we don’t even need the front clear part.

[00:03:44] We can just say, hey, as long as the left is clear, we should keep going. And then, just to make sure that we don’t run into a wall, we maybe have to jump. So, let’s try this and see how this goes. We can always fix it if we find out there’s a problem.

[00:04:00] So, maybe jump. I would just come up here and do it like this def, maybe jump, bit. Let’s document this. So, what’s the point here? If the front is blocked, jump over the hurdle. So, what does that mean to jump over a hurdle?

Start visual description. Instructor types the following code:
def should_keep_going (bit):
return bit.left_clear()
def maybe jump(bit):
"""If the front is blocked, jump over the hurdle”””
@Bit.worlds(‘hurdles’, ‘more-hurdles’)
def run(bit):
while should_keep_going(bit):
bit.move()
bit.paint(‘gree’)
maybe jump (bit)
End visual description.

[00:04:24] Well, I think what we intend is that bit’s going to start right here. In fact, let’s draw this out. So, we’ve got the little hurdle here, and we’ve got a little bit facing the wall. The end of the hurdle comes off this way.

[00:04:42] So, where do we want bit to end when the hurdle is jumped? And I propose right here. Now, bit’s ready to keep moving forward. So, we start facing this way, we end facing that way. Let’s document that.

Start visual description. Instructor sketches the hurdle problem on the screen. End visual description.

[00:05:01] So, it starts on the left of the hurdle facing right. It ends on the right of the hurdle facing right. Not facing down. We want to make sure that we’re clear on where we want things to go. And so now, what are the big ideas that comprise jumping a hurdle?

[00:05:28] We’ve got to go up, go over, and go down. We can do that. What does go up, let’s even pause right there. Just go to our code and do that. So, go up, bit, go over, bit, go down, bit. That’s a jump.

[00:05:58] Oh, but this is supposed to be a maybe jump. If the front is blocked, jump over the hurdle. How do we know that we have a hurdle? We have a hurdle if the front is blocked. Maybe that was a redundant statement, but it makes it obvious to us that we need to catch this condition.

[00:06:20] So if bit.clear, that’s not the condition we’re looking for. If not, the front is clear. Go up, go over, go down. Great. Now, let’s talk about what does it mean to go up, to go over, and go down.

[00:06:40] Let’s create a function, go up, and let’s come down here and say, create a function, go over, come down here, and create a function, go down. Great. Go back to our drawing for a second. So go up. We need to decide when is bit going to end and what direction is he facing.

Start visual description. Instructor types the following code:
def maybe jump(bit):
"""If the front is blocked, jump over the hurdle We have hurdle if the front is blocked
Bit starts on the left of the hurdle facing right Bit ends on the right of the hurdle facing right”””
if not bit.front_clear():
go_up(bit) go_over (bit)
go_down (bit)
End visual description.

[00:07:01] Maybe in this case, we’ll say, bit’s supposed to turn and go up and facing this way. Maybe we could say, let’s do the turns as glue code and then just make functions for the straight shots. So we’ll handle the turn down here to have him facing up.

[00:07:22] Now go up is just to run straight up. And stop like this. We’ll handle the turning and then, so we’ll get bit to turn and face like this. And now we want bit to run to where. We know what’s the condition here that we can use?

[00:07:47] Well, we’re trying to run past all of the black. So we’d say, okay, we’ll run to the end of it. That’s how we’ll know we’ve ended. So we’re going to end on the outside. This is terrible.

[00:08:01] We’ll run to the outside of it and then we’ll handle the turn again and have another function that runs bit to the bottom. Okay we can handle that right. Okay so let’s sketch those details out and see what we have.

[00:08:20] So go up bit starts facing up and goes until moving along until the right is clear. It goes until the right is clear. Great, so we can do that. While bit.right clear. No actually we want while not bit dot right clear bit.move bit.paint.

[00:08:55] Okay so that’s to go up. That should stick us with bit facing right here. So let’s remember now we had that glue code that we promised we were going to go put back in. So here we’re going to say bit.left.

[00:09:10] Now go up is going to go all the way up. Now we know that from go up, we’ve got to turn. So we came to here, we’ve got to turn facing this other way. So let’s do a bit.right. And now we just have to go over.

[00:09:24] Okay, so let us go over. Bit.movesUntil, what was the condition? Until the right is clear. And as I start to write this, while not bit.rightClear, I realize I’m about to write this exact same function.

[00:09:54] Both of these actions of going up and going over, this is moving to the right is clear. So maybe instead of calling this go up, I’ll say go until rightClear and not have go over at all. We’ll copy this.

Start visual description. Instructor types the following code:
def go_until_right_clear (bit):
"""Bit starts facing up, and goes until the right is clear"""
while not bit.right_clear():
bit.move()
bit.paint(‘green’)
def go_over (bit):
"""Bit moves until right is clear"""
while not bit.right_clear():
End visual description.

[00:10:14] Come down here and say go up. We’ll go into the right is clear and just reuse that same word. We’ve already made it. Let’s use it. Okay, so now that bit has cleared. Now we just need to turn and go until the front is blocked.

[00:10:31] So let’s see here, we come down. We have to bit.right and then go down. If I control click or command click, it’ll take me to the definition here. And I say bit moves until blocked in front. Well, bit.frontClear, bit.move, bit.paint.

Start visual description. Instructor types the following code:
def go down (bit):
"""Bit moves until blocked in front"""
while bit.front_clear():
bit.move()
bit.paint(‘green’)
End visual description.

[00:11:02] Okay, once I’ve hit the bottom and I’ve landed, I need a little glue code to turn and then a bit’s ready to go, bit dot which way did he have to turn? Down, facing left. Great. Now this should have us jump a whole hurdle.

[00:11:24] So maybe let’s put a snapshot here, bit.snapshot hurdle jumped, and let’s just see how that first action happens if we managed to clear that first hurdle. Paint.green is not going to work for us.

Start visual description. Instructor updates maybe_jump function to:
if not bit.front_clear():
bit.left()
go_until_right_clear (bit)
bit.right()
go_until_right_clear (bit)
bit.right()
go_down (bit)
bit.left()
bit.snapshot(‘Hurdle jumped’)
End visual description.

[00:11:44] Let’s fix that to paint that green. Oh, something happened, but it wasn’t what we thought was going to happen. Great. So let’s look at it. What’s going on? Is there a jump? Hurdle jumped. Is that what we expected the hurdle to look like when we jumped?

[00:12:07] Of course not. So let’s go walk through this. So we’re moving through our code. There’s no good place to put this. Maybe down here. All right. We’re moving through the code. Left is clear. So we’re allowed to keep moving.

[00:12:21] Right? So we’re going to move and paint green. And the front is clear. So we don’t have to jump anything. The left is clear. So we’re allowed to keep moving. So we move and we paint green. And now the front is not clear.

Start visual description. Instructor runs code and goes line by line to see the behavior of the grid and how the code works. End visual description.

[00:12:33] That’s on line 28. All right. Well, not front clear. We’re going to maybe jump. And so now, because it’s not clear, we’re going to go into our jump maneuver. And so we’re going to turn left and the right is clear.

[00:12:50] In fact, we could make this a little bit faster. Why not? Let’s come in here. Going to right is clear. And say bit.snapshot. And we say right is now clear. Great. And then go down. We could come down here and say bit.snapshot.

[00:13:12] Bit is now down. Something like that. Let’s run this again and then use our jump to just jump right to where the ends of each of these functions are. So snapshot. Right is now clear.

Start visual description. Instructor types the following code:
def go_until_right_clear(bit):
"""Bit starts facing up, and goes until the right is clear"""
while not bit.right_clear():
bit.move()
bit.paint(‘green’)
bit.snapshot(‘Right is now clear’)
def go_down (bit):
"""Bit moves until blocked in front"""
while bit.front_clear():
bit.move()
bit.paint(‘green’)]
bit.snapshot(‘Bit is now down’)
End visual description.

[00:13:31] That’s line 13. That’s great. So now if we jump again, right is now clear. He’s made the turn. He hasn’t moved any. So if we come, let’s look through this. What’s going on? Right clear.

[00:13:48] He turns right and he moves until the right is clear. And now maybe we realize, oh, he’s right here. The right is already clear. He’s not going to move. We need another little step of glue code that once he jumps up to the top and turns we need to move one step over so that he can move across the top of the hurdle.

[00:14:08] Okay so right up here you can move up into right clear, return right, turn a little bit dot move, and now we can go into the right is clear. Right, let’s check it again. Oh, close. Here it looks like we tried to jump into a wall but before we try and fix this down here let’s just go back to the beginning and then see.

[00:14:32] So we jumped up, the right is now clear, we jumped to the other end, the right is now clear, bit is now down, and the hurdle is jumped. So the hurdle looks about correct from what we expected.

[00:14:49] That’s good, but there’s this little piece missing right here. Why is that? So let’s jump right here and step forward.return, we move, that’s line 34, bit.move. Now we’re going to go until right is clear.

[00:15:05] And what does that mean? If the right is, so we’re going to go next, write is not clear, okay great, so we’re going to move. And we realize that that extra move that we put in is glue code, we’re losing that spot.

[00:15:17] It’s not getting painted. So let’s go down to our glue code and say, you know, not only do we have to move, but we also have to bit that paint green. And that should solve this problem right here.

[00:15:32] Let’s make sure it does before we move on. All right, so now we can see we’re jumping all of the hurdles. It looks like our ending condition is not quite right. So there’s our last hurdle that we jumped, there’s nothing useful there, so let’s step back, just a few steps.

[00:15:54] Okay, so the front is clear, that means there’s no hurdle to jump. that’s line 30. Let’s come over here and double check, okay, so we’re in the maybe jump function. Maybe jump, the front is not clear, so we’re not going to jump, okay, that’s fine.

[00:16:13] So move next. The left is still clear, so we’re going to move. That’s line 46, we’re going to paint green then, all right, okay, good. And now we’re going to maybe jump. And so let’s go back again, let’s maybe jump, if not front clear, and we’re going to start jumping.

[00:16:35] So what do we actually want to do here? We want it to not jump. If the left isn’t clear, there’s no point in us trying to jump. So let’s fix that condition. This function to me is starting to get a little busy, and so maybe what I would do is break this out like this and say if should jump bit jump hurdle bit.

[00:17:05] Now I can come over here create the function should jump. How do I know if I should should jump? Well if the front if not bit dot front clear and bit dot left clear. So I’m blocked in the front and I can turn left and go, then I should jump.

[00:17:29] And now I can come over here create a function jump hurdle and take all this logic out and put it in there. This is what it means to jump a hurdle. Turn left move up etc etc and and that makes this, so maybe jump is just a simple if I should jump, jump it.

[00:17:54] Jump hurdle has the nitty gritty details about the glue code and the basic maneuvers. Should jump is simply now this one condition. Let’s see if this little refactoring of our code still does what we expect it to do. All right, it didn’t error here. What’s the problem? It is the green at the very beginning.

Start visual description. Instructor types the following code:
def should_jump(bit):
return not bit.front_clear() and bit.left_clear()
End visual description.

[00:18:16] Okay, so we know how to do this. Bit.paint green. Run hurdles. Hooray, everything’s good so far. But I have a little warning that popped up down here. Bit tried to move, but that space is blocked. I should look at the other tab.

[00:18:39] More hurdles. What do we see? Right at the very, very beginning, there’s a hurdle right in front, and we move right into it. So maybe we can go very, very first. What’s the initial thing?

[00:18:55] We paint green. There’s our paint green. Next step, if the left is clear, then we should move. And that’s, of course, is the problem here. What we want is that maybe jump to get triggered first, right, we want to say, hey jump, if you have to, if you don’t have to jump, it’s safe to move forward.

[00:19:18] And so let’s see if that fixes our problem here. So if you take, maybe jump out, put maybe jump first, maybe jump, and then if you’re done, you can move and paint green. Let’s see where that gets us.

[00:19:36] Okay, this first one worked, great. How about the second one? Close. What happened? Well, let’s go to the beginning. So we can jump. Okay, so the right is clear, and the right is clear, and we’ve hit the bottom, And the hurdle has been jumped, and now we’re going to move.

[00:19:58] Now do we start to see part of the problem here. Maybe jump, we might need to jump again. And so, the move isn’t always safe. How do we know whether it’s safe to move forward after I’ve jumped, or whether I need to jump again?

Start visual description. Instructor runs the code and goes through the grid simulation for the hurdles. End visual description.

[00:20:21] We can consider this for a second. But we don’t want to overthink it. It looks like the problem is, if the front isn’t clear, I need to jump hurdle. But if the front is clear, I should move. So let’s change our code to reflect something like that.

[00:20:41] So if I should keep going, I’m going to keep going. If the bit.frontClear, if the front is clear, I’m going to go a bit.move. Great. And if it’s not, well, in this case, now we have this question, you know, well, just maybe jump.

[00:21:10] And then if I don’t end up jumping, then we know that we should, we’ll hit this, should keep going and it should stop us. Let’s get rid of these down here. Again, we made a little change.

Start visual description. Instructor types the following code:
@Bit.worlds(‘hurdles’, ‘more-hurdles’)
def run(bit):
bit.paint(‘green’)
while should_keep_going (bit):
if bit.front_clear():
else:
bit.move()
bit.paint(‘green’)
maybe_jump (bit)
End visual description.

[00:21:23] Let’s test it, see what its effect was, and continue moving forward. All right. So this first one is still working, haven’t broken anything. And the next one was working also. There you go. So, a couple things to note then through this experience.

[00:21:40] The iterative process, building something, drawing it out, figuring out where the pieces fit together, breaking it down into smaller pieces, testing those pieces, using snapshots to be able to jump to the interesting places in the process.

[00:21:56] So you can see if everything’s fitting together correctly, checking both tabs and making sure that both worlds are getting solved. And then making small changes at a time and testing those to see that it works.

[00:22:16] Looking at it, coming up with a hypothesis, well, I think this could fix it, trying it, testing it. And then if it didn’t work, trying to look and understand why, what’s still going on, should I make a different change or another change, and working forward.

[00:22:35] And sometimes problems in programming will take a little while and they’ll take lots of iterations. And you’ll find that what you had started with isn’t what you need to end with. And that’s okay. That’s real life.

[00:22:49] And what you want to do is develop this kind of optimism. that even if the first thing you tried didn’t work, that’s okay, you can try something else. Maybe you can change it a little bit or you go back to the drawing board altogether and you keep searching and you keep practicing.

[00:23:05] And the more that you do that, one, you’ll develop an intuition that helps you get things right the first time for things you’ve done a lot of, but more important than that, you’ll develop a resilience that keeps you moving forward and solving problems.

[00:23:20] So the reality is most of the problems you solve as a programmer are problems you haven’t seen before. So you’re not going to get them right the first time. You’re gonna get them right the third time, the fourth time, and you need the stamina to keep yourself moving through that process in order to get the job done.

[00:23:38] Good luck with the assignment. Again, I invite you to try and solve this problem yourself. If you need to look at the code or the solution code or watch this video again to get through it, that’s good.

[00:23:52] Pattern it, mimic it. get it right, and then delete your code and try it again. And you’ll know that you’ve mastered it when you’re able to solve it yourself without looking at a prompt in order to get it done.

[00:24:06] And I wish you all the best, good luck.