Skip to content

Instantly share code, notes, and snippets.

@guymorita
Created September 14, 2018 04:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guymorita/d9d85dfa886a9717e781de6d28e08210 to your computer and use it in GitHub Desktop.
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=
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