Summing Lines to Win0:00
So, how would you go about calculating victory automatically in a game of tic-tac-toe? Well, let's give that thought for a second. In a game of tic-tac-toe, there are three ways to win. You can get three in a row, you can get three in a column, or you can get three in a diagonal. Now, remember, we've represented each square that is blank with a 0. So, imagine that we fill all of these squares with the value 0 to start. Let's say that crosses wins on the top row. That would mean that we replace the 0 in this row with 3 minus ones, because minus one represents a cross. If you were to sum up the squares in that row, what would you end up at? You'd end up at minus 3.
If you were to sum up the squares in that row, what would you end up at? You'd end up at minus three. Now, let's say that, instead, noughts wins on the top row. We know that nought is represented by a 1. What would the sum of the row be now? It would be 3. And, in fact, the only time a line, that is, a column, a row, or a diagonal, will ever have a sum of minus 3 or 3 is if we have a victor on our hands. So, we could use that to our advantage to calculate the winner. After any move is made, we'll loop through each row, each column, and each diagonal,
Implement Win Detection1:15
So, we could use that to our advantage to calculate the winner. After any move is made, we'll loop through each row, each column, and each diagonal, and then we'll sum up the values. If the values equal minus three, we know that crosses have won. If the values equal three, we know that noughts have won. Simple enough, right? Let's get it implemented inside our view code. Just to make things super clear, I'm going to comment this span out, and I'll output the index of each square in the grid. There we go.
Define Winning Lines Array1:43
and I'll output the index of each square in the grid. There we go. It's exactly as you'd expect, but it will help us visualize our next step. So, let's go ahead in the code here, perhaps just above the fillSquare function. We'll create a const called lines, which is going to be an array of all of the rows, columns, and diagonals. We'll start with rows. So, here we want an array that contains 0, 1, and 2. We'll add that. What do we have next?
We'll add that. What do we have next? Three, four, and five. Let's add that as well. And then six, seven, and eight. Nice. And that defines all of the rows inside our grid. Let's tackle columns next. So, here we'd have zero, three, six. We'd have one, four, and seven.
So, here we'd have zero, three, six. We'd have one, four, and seven. And we'd have two, five, and eight. Finally, we'll tackle the diagonals. So, here we'd have zero, four, and eight. And we'd have two, four, and six. Very good. So, we now have every possible winning line in the game. Our next step would be to loop over these lines and essentially check them against the board state.
Compute Line Sums2:53
Our next step would be to loop over these lines and essentially check them against the board state to see if there is a winner on the board. So, what I'll do here is take each line and map over it. So, this will allow me to return a new value for that line, which is going to be the sum of that row, column, or diagonal. In order to create the sum, well, we can use reduce as we've discussed in previous episodes. So, I'll give the carry. And I'll also have here the index of the square.
So, I'll give the carry. And I'll also have here the index of the square. And I can say something like carry plus boardState.value passing in the index of that square and then a starting value of zero in this case. Okay, so now we have an array of sums for each row, column, and diagonal for each line. So, a winning value would be any of those that are either minus three or three. I'll use find for this.
that are either minus three or three. I'll use find for this. It will provide the sum. And how could I make this check? I could use a simple if check. Or I could use math.abs, I guess. So, something like math.abs passing in the sum is equal to three. So, in case you didn't know, when you use math.abs, if you have a negative integer,
So, in case you didn't know, when you use math.abs, if you have a negative integer, it's going to return the positive version of that integer. So, if we pass 3 into this, 3 will be returned. If we pass -3 into this, 3 will be returned. Meaning it's a very easy way to check for this winning condition. Let's assign this to a constant. So, const winningLine equals. And then here we can just check
So, const winningLine =. And then here we can just check what the value of that winningLine is. So, if winningLine === -3, that would indicate that crosses have won. So, we'll say alert('x has won'). And then let's do an early return here. Underneath we can then say if the winningLine is actually === 3, that means noughts have won.
if the winning line is actually equal to three, that means noughts have won. So, we'll alert nought has won. Exclamation mark. And now let's test it in the browser. We'll put a cross in the top left, and in the middle, and in the top right. And there we go. We can see that crosses have won. Let's reset the game.
This is just a simple explanation with no code.
Add Stalemate Condition5:17
Awesome. So, this is actually a working version of tic-tac-toe with automatic detection for victory. But what if nobody wins? It's highly possible in a game of tic-tac-toe to have a stalemate. So, let's make sure we add that condition in as well. How would we calculate a stalemate? Well, really, a stalemate happens when no more moves can be made,
Well, really, a stalemate happens when no more moves can be made, and there is no victor. So, essentially, if there was no zeros left in the board state, that would indicate that every square has been filled. Then, if we come down to fill square, after we've checked for a winning state, if that hasn't happened, but there are no zeros left in board state, it would indicate that we must be at a stalemate.
but there are no zeros left in boardState, it would indicate that we must be at a stalemate. So, we can add that pretty easily. I'll do an early return on winningLine here. And we can say something like, if not, and then we're looking for boardState.value, and we'll use the includes function to check for a specific value, in this case, zero. So, if the board does not include the value zero, we're going to alert and say stalemate.
So, if the board does not include the value zero, we're going to alert and say stalemate. There we go. Let's test that. We'll put an X on the left here, and we'll fill with a 0, cross in the middle, 0, cross on the right here, 0, cross top middle, 0. Classic.
cross top middle, 0. Classic. It's so difficult to get a stalemate when you actually don't want one. Let's try that again. Cross, 0, cross, 0, cross, 0, cross, 0, cross. There we go. That's more difficult than it seems. But there we go.
That's more difficult than it seems. But there we go. We've got a stalemate. We can see that that logic works. Absolutely perfect. So, the logic is now in place to detect when a game of tic-tac-toe is won or when a stalemate occurs. And that really lays the groundwork for everything else we're going to do in this series.
UI Display Homework7:06
And that really lays the groundwork for everything else we're going to do in this series. Now, a little bit of homework. Obviously, a browser alert isn't the nicest way of displaying victory. So, I want you to just go away and play with, instead, displaying victory in the UI, in some other form, right? Showing it on screen, and then, also, after the victory has happened,
Showing it on screen, and then, also, after the victory has happened, resetting the board back to its initial state so that you can play again. And once you've got that in place, however you'd like, come back to the next episode and we'll pick up there.
