Closed JogoShugh closed 9 years ago
Heh....well the syntax could be slightly cleaner if little functions were in scope like r, l, d, u:
await move(0, 0, r(5), d(6)) etc..... And probably have right, down etc as aliases
Those functions can just return a '5 r' string or {r:5} object to be processed by the runner.
OK, this is pretty much working!
After running the nitrous instance by doing . ./start.sh
, you should be able to browse to:
http://supersonic-box-113463.nitrousapp.com:3000/lesson?id=training&sec=10
Then, directly paste this code that uses await
in and then press execute:
for (let x of range(3)) {
x *= 7;
for (let y of range(3)) {
y *= 4;
await run('move', pt(x, y), r(3), d(3), l(3), u(2));
}
}
alert('Done!');
This should pick up all the gemstones correctly, one group at a time top-to-bottom, left-to-right.
Another idea would be to break stuff out with functions for:
await teleport(x, y);
await right(3);
await down(3);
await left(3);
await up(2);
The problem with that is that it starts to become await soup.
An alternative would be to use await*, but then...I'm not sure if this results in parellel execution or sequential.
await* [
teleport(x, y),
right(3),
down(3),
left(3),
up(2)
];
Here's a fun one that produces new player sprites in the wake of the original leader. It still works all the way through hahaha. Students love "breaking" things like this:
for (let x of range(3)) {
x = 7;
for (let y of range(3)) {
y = 4;
await run('move', pt(x, y));
for (let direction of ['r', 'd', 'l', 'u']) {
let dist = direction !== 'u' ? 3 : 2;
for (let n of range(dist)) {
await run('move', 1 ${direction}
);
game.world.setSprite('p');
if (dist === 2 && n === 1) {
await run('move', '1 r');
game.world.setSprite('p');
}
}
};
}
}
alert('Done!');
Note that now the run('move'...) syntax doesn't work. But this does:
for (let x of range(3)) {
x *= 7;
for (let y of range(3)) {
y *= 4;
await move(pt(x, y), r(3), d(3), l(3), u(2));
await move(point(x, y), {r:3}, down(3), {left:3}, '2 u'); // we got variety of ways...
}
}
alert('Done!');
Background
ES7 is going to (likely) provide C# style async/await support. This is syntactic sugar around Promises, but greatly reduces the amount of ugly code and handler functions needed.
To get a quick sense of the beneft, see this:
http://jancarloviray.com/blog/es7-async-await-javascript-simplified/
In short:
This code:
Will really be doing this:
Take a look at another more in-depth article at
From there, we see that this code which chains Promises:
Can be written this way in ES7:
Clearly this is a massive improvement at the language level!
Goals
How To Implement
First of all, the babel-compiler for Meteor has a limited, server-side-only approach to async / await currently. This is not what we need.
Visit this link to see that kind of client-side stuff we want to support:
http://babeljs.io/repl/#?experimental=true&evaluate=true&loose=false&spec=false&code=(async%20function()%20%7B%0A%20%20async%20function%20run()%7B%0A%20%20%20%20return%20await*%20%5B%0A%20%20%20%20%20%20%24.ajax('https%3A%2F%2Fcommitstream.v1host.com%2Fhealth%2Fprojections')%2C%0A%20%20%20%20%20%20%24.ajax('https%3A%2F%2Fcommitstream.v1host.com%2Fhealth%2Fstatus')%2C%0A%20%20%20%20%20%20%24.ajax('https%3A%2F%2Festimably.com%2Fhealth%2Fpersistence')%0A%20%20%20%20%5D%3B%0A%20%20%7D%0A%20%20%0A%20%20try%20%7B%0A%20%20%20%20let%20val%20%3D%20await%20run()%3B%0A%20%20%20%20alert(JSON.stringify(val))%3B%20%20%20%20%0A%20%20%7D%20catch%20(err)%20%7B%0A%20%20%20%20let%20stringErr%20%3D%20JSON.stringify(err)%3B%0A%20%20%20%20alert(%60Error!%20%24%7BstringErr%7D%60)%3B%0A%20%20%7D%0A%7D())%0A%0A
That is, this code:
The code it gets transpiled into is complicated, and relies upon the runtime.js from regenerator by Facebook (https://github.com/facebook/regenerator/blob/master/runtime.js).
Here's a working JSFiddle that has the entire runtime.js embedded into it:
http://jsfiddle.net/e35qchga/2/
SpaceMiner Examples
For SpaceMiner, we want students to be able to do something like:
We already have support for
move('5 l', '6 d', '7 r')
. HOWEVER, if you want to use afor
loop, you really end up having to get into recursive function calls, and that's less than optimal for a beginner, so having the ability to use await would do wonders for the teaching aspect without introducing the complications of Promise syntax formally -- and it will prepare them for ES7 features ahead of the game!Parital support so far
I don't have a standalone Babel translator service running yet, but I've already added a
run
function which returns a Promise, and thus can be sugared over withawait
, and thus supported by Babel and Facebook's regenerator runtime.js which I already added. Here a sample:Go to the Box Step training step at http://supersonic-box-113463.nitrousapp.com:3000/lesson?id=training
http://babeljs.io/repl/#?experimental=true&evaluate=false&loose=false&spec=false&code=(async%20()%20%3D%3E%20%7B%0A%20%20for%20(let%20x%20of%20range(3))%20%7B%0A%20%20%20%20x%20*%3D%207%3B%0A%20%20%20%20for%20(let%20y%20of%20range(3))%20%7B%0A%20%20%20%20%20%20y%20*%3D%204%3B%0A%20%20%20%20%20%20await%20run('move'%2C%20x%20%2B%20'%20'%20%2B%20y%2C%20'3%20r'%2C%20'3%20d'%2C%20'3%20l'%2C%20'2%20u')%3B%0A%20%20%20%20%7D%0A%20%20%7D%0A%20%20alert('Done!')%3B%0A%7D())%3B%0A%0A
Code
You cannot directly type the following code in SpaceMiner yet. Instead, paste the transpiled code in from Babel above.
Clearly this code is way easier to learn, type, and explain! We won't need the outer shell, so we'll end up just having to teach and explain this part:
Perhaps it will be better to have the API read more like this:
Here's another more complicated approach which uses the new
game.world.setSprite()
function to drop a tile into place where the ship moves.