-
Notifications
You must be signed in to change notification settings - Fork 4
/
index.rsh
168 lines (139 loc) · 4.92 KB
/
index.rsh
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
162
163
164
165
166
167
168
'reach 0.1';
/*
* Problem Analysis
- Who involved in this application
1. step: 1 observer and 10 players
2. step: 1 observer and N players
- What info do they know at start?
Observer has the game and knows the payout for duration
Players know the moves and duration they will play
- What info they will know in the application?
Players will learn the payout for every duration.
They will decide the move and decision and send it to Observer, paying the amount
Observer will learn players moves and durations.
- What funds will change ownership?
1. step: duration * payoutPerDuration is transactioned every time.
At the end of the game balance is transferred to a charity.
2. step: duration * payoutPerDuration is transactioned every time.
Every time an important step happens in game, the last move maker takes the money.
* Data Definition
duration: UInt
move: UInt
payoutPerDuration: UInt
moveLimit: UInt
* Participate Interfaces
? Observer
{
getParams = {
payoutPerDuration: UInt,
moveLimit = UInt
}
}
? Player
{
confirmMove = Fun([UInt], Tuple(Bool, (move) UInt, (duration) UInt, (toPay) UInt))
}
* Communication Construction
-> Observer sets the payoutPerDuration and moveLimit,
-> While total moves are less than moveLimit:
-> Ask particioant to play a move
-> If player accepts:
-> Pay the price to consensus, publish the move
-> Else
-> Let others know player refuses
-> Pay the balance to observer.
Finish the program
*/
// ! Code needs to be brutally refactored
/*
* For now totalTurns must be defined before-hand.
* Also frontend must define the player count either
? - 1. By embeding it to the frontend code
? - 2. By asking it before the game starts
* Every turn players add their moves to a list in the frontend and observer
* pushes this list to the server by an API call (Not implemented yet).
* For test purposes players return random numbers
FINISHED: Make players return single values, store it in the frontend
FINISHED: (IMPORTANT) Make players get the list from Observer,
change it and then send it back to Observer. Make interface for that
Make it work in the while-loop(I guess)
FINISHED: Try to observe one move at a time (again)
FINISHED: Rethink the turn concept in the game.
Maybe while is looping every move.
FINISHED: (SECOND STEP) Add race to the game
*/
const timeoutBlocks = 30;
const ObserverInterface = {
getParams: Fun([], Object({
payoutPerDuration: UInt,
moveLimit: UInt,
})),
observeMove: Fun([UInt, UInt, UInt, Bytes(32)], Null),
observeGameFinish: Fun([], Null),
observeTurnStart: Fun([UInt], Null),
observeTimeout: Fun([], Null)
};
const PlayerInterface = {
acceptMove: Fun([UInt], Bool),
getMove: Fun([], Tuple(UInt, UInt, Bytes(32))),
};
export const main = Reach.App(
{}, [
['Observer', ObserverInterface],
['class', 'Player', PlayerInterface]
],
(Observer, Player) => {
Observer.only(() => {
const _params = interact.getParams();
assume(_params.moveLimit > 0);
const [payoutPerDuration, moveLimit] = declassify([_params.payoutPerDuration, _params.moveLimit]);
});
Observer.publish(payoutPerDuration, moveLimit);
require(moveLimit > 0);
//commit();
const [movePlayed, totalPayout] =
parallel_reduce([0, 0])
.invariant(balance() == totalPayout)
.while(movePlayed < moveLimit)
.case(Player,
(() => {
const [_move, _duration, _name] = interact.getMove();
assume(_move > 0 && _duration > 0, "[ERROR] Invalid Move");
const [move, duration, name] = declassify([_move, _duration, _name]);
const response = declassify(interact.acceptMove(payoutPerDuration));
return ({
msg: [move, duration, mul(duration, payoutPerDuration), response, name],
});
}), //* Local step
(([m, d, tp, r, n]) => 0), //* Pay step
(([m, d, tp, r, n]) => { // * Consensus step
if (r) {
commit();
Observer.only(() => {
interact.observeMove(m, d, tp, n);
});
Observer.publish();
commit();
Player.only(() => { });
Player.publish().pay(tp);
return [add(movePlayed, 1), add(totalPayout, tp)];
} else {
return [movePlayed, totalPayout];
}
})
)
.timeout(timeoutBlocks, () => {
Observer.only(() => interact.observeTimeout());
Observer.publish();
return [movePlayed, totalPayout];
});
//? If needed we can make it more clear that every player in the dApp observes the moveList
//? by committing and adding a Player.only statement
transfer(balance()).to(Observer);
commit();
Observer.only(() => {
interact.observeGameFinish();
});
exit();
}
);