本文章中完成了石头剪刀布游戏基础的框架,包含参与者发布值的教学。
[Reach教程翻译] Reach是安全简单的Dapp开发语言 让用户可以像开发传统App一样开发DApp 目前使用Reach开发的智能合约可以部署在以太坊、Conflux、Algorand Reach官网 Reach官方文挡
在这个部分中,Alice和Bob开始玩猜拳游戏!
首先,我们考虑如何表示出拳的手势。一个简单的方法是分别用数字0、1和2,代表“石头”,“布”和“剪刀”。但是,Reach不支持两位无符号整数,因此最好将它们表示为模数为3的整数等价类,即0和3是相等的,都表示石头。
我们也用一样的方法表示猜拳的三种结果:B赢,平手和A赢。
第一步要修改Reach程序,让我们可以与Alice和Bob的前端交互,获取他们要出的手势,随后通知他们游戏的结果。
1 'reach 0.1';
2
3 const Player = {
4 getHand: Fun([], UInt),
5 seeOutcome: Fun([UInt], Null),
6 };
7
8 export const main = Reach.App(() => {
9 const Alice = Participant('Alice', {
10 ...Player,
11 });
12 const Bob = Participant('Bob', {
13 ...Player,
14 });
15 deploy();
16
17 Alice.only(() => {
.. // ...
在继续编写Reach程序之前,我们回到JavaScript中,在前端中实现这些方法。
.. // ...
13 const HAND = ['Rock', 'Paper', 'Scissors'];
14 const OUTCOME = ['Bob wins', 'Draw', 'Alice wins'];
15 const Player = (Who) => ({
16 getHand: () => {
17 const hand = Math.floor(Math.random() * 3);
18 console.log(`${Who} played ${HAND[hand]}`);
19 return hand;
20 },
21 seeOutcome: (outcome) => {
22 console.log(`${Who} saw outcome ${OUTCOME[outcome]}`);
23 },
24 });
25
26 await Promise.all([
27 backend.Alice(ctcAlice, {
28 ...Player('Alice'),
29 }),
30 backend.Bob(ctcBob, {
31 ...Player('Bob'),
32 }),
33 ]);
.. // ...
这部份代码相当简单,没有特别之处;这就是Reach的优点:我们只需要编写业务逻辑,而不必关心共识网络和去中心化应用程序的细节。
让我们回到Reach程序,研究Alice和Bob该怎么操作。
在现实生活中的“剪刀石头布”中,Alice和Bob同时决定他们要出哪种手势并同时出拳。“同时性”是一个复杂的概念,很难实践。例如,跟小孩猜拳时,您可能会发现他们"慢出"---试图在看到您出的手势后才出拳,以获得胜利。但是,在去中心化应用程序中,同时是不可能实现的。反之,必须让一个参与者“先出”。在这个示例中,我们将让Alice先出。
是Alice先出,还是我们将先出的玩家称为Alice?似乎没必要这样区分,但是Reach巧妙地利用了这一点。在前端,我们明确区分了backend.Alice和backend.Bob。这样我们把特定的JavaScript线程提交为Alice或Bob。在我们的游戏中,先运行Alice后端的人就是先出拳的人。在更后面的教程里,用户可以选择要扮演的角色,届时这个概念将更加明确。
游戏分三步进行。
首先,Alice的后端与前端进行交互,获取她的手势,然后发布它。
.. // ...
17 Alice.only(() => {
18 const handAlice = declassify(interact.getHand());
19 });
20 Alice.publish(handAlice);
21 commit();
.. // ...
下一步也类似,Bob发布了他的手势。不同的是,此时我们不立即提交状态,而是先计算猜拳的结果。
.. // ...
23 Bob.only(() => {
24 const handBob = declassify(interact.getHand());
25 });
26 Bob.publish(handBob);
27
28 const outcome = (handAlice + (4 - handBob)) % 3;
29 commit();
.. // ...
最后,我们调用each方法将每个参与者运行的结果发送到他们的前端。
.. // ...
31 each([Alice, Bob], () => {
32 interact.seeOutcome(outcome);
33 });
.. // ...
此时,我们可以运行程序查看输出结果 $ ./reach run
玩家的运行结果是随机的,因此每次的结果都会有所不同。例如我们运行该程序三次,得到的结果如下:
$ ./reach run
Alice played Scissors
Bob played Paper
Alice saw outcome Alice wins
Bob saw outcome Alice wins
$ ./reach run
Alice played Scissors
Bob played Paper
Alice saw outcome Alice wins
Bob saw outcome Alice wins
$ ./reach run
Alice played Paper
Bob played Rock
Alice saw outcome Alice wins
Bob saw outcome Alice wins
(Alice很会猜拳!!)
我们可以看到,共识网络(特别是Reach)保证所有参与者都同意各自计算的结果。这就是共识网络这个名称的来源,因为它们使这些分散且不受信任的各方能够就计算的中间状态达成共识协议。如果他们同意中间状态,那么他们也会同意输出结果。这就是为什么每次运行./reach run
时,Alice和Bob都会看到相同的结果!
如果您的代码不能正确运行,请查看tut-3/index.rsh和tut-3/index.mjs的完整版本,并确保您正确复制了所有内容!
在下一步中,我们将增加下注机制,让Alice可以利用自己的拳法变现!
您知道了吗?: Reach程序允许通过以下哪种方法与用户界面进行交互
答案:2和3;Reach通过参与者交互界面实现前端与后端的双向交互。
您知道了吗?:
Reach应用程序中的参与者如何共享彼此信息,知道其他人共享了什么?
回答:2; 原始语句publish替你搞定了一切!
欢迎关注Reach微信公众号 并在公众号目录 -> 加入群聊 选择加入官方开发者微信群与官方Discord群 与更多Reach开发者一起学习交流!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!