Next lesson playing in 5 seconds

  • Overview
  • Transcript

5.2 Display the Game: Prep Work

In this lesson, we're going to build what is arguably the most important part of our application. And that is the actual chessboard that we're going to be displaying to our users. Actually, I guess the most important part is a toss up between the displaying of the actual board and the logic that allows them to make the actual moves. But, you can't really have one without the other. So we'll stick with that. This is the most important part of our application. And most of our work is going to be going in our client/game/game.js file. In the previous lesson we subscribed to our game, and so we now know that whenever we're working within this template we have access to that one game that we want. So let's just write a quick helper function here that we're going to use. Since it's only going to be used within this file we only need to have the function here. And we'll just call this getGame and this is just going to get that one game that we have subscribed to. So, I'll just return Games.findOne and we'll pass it flow rather dark get paramus and we'll get the ID. And so, get game here we'll just return our single game. Now there's another helper function that we're going to need and that is getMoves. And we're going to use this in a couple of places. Let's write this function first. And then later on, you'll see where this function will be useful. But let me tell you right now that the getMoves function is just going to return an array of the moves that have been made so far in our chess game. Now it's important to note that when we're talking about moves in a chess game, we're going to be using what's called algebraic notation or algebraic chess notation. This is actually pretty simple. As you can see in this image over here, the rows or ranks as they're usually called in chess are numbered one through eight. And the columns, or they're usually called files, are lettered A through H. And so you can reference any cell by just using its file letter and its rank number. When we're talking about a move in a chess game, the full notation begins with the letter referencing the piece. So K for king, Q for Queen, B for Bishop, R for Rook and N for Knight. Even the knight and king will start with K, we use N for knight and then followed by the space to which they moved. If it's a pawn that's moving, there's no letter used at all. There are some other details that I'm not mentioning here. If you want to read about them, I'll have a link to this Wikipedia page underneath this lesson. However the idea here is that for every game in our database, we will have a moves field. And we create an empty string as the moves field when we initially start the game. Now even though we're calling that field moves what's actually stored in that field is portable game notation. Now this is actually very simple if you just look at an example here. Ignoring this header stuff, which is optional, you can see what we have here is the portable game notation, which is our list of moves. And we just have turn one followed by E4, E5 and those are the first two moves. White moved point E4 black move point E5. For the second turn white moved knight to F3, black moved knight to C6. And so you can see this is what we will eventually be storing in that moves field every time our user makes a move we will update our moves field. So this means when the user has come to the page to play another turn in their chess game, it's most likely that they have already played some moves and so we have to set up the board to be wherever they left off. Right, so here within getMoves let's create a chess object here. And this is going to be a new chess game. Now remember we're using this chess as library, and so when we create this we've got a brand new game with an empty board. However of course, the idea here is that we want to use some of the features of the chess chess library to make some of the calculations easier for us. So what we're going to do after this is a chess.load_pgn, of course portable game notation. And what we can do is pass some portable game notation to this function and it will load it into this chess game. And it will basically move the chess pieces into the right position based on the turns that have already been played. And of course, all that is represented within this chess object. What we're gonna pass to this is getGame meaning we get our game from the database. And then we can say .moves which is going to be the string in which we will eventually store our portable game notation. All right now after this we just want to return chess.history. And chess.history is going to be those same moves except in an array where each move is its own item in the array. So basically all this function does is it takes our portable game notation that we've stored in our database. And we're using a chess object here to convert it to an array of all those moves. Now, why do we need this array of all the moves? Well, above our two helper functions here, let's do And the reason we need those moves is because, right now, we want to create a helper called rows. And this is going to be the actual rows of chess pieces that we want to display to the user. We need a ray of rows, so that we know where each piece is going to be placed on the board. And so what we're going to do here is again create a new chess game so will say chess = new Chess and then remember that this chess game that we've just created is a chess game in the initial state. Right we need to move all the chess pieces to where they would be in our game. So let's do chess.move and what you can do is pass chess.move a move and if that move can be made it will be made. So for example, we could pass it, E4. And it would update the chess object with that move or we could pass it. To E5 or something like that and that move would be made assuming that a move could be made. Instead, the way we're going to use chess moves we're going to say getMoves, to get our array of moves. And then we're going to say for each. And we'll say chess.moves.bind(chess). So we're going to basically loop over each one of the moves we've made and make that move in our chess game here. Now at this point, this seems like what we've done is actually pretty repetitive. If you take these things in order, we've created a new blank chess game, set up the board so that it matches what is in the database, then used that game to get a list of all the moves that have been made. And then using that list, we make a new blank board and move all the pieces on the second board. So why are we doing it this way? Well, we're doing this way because in the back of our minds we know that we're actually going to be using this board in two different features. There's the primary feature that we're working on right now which is just playing the chess board so that they can make their moves during the game. However when the game is finished we're going to allow them to step through each one of those moves, right? And so we need some way to set up the board to any given point during the game after the game has been completed. And that's what we're doing here. Later on and we're going to change this get moves function so that it only returns history up to a certain point in the game, and we can control that point. Then as we change that point in history, that will be reflected in our rose function. The board will be displaying at that point in history. And as we change that point the board will actually change to step through the different moves that have been made. That's also why we're not using the board field from our database. If we look back at where we create the game object you can see that our board field is actually using the Forsyth-Edwards notation, which doesn't keep track of the moves, but just shows the current state of the game board and also whose turn it is and a few other things. The reason again that we can't use that is because we don't want to know the game at the end. We want to know the game at any point that we choose to look at it. And so, that's why we're using getMoves. Okay, so at this point we have a chess game here and we could say chess.fen. And at whatever point in the history of the game we've chosen to look at chess.fen will be the board as it should be displayed to the user at this point. So what we need to do now is convert chess.fen to array of rows. And to do this we're going to use a function that we're going to call makeRows. And this is going to take two attributes. Chestnut.fen, of course, is going to be the first one. And also, I'm going to get the game here, and we're going to return .b. Now remember, B of course is the idea of the player who is playing black. And the reason we need to know which user is playing black is because the black player views the board upside down if you will or from their angle. So it will default to white and then it will be simple to reverse our array of rows to get the board from the black player's perspective, okay? So why don't we write this helper function? I'll just put it down below here, makeRows. And we're returning the board and the black player. So I'll just give that b. And before we begin here, I should show you exactly what the Forsyth-Edwards notation that we're going to be using here is going to be because remember that is what the value of board is. So right down here we have an example of the starting position of a chess game in fen. And the part we're interested in right now is this first chunk here, up to just before the first space. As you might guess, these are the eight rows or ranks in our chess board. Now, the way this works is that empty spaces on the board are noted by numbers. The white pawns and pieces on the board are noted by capital letters and the black pawns and pieces on the board are represented by lowercase letters. And the letters are pretty much as you might think. P is of course for pawn. We have R for rook, N for knight, B for bishop, Q for queen and K for king. And so, this just works out this way. At any point where there is a string of blank cells we have a number. So you can see here for example after the move E4, then you can see instead of having four blank rows in the middle as we did before here, with eight empty spaces in each. We have four empty spaces, a white pawn, and then three more empty spaces. And then of course, this second rank here has four pawns, one empty space and then three more pawns, okay. So our responsibility now in the make rows function is to convert this notation here into an array. Full of rows and each one of those rows of course will be an array full of objects which will have the necessary information for our pieces here. Now there's actually one more thing we need to think about before we get into our makeRows function, and that is how are we actually going to display our chess pieces on the board? Well thankfully there are HTML entities that we can use to display all the chess pieces. So I'm going to open up a new file, I'll call it pieces.js and this is going in our lib folder. And in here, let's create a pieces object. And this is going to be pretty simple. Just like the Forsyth-Edwards Notation, we'll use capital letters for the white pieces, lowercase letters for the black pieces. And this way we can just use the Forsyth-Edwards notation as the key to find the right piece in our pieces object here. So we'll set the king equal to and of course since we're using in an HTML entity we'll start with an ampersand. And then this is a numbered entity so we just have a hash sign. And then the king is 9812 and then of course we had with a semi-colon. Now let me duplicate this the queen is going to be 9813. Next we're going to have the rook next we're going to have the white bishop. Next we're going to have the white knight. And finally we have the white pawn. And in all of these cases we're just going up by one number. So the king is 12, queen 13, rook 14, bishop 15, knight 16, and pawn 17. And then let me just copy this and paste it below. Next we have all the black pieces, which are just the lowercase letters, so k, q, r, b, n, p in lowercase. And these just continue to count. So if the king is 18, the queen is 19, the rook is 20, the bishop is 21, the knight is 22, and the pawn is 23. And there we go, those are our pieces. Okay, so with all that set up, we are ready to go ahead and make our rows. However, with so much setup work already finished. Why don't we look at this makeRows function in the next lesson.

Back to the top