Winning Part 1 - Horizontal and Vertical
Start course
2h 36m

In this course, we begin building a game in Solidity, and more specifically, we begin to look at defining the mechanics and the components of the game.


In the previous lecture, we were talking about how to check if it's a draw or not, but we didn't take into account any winning. So, when we tested our game, no matter what we put into the single fields of our three in a row game field, at the end it had to be a draw. So, in this lecture, we're going to talk about how to check if it's a win. And we are splitting the web in two parts. The first one will really be checking horizontal and vertical wins and then paying out the player and the next part will be the diagonal wins. Okay, I've drawn this beautiful game field here in order to explain some theory of what we're going to do now. We are going to check in the first part, the horizontal and vertical wins. So, that means if let's say player1 has already a field here in box number 01 and he has his own address already in box number 21, then he is going to place it in 11 so, in the center row; then our algorithm should go in and check. Okay, first is he having something here, here, and here? Then, it's a win. If it's not him here, then we don't need to check any further the column, we can already stop checking that. Furthermore, is he having his own address here in the same row? On the left column and the center column where you just set it in and on the right column; then it's a win as well. If here or here, he doesn't have any stone set or his address set, then it's not a win. So, how could we model this? And it is fairly straightforward when you think about it. We have one for loop which is going from zero to our boardSize but not including our boardSize, so from 0-3. And we are going to check if the board in the right column has all three of his addresses set or in the right row all three of his addresses set. And if that's so, then we are going to call the set winner function. Let's get started. We have one column and I'm going to make this a uint8, i = 0 because we are not going beyond 255 and our i must be smaller than the boardSize and every time on every iteration we increase our i. Now, we are doing, we are not checking if all three of them have the player set, we are checking if somewhere is the player not set and break this for loop. And if the i reaches the number three or the number two, actually, boardSize -1, then we have a winner. So, if board, no gameBoard has in the current row at the column where the user just set his stone not and it's not the activePlayer, so not the player that is currently playing, then we break this for loop. So, we stop here. On the other hand, if the (i == boardSize - 1), then we can call setWinner with the activePlayer which is going to get the money and we return here. We don't have to do anything further. The winner is set. Now, a little coding challenge at this point is we have the game logic now for the column Y and the row 1, 2, and 3 or 0, 1, 2. And now, we are going, we have to implement the same for as a row, but the columns 1, 2, 3. So, go ahead if you want to do the coding challenge, then pause the video now or else I will explain it to you in a second. Okay, now let me show you how this is done obviously. We have the very, very same structure and the only thing we have to change is we are going on the row that the user just selected and we are jumping in the columns. And then if the player is not the activePlayer, then we go out and if we reach the boardSize, then we have a winner. Now, let's talk about winning here. First of all, if we have a winner, then we have this, where is it; SetWinner function where we have a player and that player needs to get some money, obviously. And the structure how we get the money is not very different from the setDraw function. Just that in this case our player, our activePlayer is getting all the money and the other player is getting nothing. So, let's try this. First of all, we have the balanceToPayOut is the balance of the current smart contract and then what we try is if(_player.send(balanceToPayOut) is not true, then we have to see if the player is the player1 or the player2 and then we credit the amount to pay out to that player. So, in our case, it's going to be if(_player == player1) then balanceToWithdraw Player1 is; actually increase that balanceToPayOut or else it's balanceToWithdraw from player1 and there is one last thing which is missing from the whole structure here. If we have a winner and it's already after, let's say the fifth round where somebody has already his first row finished, then we have to make sure that the game cannot be played anymore. And ideally, I'm going to make this with just the boolean here which says the game is active, true or false and we have to set this at the right place. So, gameActive, it's going to be initialized with a false value as soon as the game starts with join the game, then we have to set this to true and we can also assert here that nobody can come in and join the game again. You never know. And during the setStone, we have an assertion that the game must be active. So, if the game isn't active, then we cannot set the stone anymore. Now, let's give this a try. I'm going over here to the run tab. I'm selecting the 'JavaScript VM'. I'm deploying my GameManager. I'm starting a new game with 0.1 ether, start a new game, getting the address of the game. Starting to interact with the right smart contract. With my second address, I'm going to join the game. Okay, who is the player? It's again the one that is selected here. Set the Stone to 0,0. Our other players sets a stone to 1,0 second row, first column. So, that works. Our player1 sets it to 0,1 so he almost has the first row full. The other player sets it to 1,1 following in the second row. And now, comes the crucial moment. Let's observe we have here 99.89 ether so if we set this to 0,2, then we should automatically receive the payout and it doesn't, why is that? Because we are setting the activePlayer to the other player before we're actually checking if there is a win. So, I'm going to remove this over here. I'm putting it down here where we are having the last action of our setStone function and now, I also forgot one last part which is setting the gameActive = false if we have a winner, and now I would have to go in and restart all the transaction but I think there is a better way. I can just take these transactions recorded here from the side, save it to my scenario_testwin, remove the part of the scenario. And so, what I'm going to do next and what I'm going to do next is I just reload here to have a fresh clean a run for this game and we start from scratch. I'm going to deploy this. I'm going to send 0.1 ether to the GameManager. I'm going to take my smart contract once more, I go to ThreeInARow game, I say it's running under specific address. I'm going to select my other account. Going to set 0.1 ether to join the game. And now, if everything is according to whatever was before, we're having the next player again this one; so we set the stone to 0,0. We select the other player, set the stone to 0,1 not 1,0, sorry, for a second row first column, first row second column, second row second column. And now, comes the moment of truth, first row third column and here we go. We have 0.2 ethers more in our account and our game ended. Let's try this once more if our other player were to set the stone again, it fails because our game is not active anymore. In the next lecture, we're talking about checking the diagonal and the anti-diagonal and then we are pretty done with our game. The last thing that we have to do then is going into the high scores and combining everything with this high score manager. That will be another large lecture. But all in all, you're pretty prepared for reading any smart contract now out there. There shouldn't be anything that surprises you, this is all just how solidity works. And congratulations at this part. If you followed along until here, wow, you are pretty ready to go out and start developing your own smart contracts. And I'll see you in the next lecture.


About the Author

Tom is a CTO, senior back-end developer, and systems architect with over twenty years of hands-on development experience in a variety of languages and systems. He has a CS master's degree and has been working with Ethereum and blockchain technologies since 2016.