-
Notifications
You must be signed in to change notification settings - Fork 0
/
singlehand.rsh
124 lines (113 loc) · 2.87 KB
/
singlehand.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
'reach 0.1';
import 'rps.rsh'
//
// Rock Paper Scissors
//
// FEATURES
// - Make game fair
// 1. Alternate first moves
// - Make game more efficient O(3n)
// 1. Optimize for case where there is no draw
//
const DEADLINE = 100;
const Player =
{
...hasRandom,
getHand: Fun([], UInt),
seeOutcome: Fun([UInt], Null),
informTimeout: Fun([], Null),
};
const Alice =
{
...Player,
wager: UInt,
};
const Bob =
{
...Player,
acceptWager: Fun([UInt], Null),
};
export const main =
Reach.App(
{},
[Participant('Alice', Alice), Participant('Bob', Bob)],
(A, B) => {
const isEvenTurn = state => state.turn % 2 === 0;
const informTimeout = () => {
each([A, B], () => {
interact.informTimeout();
});
};
const playHands = (state, C, D) => {
C.only(() => {
const _handA = interact.getHand();
const [_commitA, _saltA] = makeCommitment(interact, _handA);
const commitA = declassify(_commitA);
});
C.publish(commitA)
.timeout(DEADLINE, () => closeTo(B, informTimeout));
commit();
unknowable(D, C(_handA, _saltA));
D.only(() => {
const handB = declassify(interact.getHand())
});
D.publish(handB)
.timeout(DEADLINE, () => closeTo(C, informTimeout));
commit();
C.only(() => {
const [saltA, handA] = declassify([_saltA, _handA]);
});
C.publish(saltA, handA)
.timeout(DEADLINE, () => closeTo(D, informTimeout));
checkCommitment(commitA, saltA, handA);
return {
outcome: winner(handA, handB),
turn: state.turn + 1
};
}
const playRound = (state, C, D) => {
commit();
return playHands(state, C, D);
}
A.only(() => {
const wager = declassify(interact.wager);
const _handA = interact.getHand();
const [_commitA, _saltA] = makeCommitment(interact, _handA);
const commitA = declassify(_commitA);
});
A.publish(wager, commitA)
.pay(wager)
.timeout(DEADLINE, () => closeTo(B, informTimeout));
commit();
unknowable(B, A(_handA, _saltA));
B.only(() => {
interact.acceptWager(wager);
const handB = declassify(interact.getHand())
});
B.publish(handB)
.pay(wager)
.timeout(DEADLINE, () => closeTo(A, informTimeout));
commit();
A.only(() => {
const [saltA, handA] = declassify([_saltA, _handA]);
});
A.publish(saltA, handA)
.timeout(DEADLINE, () => closeTo(B, informTimeout));
checkCommitment(commitA, saltA, handA);
var state = { outcome: winner(handA, handB), turn: 1 };
invariant(balance() == 2 * wager && isOutcome(state.outcome));
while (state.outcome == DRAW) {
state = isEvenTurn(state)
? playRound(state, A, B)
: playRound(state, B, A)
continue;
}
assert(state.outcome == A_WINS || state.outcome == B_WINS);
transfer(2 * wager).to(state.outcome == A_WINS ? A : B);
commit();
each([A, B], () => {
interact.seeOutcome(state.outcome);
});
exit();
}
);