 Hi how's everyone doing? So today I'm going to be talking about abstractions and building up a case study with chest pine open source chest pine. So a bit about me I'm Aubros and Gupta. I am gonna be a junior at Lindbrook High School when summer ends. It's my Twitter and that's my github. So I started programming like I'd say middle of seventh grade. So I started programming sometimes like in the middle of seventh grade. I started with app development for iOS and then I gradually moved on to Python to much cleaner language. So yeah. So this is the agenda for today. So we talked about like the big questions in this talk and then you know your chest and so on. So the big questions. What is abstraction and why is it important? So abstraction is most of you probably know it's the concept of taking an idea and making it easy to refer to giving a name of some sort and representing it in a way that's representing it in a way that is simple. It gives you all the details you need and cuts out anything that's unimportant. And why is it important? Well it's kind of what the whole paradigm of object-oriented programming is based on abstraction and without abstraction like basically none of modern programming would exist. It's like the only way to take an idea or a situation and kind of put it into like a neat little box so that it's easy to use. So let's use chess to understand abstraction. So chess is a board game and it's simple. It consists of a board with pieces. You know there's two players. It's unambiguous. There's concrete game rules so like there's no weird like all the rules are written down. They're explicit. They don't change and it's well known. You guys probably know chess. So why I chose chess? Well I've always been interested in chess. I used to play competitively. My rating was somewhere upwards of like 1000 at one point. For reference the Grandmaster's rating is 2500. And also programming is something you know I love to do and I do in my free time so I decided why not combine them? There are two things that I love at once. So the model for chess. So what I try, what this what I'm doing is essentially creating a chess client. A simple you know a simple way to create a chess client. And first of all before you can do anything you have to figure out you know what is my model what what am I trying to do. So if I want to create a chess client well I need a board an abstraction of it right. I need pieces. I need a way of verifying rules. This is especially important so that people don't just go around by doing illegal rules and then are totally mess and obviously we need a way of changing the board to implement those rules once they've been made. And then we need a way to check you know the game and who won. So this is the model I came up with. As you can see this is a game object. So this game object is basically what is encompassing most of it. And both players are interfacing with it. So this is especially important because I wanted to create the player. I wanted to create the player to externalize the player. So that way they could be you know they don't really have an effect on the game. I want to abstract the game into one single idea of the player just interact with the player. And inside it well you can see the board with the pieces of the board. And then there's validator on it. It takes in a move that the player plays and makes sure it's legal and then changes the board. And then changes the board. And the board in turn the board in the arrangement of pieces on the board in order to reflect that change. And after the game is done the game won't output the result. So basically my code. This is the design I use. This is the design I use. The code I wrote. The code I wrote is the actual game idea. So before moving on I wanted to talk about the abstract base class. It's a bit abstract base class. Because it's like a fundamental, like basically it's an abstraction. An abstraction. And so an abstract base class is based on a signal to be instantiated or to be instantiated. It is at the base because it will be played more for other classes and more for other classes. So just by... I mentioned abstract base code P, base class code P. And this abstract base class abstract base essentially holds the foundation for what the foundation really is. So obviously all the pieces on the board... All the pieces on the board. The rowing. So on and so forth. So on. They all share a set of... They all share a set of... In this case a set of methods. And they have a lot of different methods. We even started writing all that code. Instead we put it in the set piece, add it on the base piece, abstract base class. So it makes it much easier. It makes it easier to get to the answer and see a path here. Row for nine or whatever. And obviously we don't want... Obviously we don't want to initialize this. I'm going to initialize because it's a piece. It's a type of object. So in this case you can see. In this case you can see the initializing method. So what that means is that it has to be implemented across the entire tunnel burner. And same with possible methods. And same with every single piece. A method called the process method. And the reason is that every single piece has a possible move. The way the validator works is that it looks at all the possibilities that you see and it turns back to what it did. That it will find a move. It's not find a move. It's not a legal move. And then there's like that equals. And then there's like that equals method. I had to write my own customer's phone because it's both methods because when I'm testing quality, when I'm testing free quality, it becomes the same. I want to get it right. But I don't care about height. I don't care about the location. So that's obviously not an abstract method. That's what it is. There's a way to do that. So the way that it works is that it's not a legal move. It's not a legal move. It's not a legal move. and making a function on this is, consider this, let's put it on the bottom. It's a very simple function, a very simple function. We turn this two times out. We turn this two times out with X being the event, with X being the event. So, we can do the same thing with the lambda. And this lambda, this lambda, we're making a lambda, which acts in X, it turns two times X, and sets it two times X. So you'd use both, so you'd use both of these expressions. Both of these expressions on the one, both of these functions in the same way. So you're wondering, you know, what's the difference between lambda and function there? The way they're abstracted is different. So what we do, the function is doing is making a function called time returns to X, which returns to X. So what the lambda is doing is creating an anonymous function, a function with no name, which takes an X, which takes an X and returns to X, and then setting that two times X. And the reason this is important is we don't have to set it to my function. We just do the lambda as it is. And it's really useful for different purposes, such as we can pass it in as parameters of other functions. We can pass it like an object as a parameter of function, so why not another function? So let me show you an example of how I use that. So let's record the movement. So before I talked about the possible movement, that each piece must have. So actually, obviously, I'm going to write all of those, and they're different for each piece. When it comes to a rook, rooks move up, down, left, right, the certain number of spaces until they either hit the board or hit another piece, they can't move past that. So all those docks you see on the board are possible moves for that particular block work. And we want to record all those moves in a list of possible moves. So then those are the possible moves. So how do we do that? Well, what we can do is we have a for loop that takes the rook's location and keeps moving it up and recording all of those locations as moves, heading up, but that would be painful. So essentially, why not use a higher order function instead? Because the reason I'm painful is because if we use a for loop to record all the moves that are on top of the rook, we're going to have to copy paste the code and record all the moves up left of the rook, on the right of the rook, below the rook, that would be painful because you're copying pasting the code four times and that's not good. So instead, we use a lambda to essentially abstract the direction of the movement and write a function that only focuses on moving until there's an obstacle. So let me show you what I mean in the next slide. So as you can see, there's a function possible moves. It takes in direction, which is a lambda, and the position, which is essentially the board, the position on the board. And what this does is it keeps adding like those little dots until, well, either, as you can see in the while loop, until either it's not on the board because if essentially the pointer is like, the thing that's recording the move is not on the board. We want to stop because we can't move off the board. And if the square is not empty, so the is square empty is obviously a method that I wrote on the position class. And so this while loop takes, it keeps doing this until it's not on the board and the square is not empty. So what this is doing is it keeps appending the current move to this current move to the list of possible moves. And then it keeps moving it a certain direction. Now this direction can be specified later using a lambda. So instead of a specific, say, shift up, as you can see in the bottom. So that way we can put in all the directions as shift up, shift right, shift down, and shift left and pass those in into the function. So that way all of these, basically the same function is there to record all the moves on top of the roof, left, right, and below the roof. So the shift up function is a function of the type I made called location. And this type is essentially an abstraction of a coordinate. Like it's a coordinate on the board, that's what it is. So inside that class I wrote a method called shift up, which shifts the coordinate up because I didn't want to manually have to change the X or Y coordinate. And I made one called shift down, shift left, shift right, and, you know. So that way now, since I have those functions, I can pass them in as lambdas and keep applying shift up to say, for instance, example, shift up to the location, the current location of the roof. And those resulting locations that get returned, put them in a list called possible and return that. Because those are all the possible locations that the roof can move to next. And this is really powerful because, the abstract new direction, because as you can see, we can reuse this code later. So if you reuse it to record Bishop and Queen. So obviously if you think about a Bishop, it's basically a roof that moves diagonally. So instead of up, down, left, right, it moves upright, up left, down right, and down left. So instead of repeating ourselves, why not use the possible method, the possible moves method in the other roof class we have, why not reuse that? So that's what we did. But instead of passing in up, down, left, right as lambdas, so it can add up, down, right, left, we passed in upright, up left, which are other functions I wrote in that class, down right and down left, so that all the diagonal squares instead will be added. So now the really great thing about that now is that in the Queen class, a Queen is essentially a combination between a Rook and a Bishop. So now in four lines of code, all I have to do is I combine the possible moves from the Bishop and the Rook that would have corresponded where the Queen is right now, and combine them into one huge list that has the diagonal moves we saw from the Bishop and the straight, up and down, left, right moves from the Rook. And now you have all the Queen moves. So this is awesome because we just reused all this code that we would have otherwise had to write. And now the thing is, in that, say we wanted to change that method, because as you saw, this method of possible moves, it does not record captures. So if we wanted to say implement a capture in this move, then basically you just change this method and then now all of a sudden the Queen, Bishop and Rook, they can all capture. So that is the power of abstraction because we abstracted the movement without the direction because the direction can be passed in later, right? So why not take the, why not just like move but then the direction, you don't need to know what that is. So because you can pass it in later. So my end result is I actually created a chess client called chess pie and it's open source. You can get it on GitHub and it's written in 100% Python. And the cool thing is I also made it a framework as well as a script, like as well as an application. So the thing about what I mean by framework is you can use it to in your code to play your own chess game. So say you wanted to make an artificial intelligence or whatever to play chess, right? And then if you use this, you don't really have to program the specific built-in chess. You don't have to program it to know how to play, like you don't have to program the machine to play chess, you just have to program the player. So that's the power of this abstraction is now that we have this game in a nice little package, later you could just basically import it, find out what the possible moves are, choose a move and then move. And then later get the result of the game, you know, after the game's over. So you don't have to worry about like all this messiness that, you know, correct. You don't have to worry about all this messiness that comes from making a chess client because it's a framework. So yeah, this is my bibliography. And that's basically it. Thank you. Are there any questions? So what I did with that, if you wanna me to explain it in more detail is I created a rook object inside the class and I passed in the current queen location. So essentially it's creating a virtual rook that thinks it's where the queen is. And then I can take that and all the possible moves that that virtual rook has, I can combine it with the possible moves that a virtual bishop has that also thinks it's in the queen's location and I have all the possible moves of the queen in that location. Any other questions? Yeah. Have you used your code to implement a game or anything that builds on your code? So for right now, my code, it basically runs in a terminal, it doesn't, there's no UI. I can show you a demo if you want. But basically, like this is a default thing where it just runs in the terminal. Later I might make a GUI for it and as for something that implements it, later I'm thinking I might write like a machine learning algorithm or something that they can take this and learn how to play chess well. So how much time do I have left? So do you guys want to see a demo? Yes. Okay, this is my code. Yeah, let me just run this. So the cool thing is I figured out like that there are these ASCII chess pieces that you can print on the console. So that's a really nice representation. So if I wanna move, say like the most popular first white move is E4, right? So I can take this and then this will be converted into my move object and then it applies it on the board. But if I try something like for black, say I try an illegal move, say I try E4 again just to see what happens, then it's not gonna work because it doesn't match up with any of the possible moves. So obviously the black's reply would probably be E5, right? So then that gets moved. And I'm gonna just do the full move checkmate so you guys can see how this game will end. So then white's move would be queen to, let's see, A, B, C, D, E, F, G, right? So queen to H, two, three, four, right? Wait, no. Okay, fine. What move do you guys wanna do next, I'm just curious. What? Queen H5. Queen H5? Okay. Yeah, that's true. I'm bad at that. There. Cool. And then say we do for black, we do A6, just a time-pressed move. So then for white, we do bishop, what is it? Sorry? C4. C4. Yeah, I'm kind of bad at algebraic notation. So, sorry? What? Yeah, okay. You're right. Well, I'll just do another B6. You can play on C5 and then you should see for next. Yeah, that's true. And then, I don't know, I'll just do C6 next. Wait, no, that's, yeah. Don't worry, cool. And then queen F6, checkmate, right? F7, what did I just do? Oh, good. Oh, you're just black, it's black. Okay, so let's just do C, so queen F7. Oh yeah, queen XF7, that's cool. Yeah, cool. So, the result is one. As you can see, this program's a lot better at playing chess than I am. But, so this result is one, meaning white one. So if it was black winning or B0, if it was a tie or B0.5. So the cool thing about this is now, if within code, we can just set this to a value called result. So then when it returns this result, then we can use that result to further, say, fine tune what whoever's playing or whatever computer's playing this game. Any other questions? Sorry, could you repeat that a bit louder? I couldn't hear that. Yeah, when you wanna say available pieces on the board for a particular piece, but you wanna do a capture, you need the logic of knowing whether or not it's the opponent's piece that you capture. Oh yeah, so how I implemented that was, obviously with each piece is different, but basically I have each piece knows, it has a value called input color. So using that it knows if it's black or white. So I just have to check if the piece is of the opposite color and if it is, then it can capture. If not, then it can't. So any other questions? Yeah, that's true. The 50 move rule I believe you were referring to, right? Yeah, so for those of you guys who didn't know, the 50 move rules and chess is if both sides basically just dance around and there's no progress, no captures, no pawn moves, and 50 move the game's an automatic draw. So that's a good one. That's what I have to implement next. I haven't done that yet. The basically the only way to end the game now is if there's zero moves left for anyone. So that's a stalemate or a checkmate. But yeah, that's a good one to do next. That would be fun. Looks like I'm done.