Next lesson playing in 5 seconds

  • Overview
  • Transcript

5.6 Making Moves: The Meteor Method

In our last lesson we wrote this event handler function which should allow our users to actually make moves during their chess game. And we ended by calling a meteor method make move. And so in this lesson we're going to write this method which will actually log the moves that our players want to make. So over here in our methods js file right down at the bottom let's add a make move function. And as we saw in game js this is going to take two parameters. It's gonna take the id of the game and it's going to take the move and remember this move is going to be in the algebraic notation that we used to record a chess move. So we give these parameters the name gameId and move. So first, let's go ahead and find the game and we can say Games.findOn, and we pass it the (gameId). And then, let's create a new chess board. And then, let's load up all the existing moves by doing chess.load_ pgn and we'll pass it game.moves. Now you might wonder why are we not passing game.board, which is our for say notation to the chess constructor. Because that will set up the board correctly in the same way that a load pgn will do. And the reason of course for this is because when we load the board in the constructor, we don't actually have any history of the game. All we know is, this is the current state of the game. However, by loading all the moves we will have of course the right current state of the game but we'll have all of the history of the game as well. And so we can start from basically where we left off after the last move was saved. All right so now let's actually make the move so we say chess.move and we'll pass that move in. Now at this point we've actually made the move. So we could just go ahead and save the data from this chess object back into our database and let the next player make their move. However it's not quite that simple. And this is because we need to check after every move to see if the game is over. Because at some point the game will end. And so after every move we need to check to see if the game is over. So we're going to need a result if the game is over. So let's just create a result variable and we'll set it to null. And of course, null is going to be the default result if the game is not over. So we'll be using that value a little bit later. So now we can say, if chess.game_over and this is a chess function that will return true if the game is over. Now if the game is over then we need to change the result variable to be whatever the proper result of the game was. And there are two possible results. Number one, the game could be a draw or number two, somebody won the game. And the way we can figure this out is by using a turner rate expression. And we can say chess.in_Checkmate. Now you might wonder how exactly does this work because we're not specifying which player is in checkmate. Well the way it works is that our chess object here is keeping track of whose turn it is. And whenever we make a move with chess.move the turn switches to the other player. Now if this move here, let's say that's played by the black player, causes the white player to be in checkmate then chess.incheckmate will return true because it is the white players turn. So in checkmate refers to the player whose turn it currently is. Now the nice thing about this is it's pretty simple for us to figure out who won because in chess whoever moved last is obviously the one who did the check mate. So if the game is over after this move then it's obvious that whichever player made that move is the one to win. So what we need to do then is if the player is in checkmate then we need to find the current player's turn. So we can actually do this by doing chess.turn and chess.turn will return w for the white player or b for the black player. So if it's currently the white players turn then we know that the black player won because that was the last player to move otherwise it was the white players turn. Now obviously we don't just want black or white here so I'm going to put this all inside square brackets and we can say game. And so this is going to be either game.b or game.w. Which as we know will give us the id of the user who won. Otherwise the last part of our turner expression will be draw. So we'll just say, if they're in checkmate then find the player who last made their move. Otherwise we know the game is over so if no one's in checkmate then it must be a draw. So now we're ready to save the game back to the database. So I will say, Game.update and we'll pass our gameId as our query to find the right game in the database. And then we will do a set query here for the update. We'll set the board equal to chess.fen, we will set the moves equal to chess.pgn, and we will set result equal to whatever result we just determined. So either it's going to be null or if the game is over it will be an id or it will be draw. All right, so that will update the game. Now there's something we want to do after we update the game. And that is, if the game is over or if one of the players is in check, we want to go ahead and add that to the message queue. So let's add a callback after this and this will just take an error object. And of course, this callback will be called once the game has been updated. So I'll just start by saying if there's an error go ahead and throw the error. Otherwise we need to figure out what message we want to add to our queue. So there are a couple of things we can do here. We can say, if the result is equal to draw then let's set message to be Game over; draw'; otherwise if there is a result, meaning result is not null then we know that somebody won. So let's set message = getUsername, remember we have that helper function, will pass the results in because that's an id and then we can just add the text won. Otherwise if we can say chess.in_check is whoever's turn it is next in check. If they are let's add a message for that. And then let's put the user name of the user who just took their turn. And obviously checked the other player. And actually in thinking about this I'm realizing that the way this code is going to run we can say Meteor.user.username to get the id, to get the username of the currently logged in user because when this code is run the move that was just made was obviously made by whichever user was logged in. And so we can just say, Meteor.user.username and I think that would actually work up here as well right because if we are in checkmate then obviously the currently logged in user is the one who did the checkmating and therefore won the game. So we should be able to actually shorten this up and say Meteor.userId or draw. And we can get rid of these two lines. I think that should work. We'll give that a try. And if that doesn't work we'll switch it back to what I had before. But I'm pretty sure that will work. So let's go back down here to our message. If the result is draw we give the draw message. If there is a result and it's not draw obviously we know somebody won. If there is no result and someone is in check then we'll get the check message and otherwise if none of that is true we will just return. Okay but assuming we didn't return. Then we have a message that was set and we have to save it to our conversations database. Let's say Conversations.update. And we'll update it where the game is the gameId that we had and let's go ahead and say $push to add a message to an array. And we'll say the name is system and we can say the text is the message. So with all this in place we should be able to actually take some turns now because this is the code that allows us to save those moves to our database. All right so I have the same game open here in both screens. On the left side we have Andrew playing white. On the right side we have Cameron playing black. So let's see if this will work. And I'm going to pop up on a console just in case it doesn't work. So I can go ahead and select a player. And then if I click another cell. So we do have a problem. Let's see. Games.findon is not a function. Of course. So you must have a typo. And right here I say, findon. Let's change that to findOne. Okay, that's good. We'll let our two pages reload. And let's try this again. Well that's not quite what we expected. [COUGH] okay it looks like we have an error within the chess library we cannot use inoperator to search for legal in e4. Okay so it looks like we're misusing something in the chess library. And right here we have an array for each and in our templates games helper rows. Okay, so let's go look at that function and see if something's wrong, that was back here and in our game helper here we have rows. We said getMoves and then forEach(chess.moves.bind(chess));. And the problem here is this should be chess.Move. So we don't want to get a set of moves we want to actually perform the move by doing chess.Move. Ok but that's good. That means the get moves returned an array with something in it and that we were trying to make that move. And actually once I change that code and refresh the page you can see that the move I made was actually saved. And if I try to click another player here you can see that it's no longer white's turn. And so I can't actually make a move. If I come over here to the black side. Let's see, I can make a move and notice how it automatically moves on both sides, that's good. I'll make another move here on white side. Let's make another move here on black side, another move here on white side, another move here on black side. And now on white side if I move down to here this is actually checkmate. And if on black side you see I try and select someone you can see that it won't work because the game is over. And this is actually great because now if I go back to play chess you can see that we now have an archived game. Because that game has been won. Andrew versus Cameron, Andrew won. And now I can start a new game with Cameron. Which means that our form and our lists here were actually right all along. We just never had a chance to check them. All right, so we are successfully making moves and saving those moves to the database. And at this point, the core of our application is finished and we're ready to just polish it up with a few extra features.

Back to the top