Created
June 10, 2019 11:41
-
-
Save snario/7f4fd39689eaeda992a47d97577cafe8 to your computer and use it in GitHub Desktop.
This file contains hidden or 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.5.9; | |
pragma experimental ABIEncoderV2; | |
library TicTacToe { | |
enum OutcomeType { | |
PLAYER_X_WON, | |
PLAYER_O_WON, | |
DRAW | |
} | |
enum PlayerType { None, X, O } | |
struct AppState { | |
PlayerType[3][3] board; | |
PlayerType claimToVictory; | |
} | |
function placeX(AppState calldata state, uint8 posX, uint8 posY) | |
external | |
pure | |
returns (AppState memory) | |
{ | |
require( | |
state.claimToVictory == PlayerType.None, | |
"Cannot place an X on a board where there is already a winner." | |
); | |
require( | |
state.board[posX][posY] == PlayerType.None, | |
"Cannot place an X on an already filled spot on the board." | |
); | |
AppState memory newState = state; | |
newState.board[posX][posY] = PlayerType.X; | |
newState.claimToVictory = computeVictoryClaimant( | |
newState.board, | |
PlayerType.X | |
); | |
return newState; | |
} | |
function placeO(AppState calldata state, uint8 posX, uint8 posY) | |
external | |
pure | |
returns (AppState memory) | |
{ | |
require( | |
state.claimToVictory == PlayerType.None, | |
"Cannot place an O on a board where there is already a winner." | |
); | |
require( | |
state.board[posX][posY] == PlayerType.None, | |
"Cannot place an O on an already filled spot on the board." | |
); | |
AppState memory newState = state; | |
newState.board[posX][posY] = PlayerType.O; | |
newState.claimToVictory = computeVictoryClaimant( | |
newState.board, | |
PlayerType.O | |
); | |
return newState; | |
} | |
function computeVictoryClaimant( | |
PlayerType[3][3] memory board, | |
PlayerType expectedWinner | |
) | |
internal | |
pure | |
returns (PlayerType) | |
{ | |
PlayerType ret = PlayerType.None; | |
if ( | |
board[0][0] == expectedWinner && | |
board[0][1] == expectedWinner && | |
board[0][2] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[1][0] == expectedWinner && | |
board[1][1] == expectedWinner && | |
board[1][2] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[2][0] == expectedWinner && | |
board[2][1] == expectedWinner && | |
board[2][2] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[0][0] == expectedWinner && | |
board[1][0] == expectedWinner && | |
board[2][0] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[0][1] == expectedWinner && | |
board[1][1] == expectedWinner && | |
board[2][1] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[0][2] == expectedWinner && | |
board[1][2] == expectedWinner && | |
board[2][2] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[0][0] == expectedWinner && | |
board[1][1] == expectedWinner && | |
board[2][2] == expectedWinner | |
) | |
return expectedWinner; | |
if ( | |
board[2][0] == expectedWinner && | |
board[1][1] == expectedWinner && | |
board[0][2] == expectedWinner | |
) | |
return expectedWinner; | |
return ret; | |
} | |
function computeOutcome(AppState calldata appState) | |
external | |
pure | |
returns (OutcomeType) | |
{ | |
uint8 xCount = 0; | |
uint8 oCount = 0; | |
for (uint8 x = 0; x < 3; x++) { | |
for (uint8 y = 0; y < 3; y++) { | |
if (appState.board[x][y] == PlayerType.X) { | |
xCount++; | |
} else if (appState.board[x][y] == PlayerType.O) { | |
oCount++; | |
} | |
} | |
} | |
if (xCount >= oCount) { | |
return OutcomeType.PLAYER_X_WON; | |
} else if (xCount == oCount && xCount + oCount == 9) { | |
return OutcomeType.PLAYER_O_WON; | |
} else { | |
return OutcomeType.DRAW; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment