[Reach教程翻译] Reach是安全简单的Dapp开发语言
让用户可以像开发传统App一样开发DApp
目前使用Reach开发的智能合约可以部署在以太坊、Conflux、Algorand
Reach官网
Reach官方文挡
2.8 玩家交互、自主运行游戏
在之前实现的程序中,我们的石头剪刀布会一直运行直到确定最终的赢家为止。在本节中,我们不会改变Reach程序本身。反之,我们会通过修改Javascript前端来打造一个可交互的版本,这个版本将能够在真正的共识网络上运行。
我们将从头开始,再次展示程序的每一行。您会发现这个版本与先前的版本非常相似,但是为了完整起见,我们会显示每一行。
1 import { loadStdlib } from '@reach-sh/stdlib';
2 import * as backend from './build/index.main.mjs';
3 import { ask, yesno, done } from '@reach-sh/stdlib/ask.mjs';
4 const stdlib = loadStdlib(process.env);
5
6 (async () => {
.. // ...
- 第 1、2、4 行和之前一样 : 导入标准库和后端。
- 第 3 行是新加入的,导入了一个 Reach 标准库中的 ask.mjs 库。下面我们将看到如何使用这三个函数。
.. // ...
7 const isAlice = await ask(
8 `Are you Alice?`,
9 yesno
10 );
11 const who = isAlice ? 'Alice' : 'Bob';
12
.. // ...
- 第 7-10 行,询问用户是否以 Alice 的身份参与,期望得到“是”或“不是”的回答。
ask
会反复显示问题并提示用户输入,直到得到的输入是 ‘y’ 或 ‘n’为止。
.. // ...
13 console.log(`Starting Rock, Paper, Scissors! as ${who}`);
14
15 let acc = null;
16 const createAcc = await ask(
17 `Would you like to create an account? (only possible on devnet)`,
18 yesno
19 );
20 if (createAcc) {
21 acc = await stdlib.newTestAccount(stdlib.parseCurrency(1000));
22 } else {
23 const secret = await ask(
24 `What is your account secret?`,
25 (x => x)
26 );
27 acc = await stdlib.newAccountFromSecret(secret);
28 }
29
.. // ...
- 第 16 – 19 行,用户可以选择新创建一个测试帐户,或者输入密钥来导入自己的帐户。
- 第 21 行像之前一样创建测试帐户。
- 第 27 行导入帐户。
.. // ...
30 let ctc = null;
31 if (isAlice) {
32 ctc = acc.contract(backend);
33 ctc.getInfo().then((info) => {
34 console.log(`The contract is deployed as = ${JSON.stringify(info)}`); });
35 } else {
36 const info = await ask(
37 `Please paste the contract information:`,
38 JSON.parse
39 );
40 ctc = acc.contract(backend, info);
41 }
.. // ...
- 第 31 行确定以下分支中玩家扮演的角色是Alice-部署合约,还是Bob-加入Alice部署的合约。
- 第 32 – 34 行部署合约并打印合约公开信息(ctc.getInfo),部署者可以在部署好后将这个信息发送其他要加入合约的参与者,用于让他们加入合约。
- 第 36 – 41 行请求、解析和处理这个信息。
.. // ...
43 const fmt = (x) => stdlib.formatCurrency(x, 4);
44 const getBalance = async () => fmt(await stdlib.balanceOf(acc));
45
46 const before = await getBalance();
47 console.log(`Your balance is ${before}`);
48
49 const interact = { ...stdlib.hasRandom };
.. // ...
- 定义几个辅助函数并声明参与者交互接口。
.. // ...
51 interact.informTimeout = () => {
52 console.log(`There was a timeout.`);
53 process.exit(1);
54 };
.. // ...
- 定义一个超时处理程序。
.. // ...
56 if (isAlice) {
57 const amt = await ask(
58 `How much do you want to wager?`,
59 stdlib.parseCurrency
60 );
61 interact.wager = amt;
62 interact.deadline = { ETH: 100, ALGO: 100, CFX: 1000 }[stdlib.connector];
63 } else {
64 interact.acceptWager = async (amt) => {
65 const accepted = await ask(
66 `Do you accept the wager of ${fmt(amt)}?`,
67 yesno
68 );
69 if (!accepted) {
70 process.exit(0);
71 }
72 };
73 }
.. // ...
- 根据是 Alice 还是 Bob,决定请求赌注值
wager
,还是定义acceptWager
方法
.. // ...
75 const HAND = ['Rock', 'Paper', 'Scissors'];
76 const HANDS = {
77 'Rock': 0, 'R': 0, 'r': 0,
78 'Paper': 1, 'P': 1, 'p': 1,
79 'Scissors': 2, 'S': 2, 's': 2,
80 };
81
82 interact.getHand = async () => {
83 const hand = await ask(`What hand will you play?`, (x) => {
84 const hand = HANDS[x];
85 if ( hand == null ) {
86 throw Error(`Not a valid hand ${hand}`);
87 }
88 return hand;
89 });
90 console.log(`You played ${HAND[hand]}`);
91 return hand;
92 };
.. // ...
- 接着定义两人共同的
getHand
方法。
.. // ...
94 const OUTCOME = ['Bob wins', 'Draw', 'Alice wins'];
95 interact.seeOutcome = async (outcome) => {
96 console.log(`The outcome is: ${OUTCOME[outcome]}`);
97 };
.. // ...
- 最后是
seeOutcome
方法。
.. // ...
99 const part = isAlice ? ctc.p.Alice : ctc.p.Bob;
100 await part(interact);
101
102 const after = await getBalance();
103 console.log(`Your balance is now ${after}`);
104
105 done();
106 })();
- 最后的最后,我们选择合适的后端并等待其完成。**
现在我们可以运行在两个终端分别运行$ ./reach run
来扮演 Alice 和 Bob 。
下面是一组运行的例子:
$ ./reach run
Are you Alice?
y
Starting Rock, Paper, Scissors as Alice
Would you like to create an account? (only possible on devnet)
y
Do you want to deploy the contract? (y/n)
y
The contract is deployed as = "0x132b724e55AEb074C15A5CBb7b8EeE0dBEd45F7b"
Your balance is 999.9999
How much do you want to wager?
10
What hand will you play?
r
You played Rock
The outcome is: Bob wins
Your balance is now 989.9999
另一边:
$ make run-bob
Are you Alice?
n
Starting Rock, Paper, Scissors as Bob
Would you like to create an account? (only possible on devnet)
y
Do you want to deploy the contract? (y/n)
n
Please paste the contract information:
"0x132b724e55AEb074C15A5CBb7b8EeE0dBEd45F7b"`
Your balance is 1000
Do you accept the wager of 10?
y
What hand will you play?
p
You played Paper
The outcome is: Bob wins
Your balance is now 1009.9999
当然,每次运行时的赌注可以不同,部署地址也会不一样。
如果你的版本不能正常运行,看看完整的版本: rps-8-interact/index.rsh 和 rps-8-interact/index.mjs ,并确保您完整地复制了所有内容!
如果我们在两个终端运行的是$ REACH_CONNECTOR_MODE=ALGO-devnet ./reach run
则相当于在一个私有的 Algorand 测试网运行我们的程序。
连接真正的共识网络也一样简单,例如运行:$ REACH_CONNECTOR_MODE=ETH-live ETH_NODE_URI="http://some.node.fqdn:8545" ./reach run
您知道了吗? :
是非题 : Reach 帮助你自动化测试DApp,但它不支持构建交互式用户界面
答案是:
否! Reach 不会对使用 Reach 应用程序的前端做任何限制。