3.0 A High Stakes GameΒΆ

OK how about a friendly wager!

  1. Add a storage variable to hold the placed wagers, beneath uint256 public turnsTaken_;

    mapping(address => uint256) public wagers_;
    
  2. Add a function to allow the players to place a wager

    function placeWager() external payable {
        require(msg.sender == player1_ || msg.sender == player2_, "Not a valid player.");
        wagers_[msg.sender] = msg.value;
    }
    
  3. Update the logic if a winner is found to transfer all the value to them, within the takeTurn function

    msg.sender.transfer(address(this).balance);
    
    • Result:

      if (isWinner(msg.sender)) {
          winner_ = msg.sender;
          gameOver_ = true;
          msg.sender.transfer(address(this).balance);
      } else if (turnsTaken_ == 9) {
          gameOver_ = true;
      }
      
  4. Update the logic to refund the value if a draw has occured, within the takeTurn function

    player1_.transfer(wagers_[player1_]);
    player2_.transfer(wagers_[player2_]);
    
    • Result:

      if (isWinner(msg.sender)) {
          winner_ = msg.sender;
          gameOver_ = true;
          msg.sender.transfer(address(this).balance);
      } else if (turnsTaken_ == 9) {
          gameOver_ = true;
          player1_.transfer(wagers_[player1_]);
          player2_.transfer(wagers_[player2_]);
      }
      

Go play! Earn some ETH.

  • As above Final solution may be found here

Homework!

  • What happens when a new game wants to be started in the same contract?
  • How to allow this? When to allow this? Reset storage variables?

Important

All done? We recommend reviewing the complementary video series found here.


  • Completed code:

    pragma solidity 0.4.24;
    
    
    contract TicTacToe {
    
        address public player1_;
        address public player2_;
        mapping(address => uint256) public playerNumbers_;  // Map ugly address to number for simpler inspection of game board
        address public lastPlayed_;
        address public winner_;
        bool public gameOver_;
        uint256 public turnsTaken_;
        mapping(address => uint256) public wagers_;
    
        /** The game board itself
        * 0, 1, 2
        * 3, 4, 5
        * 6, 7, 8
        */
        uint256[9] private gameBoard_;
    
        function startGame(address _player1, address _player2) external {
                player1_ = _player1;
                playerNumbers_[_player1] = 1;
    
                player2_ = _player2;
                playerNumbers_[_player2] = 2;
        }
    
        /**
        * @notice Take your turn, selecting a board location
        * @param _boardLocation Location of the board to take
        */
        function takeTurn(uint256 _boardLocation) external {
            require(msg.sender == player1_ || msg.sender == player2_, "Not a valid player.");
            require(gameBoard_[_boardLocation] == 0, "Spot taken!");
            require(msg.sender != lastPlayed_, "Not your turn.");
            require(!gameOver_, "Sorry game has concluded.");
    
            gameBoard_[_boardLocation] = playerNumbers_[msg.sender];
            lastPlayed_ = msg.sender;
    
            if (isWinner(msg.sender)) {
                winner_ = msg.sender;
                gameOver_ = true;
                msg.sender.transfer(address(this).balance);
            } else if (turnsTaken_ == 9) {
                gameOver_ = true;
                player1_.transfer(wagers_[player1_]);
                player2_.transfer(wagers_[player2_]);
            }
    
            turnsTaken_++;
        }
    
        function getBoard() external view returns(uint256[9]) {
            return gameBoard_;
        }
    
        function isWinner(address player) private view returns(bool) {
            uint8[3][8] memory winningFilters = [
                [0,1,2],[3,4,5],[6,7,8],  // rows
                [0,3,6],[1,4,7],[2,5,8],  // columns
                [0,4,8],[6,4,2]           // diagonals
            ];
    
            for (uint8 i = 0; i < winningFilters.length; i++) {
                uint8[3] memory filter = winningFilters[i];
    
                if (
                    gameBoard_[filter[0]]==playerNumbers_[player] &&
                    gameBoard_[filter[1]]==playerNumbers_[player] &&
                    gameBoard_[filter[2]]==playerNumbers_[player]
                ) {
                    return true;
                }
            }
        }
    }