From df800f05416aa11bd04501b6dd771307d05dc8b7 Mon Sep 17 00:00:00 2001 From: Santo Cariotti Date: Mon, 20 Jun 2022 14:53:17 +0200 Subject: Add exercises --- Year_3/Blockchain/TicTacToe.sol | 153 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 Year_3/Blockchain/TicTacToe.sol (limited to 'Year_3/Blockchain/TicTacToe.sol') diff --git a/Year_3/Blockchain/TicTacToe.sol b/Year_3/Blockchain/TicTacToe.sol new file mode 100644 index 0000000..582e10d --- /dev/null +++ b/Year_3/Blockchain/TicTacToe.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: None + +pragma solidity ^0.8.0; + +contract TicTacToe { + enum Player { X, O } + struct PlayerInfo { + address payable id; + Player p_type; + } + enum Cell { X, O, NONE } + enum GameStatus { TURN_X, TURN_O, WAIT, END } + + mapping(address => PlayerInfo) players; + address[2] playerIds; + Cell[3][3] cells; + Player turn; + GameStatus status = GameStatus.WAIT; + uint immutable minFee; + uint fee; + uint8 moves = 9; + + event Movement(address sender, Player player, Cell[3][3] cells); + event EndGame(address winner, uint amount); + + constructor(address payable firstPlayer, address payable secondPlayer, uint _minFee) { + require(firstPlayer != address(0) && secondPlayer != address(0), "You must define both address"); + require(firstPlayer != secondPlayer, "Players must be different"); + + players[firstPlayer] = PlayerInfo({ + id: firstPlayer, + p_type: Player.X + }); + playerIds[0] = firstPlayer; + players[secondPlayer] = PlayerInfo({ + id: secondPlayer, + p_type: Player.O + }); + playerIds[1] = secondPlayer; + minFee = _minFee; + turn = Player(getRandomTurn()); + + for (uint8 i = 0; i < 3; ++i) + for (uint8 j = 0; j < 3; ++j) + cells[i][j] = Cell.NONE; + } + + function play(uint x, uint y) public payable { + require(status != GameStatus.END, "Game is over"); + require(players[msg.sender].id != address(0), "You're not one of the players"); + require(players[msg.sender].p_type == turn, "It's not your turn"); + require(msg.value >= minFee, "Value is less than the min fee"); + + fee += msg.value; + + if (cells[y][x] != Cell.NONE) { + revert("Can't use this cell"); + } + + cells[y][x] = (turn == Player.X ? Cell.X : Cell.O); + turn = Player(1 - uint(turn)); + moves--; + checkGame(); + } + + function getBoard() public view returns (Cell[3][3] memory) { + return cells; + } + + /* + ------------- + | | | | + |---|---|---| + | | | | + |---|---|---| + | | | | + ------------- + */ + + function checkGame() internal { + // It's useless to check when moves > 4 + if (moves > 4) return; + + bool result = false; + PlayerInfo memory winner; + + if (moves == 0) { + emit EndGame(address(this), fee); + status = GameStatus.END; + } + + // Diagonal wins + if ( + (cells[0][0] == cells[1][1] && cells[0][0] == cells[2][2]) || + (cells[0][2] == cells[1][1] && cells[0][2] == cells[2][0]) + ) { + address addr = address(0); + if (cells[0][0] != Cell.NONE) { + addr = playerIds[uint256(cells[0][0])]; + winner = players[addr]; + assert(uint(winner.p_type) == uint(cells[0][0])); + result = true; + } else if (cells[0][2] != Cell.NONE) { + addr = playerIds[uint256(cells[0][2])]; + winner = players[addr]; + assert(uint(winner.p_type) == uint(cells[0][2])); + result = true; + } + } + + if (!result) { + for (uint8 i = 0; i < 3; i+=3) { + for (uint8 j = 0; j < 3; j+=3) { + if (cells[i][j] == Cell.NONE) continue; + + address addr = playerIds[uint256(cells[i][j])]; + + if ( + (cells[i][j] == cells[i+1][j] && cells[i][j] == cells[i+2][j]) || + (cells[i][j] == cells[i][j+1] && cells[i][j+1] == cells[i][j+2]) + ) { + result = true; + } + + if (result) { + winner = players[addr]; + assert(uint(winner.p_type) == uint(cells[i][j])); + break; + } + + } + + if (result) break; + } + } + + if (result && winner.id != address(0)) { + assert(fee == address(this).balance); + winner.id.transfer(fee); + status = GameStatus.END; + emit EndGame(winner.id, fee); + fee = 0; + } + } + + function getRandomTurn() internal view returns (uint8) { + return uint8( + uint256( + keccak256(abi.encode(block.timestamp, block.difficulty)) + ) % 2 + ); + } +} -- cgit v1.2.3-18-g5258