-
Notifications
You must be signed in to change notification settings - Fork 0
/
RSP.sol
161 lines (140 loc) · 5.12 KB
/
RSP.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract RPS {
constructor() payable {}
enum Hand {
rock,
paper,
scissors
}
enum PlayerStatus {
STATUS_WIN,
STATUS_LOSE,
STATUS_TIE,
STATUS_PENDING
}
enum GameStatus {
STATUS_NOT_STARTED,
STATUS_STARTED,
STATUS_COMPLETE,
STATUS_ERROR
}
struct Player {
address payable addr;
uint256 playerBetAmount;
bytes32 hand;
PlayerStatus playerStatus;
uint result;
uint count;
}
struct Game {
Player originator;
Player taker;
uint256 betAmount;
GameStatus gameStatus;
}
mapping(uint256 => Game) rooms;
uint256 roomLen = 0;
function keccak(uint256 _hand, string memory _key) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_hand, _key));
}
function createRoom(bytes32 _hand) public payable returns (uint256 roomNum) {
rooms[roomLen] = Game({
betAmount : msg.value,
gameStatus : GameStatus.STATUS_NOT_STARTED,
originator : Player({
hand : _hand,
addr : payable(msg.sender),
playerStatus : PlayerStatus.STATUS_PENDING,
playerBetAmount : msg.value,
result : 0,
count : 0
}),
taker : Player({
hand : 0,
addr : payable(msg.sender),
playerStatus : PlayerStatus.STATUS_PENDING,
playerBetAmount : 0,
result : 0,
count : 0
})
});
roomNum = roomLen;
roomLen = roomLen + 1;
}
function joinRoom(uint256 roomNum, bytes32 _hand) public payable {
require(msg.value == rooms[roomNum].betAmount);
rooms[roomNum].taker = Player({
hand : _hand,
addr : payable(msg.sender),
playerStatus : PlayerStatus.STATUS_PENDING,
playerBetAmount : msg.value,
result : 0,
count : 0
});
rooms[roomNum].betAmount = rooms[roomNum].betAmount + msg.value;
}
function useOriginator(uint256 _roomNum, uint256 _hand, string memory _secretKey) public {
require(msg.sender == rooms[_roomNum].originator.addr);
require(rooms[_roomNum].originator.hand == keccak(_hand, _secretKey));
rooms[_roomNum].originator.result = _hand;
rooms[_roomNum].originator.count = 1;
}
function useTaker(uint256 _roomNum, uint256 _hand, string memory _secretKey) public {
require(msg.sender == rooms[_roomNum].taker.addr);
require(rooms[_roomNum].taker.hand == keccak(_hand, _secretKey));
rooms[_roomNum].taker.result = _hand;
rooms[_roomNum].taker.count = 1;
}
function compareHands(uint256 roomNum) private {
require(rooms[roomNum].taker.count == 1 && rooms[roomNum].originator.count == 1);
uint8 originator = uint8(rooms[roomNum].originator.result);
uint8 taker = uint8(rooms[roomNum].taker.result);
rooms[roomNum].gameStatus = GameStatus.STATUS_STARTED;
if (taker == originator) {
rooms[roomNum].originator.playerStatus = PlayerStatus.STATUS_TIE;
rooms[roomNum].taker.playerStatus = PlayerStatus.STATUS_TIE;
} else if ((taker + 1) % 3 == originator) {
rooms[roomNum].originator.playerStatus = PlayerStatus.STATUS_WIN;
rooms[roomNum].taker.playerStatus = PlayerStatus.STATUS_LOSE;
} else if ((originator + 1) % 3 == taker) {
rooms[roomNum].originator.playerStatus = PlayerStatus.STATUS_LOSE;
rooms[roomNum].taker.playerStatus = PlayerStatus.STATUS_WIN;
} else {
rooms[roomNum].gameStatus = GameStatus.STATUS_ERROR;
}
}
modifier isPlayer(uint256 roomNum, address sender) {
require(
sender == rooms[roomNum].originator.addr ||
sender == rooms[roomNum].taker.addr
);
_;
}
function payout(uint256 roomNum) public payable isPlayer(roomNum, msg.sender) {
compareHands(roomNum);
if (
rooms[roomNum].originator.playerStatus == PlayerStatus.STATUS_TIE &&
rooms[roomNum].taker.playerStatus == PlayerStatus.STATUS_TIE
) {
rooms[roomNum].originator.addr.transfer(
rooms[roomNum].originator.playerBetAmount
);
rooms[roomNum].taker.addr.transfer(rooms[roomNum].taker.playerBetAmount);
} else {
if (rooms[roomNum].originator.playerStatus == PlayerStatus.STATUS_WIN) {
rooms[roomNum].originator.addr.transfer(rooms[roomNum].betAmount);
} else if (rooms[roomNum].taker.playerStatus == PlayerStatus.STATUS_WIN) {
rooms[roomNum].taker.addr.transfer(rooms[roomNum].betAmount);
} else {
rooms[roomNum].originator.addr.transfer(
rooms[roomNum].originator.playerBetAmount
);
rooms[roomNum].taker.addr.transfer(
rooms[roomNum].taker.playerBetAmount
);
}
rooms[roomNum].gameStatus = GameStatus.STATUS_COMPLETE;
}
}
}