summaryrefslogtreecommitdiff
path: root/Year_3/Blockchain
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2022-06-17 17:21:25 +0200
committerSanto Cariotti <santo@dcariotti.me>2022-06-17 17:21:25 +0200
commitd6fdeec63a01ba43c5468ecc7c77a37347b0c953 (patch)
tree7979964f0b88f0ae13a8e173049b214d5d701082 /Year_3/Blockchain
parenta5e27da469c6224179b6a27ad89d0c6b534b5ae1 (diff)
Add exercise
Diffstat (limited to 'Year_3/Blockchain')
-rw-r--r--Year_3/Blockchain/RockPaperScissor.sol124
1 files changed, 124 insertions, 0 deletions
diff --git a/Year_3/Blockchain/RockPaperScissor.sol b/Year_3/Blockchain/RockPaperScissor.sol
new file mode 100644
index 0000000..528bc4c
--- /dev/null
+++ b/Year_3/Blockchain/RockPaperScissor.sol
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "TrustworthyRockPaperScissorsTournamentSpecs.sol";
+
+contract TrustworthyRockPaperScissorsTournament is TrustworthyRockPaperScissorsTournamentSpecs {
+ enum Move { ROCK, PAPER, SCISSOR }
+ enum Status { IN_PROGRESS, END }
+ struct PlayerInfo {
+ address payable id;
+ uint8 wins;
+ Move[] games;
+ uint fees;
+ }
+
+ mapping(Player => PlayerInfo) players;
+ uint8 target;
+ uint256 matchFee;
+ Status status;
+ Player winner;
+ address payable owner;
+
+ uint8 override public disputedMatches;
+
+ constructor(
+ address payable firstPlayer,
+ address payable secondPlayer,
+ uint8 targetWins,
+ uint256 singleMatchFee
+ ) {
+ require(firstPlayer != secondPlayer, "Players must be two different addresses.");
+ require(firstPlayer != address(0) && secondPlayer != address(0), "Players address are not valid.");
+
+ players[Player.First].id = firstPlayer;
+ players[Player.Second].id = secondPlayer;
+ target = targetWins;
+ matchFee = singleMatchFee;
+ status = Status.IN_PROGRESS;
+ disputedMatches = 0;
+ owner = payable(msg.sender);
+ }
+
+ function moveRock() external override payable {
+ move(Move.ROCK);
+ }
+
+ function movePaper() external override payable {
+ move(Move.PAPER);
+ }
+
+ function moveScissor() external override payable {
+ move(Move.SCISSOR);
+ }
+
+ modifier mustBeAPlayer() {
+ require(msg.sender == players[Player.First].id || msg.sender == players[Player.Second].id, "You're not one of the players.");
+ _;
+ }
+
+ function move(Move move_type) internal mustBeAPlayer {
+ require(status != Status.END, "Game has already finish");
+ require(msg.value >= matchFee, "You need to pass the minimum fee to play");
+
+ Player p = (msg.sender == players[Player.First].id ? Player.First : Player.Second);
+ players[p].games.push(move_type);
+ players[p].fees += msg.value;
+
+ checkGame();
+ }
+
+ function checkGame() internal {
+ uint8 n = uint8(
+ players[Player.First].games.length < players[Player.Second].games.length
+ ? players[Player.First].games.length
+ : players[Player.Second].games.length
+ );
+
+ for (uint8 i = disputedMatches; i < n; ++i) {
+ Move p1 = players[Player.First].games[i];
+ Move p2 = players[Player.Second].games[i];
+
+ // Fair play
+ if (p1 == p2) continue;
+
+ if (
+ (p1 == Move.ROCK && p2 == Move.SCISSOR) ||
+ (p1 == Move.SCISSOR && p2 == Move.PAPER) ||
+ (p1 == Move.PAPER && p2 == Move.ROCK)
+ ) {
+ players[Player.First].wins++;
+ emit MatchWonBy(Player.First, i);
+ } else {
+ players[Player.Second].wins++;
+ emit MatchWonBy(Player.Second, i);
+ }
+
+ disputedMatches++;
+
+ if (players[Player.First].wins == target) {
+ emit TournamentWonBy(Player.First);
+ winner = Player.First;
+ endGame();
+ } else if (players[Player.Second].wins == target) {
+ emit TournamentWonBy(Player.Second);
+ winner = Player.Second;
+ endGame();
+ }
+ }
+ }
+
+ function endGame() internal {
+ require(status != Status.END, "Game has already finish");
+
+ assert(players[winner].wins == target);
+
+ uint total = players[Player.First].fees + players[Player.Second].fees;
+ assert(total == address(this).balance);
+ players[winner].id.transfer(total);
+
+ status = Status.END;
+ selfdestruct(owner);
+ }
+}