Created
September 14, 2018 04:36
-
-
Save guymorita/d9d85dfa886a9717e781de6d28e08210 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.25+commit.59dbf8f1.js&optimize=false&gist=
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.24; | |
import "github.com/OpenZeppelin/zeppelin-solidity/contracts/ownership/Ownable.sol"; | |
contract TicTacToe is Ownable { | |
uint gameCount = 0; | |
mapping(uint => Game) games; | |
mapping(address => Game) latestGame; | |
struct Game { | |
uint gameId; | |
uint movesMade; | |
uint wager; | |
uint8[] gameboard; | |
address player1; | |
address player2; | |
address nextPlayer; | |
address winner; | |
bool player2Paid; | |
bool winningsWithdrawn; | |
} | |
// Private | |
// Todo: Make truly random | |
function randomBool() private view returns (bool) { | |
return uint8(uint256(keccak256(block.timestamp, block.difficulty))%2) == 1; | |
} | |
function checkVertical(uint8[] gameboard, uint8 playerVal) private pure returns (bool) { | |
for (uint i = 0; i < 3; i++) { | |
if (playerVal * 3 == (gameboard[i] + gameboard[i+3] + gameboard[i+6])) return true; | |
} | |
return false; | |
} | |
function checkHorizontal(uint8[] gameboard, uint8 playerVal) private pure returns (bool) { | |
for (uint i = 0; i < 9; i+=3) { | |
if (playerVal * 3 == (gameboard[i] + gameboard[i+1] + gameboard[i+2])) return true; | |
} | |
return false; | |
} | |
function checkDiagonal(uint8[] gameboard, uint8 playerVal) private pure returns (bool) { | |
if (playerVal * 3 == (gameboard[0] + gameboard[4] + gameboard[8])) return true; | |
if (playerVal * 3 == (gameboard[2] + gameboard[4] + gameboard[6])) return true; | |
return false; | |
} | |
function checkWinner(uint8[] gameboard, uint8 playerVal) private pure returns (bool) { | |
if (checkVertical(gameboard, playerVal)) return true; | |
if (checkHorizontal(gameboard, playerVal)) return true; | |
if (checkDiagonal(gameboard, playerVal)) return true; | |
return false; | |
} | |
function resetGame(uint gameId) private returns (uint8[] gameboard) { | |
Game storage g = games[gameId]; | |
require(g.movesMade == 9, "Still need to finish game"); | |
g.gameboard = new uint8[](9); | |
g.nextPlayer = randomBool() ? g.player1 : g.player2; | |
g.movesMade = 0; | |
return g.gameboard; | |
} | |
// Public | |
function createGame() public payable returns (uint gameId) { | |
gameId = gameCount++; | |
games[gameId] = Game( | |
gameId, | |
0, | |
msg.value, | |
new uint8[](9), | |
msg.sender, | |
address(0), | |
address(0), | |
address(0), | |
false, | |
false | |
); | |
latestGame[msg.sender] = games[gameId]; | |
return gameId; | |
} | |
function joinGame(uint gameId) public payable returns (address nextPlayer) { | |
Game storage g = games[gameId]; | |
require(msg.sender != g.player1, "Player 2 needs to be a different than player 1"); | |
require(msg.value == g.wager, "Please send the correct amount of wei to join the game"); | |
require(g.player2 == address(0), "Player 2 has already been chosen"); | |
g.player2 = msg.sender; | |
g.player2Paid = true; | |
g.nextPlayer = randomBool() ? g.player1 : g.player2; | |
latestGame[msg.sender] = g; | |
return g.nextPlayer; | |
} | |
function makeMove(uint gameId, uint position) public returns (uint8[] gameboard) { | |
Game storage g = games[gameId]; | |
uint pos = position - 1; | |
require(g.nextPlayer != address(0), "Player has not joined yet"); | |
require(g.nextPlayer == msg.sender, "Wrong player"); | |
require(g.winner == address(0), "A winner has already been decided"); | |
require(pos >= 0 && pos < 9, "Invalid move. Please choose between 1-9"); | |
require(g.gameboard[pos] == 0, "Position not empty"); | |
uint8 playerVal = g.player1 == msg.sender ? 1 : 8; | |
g.gameboard[pos] = playerVal; | |
g.movesMade++; | |
if (g.movesMade > 4) { | |
if (checkWinner(g.gameboard, playerVal)) { | |
g.winner = msg.sender; | |
} else if (g.movesMade == 9) { | |
return resetGame(gameId); | |
} | |
} | |
g.nextPlayer = g.nextPlayer == g.player1 ? g.player2 : g.player1; | |
return g.gameboard; | |
} | |
function withdrawWinnings(uint gameId) public returns (bool) { | |
Game storage g = games[gameId]; | |
require(g.winner != address(0), "Game not finished"); | |
require(g.winningsWithdrawn == false, "Winnings already paid out"); | |
g.winningsWithdrawn = true; | |
g.winner.transfer(g.wager * 2); | |
return true; | |
} | |
// Getters | |
function getLatestGame() public view returns (uint gameId) { | |
Game storage g = latestGame[msg.sender]; | |
return g.gameId; | |
} | |
function getBoard(uint gameId) public view returns (uint8[] gameboard) { | |
Game storage g = games[gameId]; | |
return g.gameboard; | |
} | |
function getNextPlayer(uint gameId) public view returns (address nextPlayer) { | |
Game storage g = games[gameId]; | |
return g.nextPlayer; | |
} | |
function getWinner(uint gameId) public view returns (address winner) { | |
Game storage g = games[gameId]; | |
return g.winner; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment