Exploring blockly in three parts

17-2-2015

Part 1: Graph Paper Programming with Blockly

Introduction

I'm getting ready to give my first programming lessons to two classes at OBS 't Schöppert. The past half year or so I've been playing with the idea of teaching programming to elementary school students. Now I have a little extra time and I've found a school that agrees that this is a great idea. Cool!

One source of lesson plans and material that has particulary impressed and inspired me is code.org. The creators of code.org have a number of offline lessons aimed at introducing programming concepts followed up by interactive puzzles that can be solved by writing programs using google's Blocky. If you haven't seen blockly in action then you might have a look at code.org or check out some of the demos.

Code.org is very cool, and for the time being it would be fine to base all my lessons on their material. But it would be even more fun (and more educational for both me and the kids) if I could supplement their stuff with material of my own. To that end I figure it would be interesting to see if I can get blockly working on my own website and interfacing with my own javascript code.

Blockly on my own page

Luckily the developers of blockly have done a great job documenting the most important steps required to get blockly working. My first page with blockly on it was just a question of downloading the code and following the steps. I went with the IFrame option (instead of the div) because it seemed like this was most flexible and not much harder to implement. So far, so good, but without something for Blockly to do beyond showing a popup message - not very exciting.

Graph paper programming

I'm starting my programming lessons with the offline graph paper programming (gpp) lesson from course 2 on code.org. I figure it would be a nice test case to implement this as my first blockly customization. With a bit of luck I can even use the result in a follow up lesson in which to introduce Blockly to the kids. The gpp language is very simple, and consists of just 5 language elements: up, right, down, left and draw. These are intuitively represented in the gpp lesson with arrows and a squiggle for "draw". All I need to do is create 5 custom blocks for these 5 statements, let these generate the appropriate code, and of course I need to create a graph paper grid on my web page that my gpp program can draw on.

The blocks

More kudo's to the google developers for two great resources that helped me get to grips with the block representation:

With the block factory it's relatively intuitive to make new blocks. My 5 simple blocks were easy. Here's one. Blockly blocks are created in javascript and added as new properties of the Blockly.Blocks object. The block factory generates this code for you, and I could have just copy pasted all five blocks into my own code. I'm fairly obsessive about not repeating myself though, and it is also simple to create a parametrized factory method that creates all five blocks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function getInit(imageSuffix){
	return function() {
		this.setColour(65);
		this.appendDummyInput()
				.appendField(new Blockly.FieldImage("http://meestermark.nl/Programmeren/img/GraphProgramming" + imageSuffix + ".png", 30, 30, "*"));
		this.setPreviousStatement(true);
		this.setNextStatement(true);
	}
}

Blockly.Blocks.gpp_move_up = {
	init: getInit("Up")
};

The graph paper

I've been playing and working with the javascript MVVM framework knockout for that past year or so. The more I work with knockout, the more I like it. These days if I'm making in interactive web page I use knockout and jquery as a matter of course. Here too, and I came up with the following viewmodel (somewhat abridged):

 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
var viewModel = {};

viewModel.rowCount = ko.observable(8);
viewModel.columnCount = ko.observable(15);
viewModel.cursor = ko.observable({x: 0, y: 0});
viewModel.rows = ko.observableArray(rows);

viewModel.moveUp = function(){
	viewModel.tryMove({x: viewModel.cursor().x, y: viewModel.cursor().y - 1});
}
eh
viewModel.moveRight = function(){
	viewModel.tryMove({x: viewModel.cursor().x + 1, y: viewModel.cursor().y});
}

viewModel.moveLeft = function(){
	viewModel.tryMove({x: viewModel.cursor().x - 1, y: viewModel.cursor().y});
}

viewModel.moveDown = function(){
	viewModel.tryMove({x: viewModel.cursor().x, y: viewModel.cursor().y + 1});
}

viewModel.draw = function(){
	viewModel.rows()[viewModel.cursor().y]()[viewModel.cursor().x].isFilled(true);
}

So the 5 blockly blocks just need to call the 5 viewModel methods and that's all there is to it. It couldn't be more simple.

Blocks to code

Next to the block initialization code, the block factory also produces a skeleton for the actual code that the blocks will create. The code a block produces is nothing more exotic than a string. It's the developers responsibility to ensure that this string is valid code (in my case javascript code). Because my blocks are simple, with no value inputs, the code to produce is also simple:

1
2
3
Blockly.JavaScript.gpp_move_up = function() {
	return "viewModel.moveUp();\n";
};

Success

Putting it all together gave me my first custom blockly application. Pretty neat. But there is still lots of room for improvement:

More about that in the future...

21-2-2015

Part 2: Left to right coding with value inputs

Introduction

In my previous post I developed a blockly version of graph paper programming (gpp). Today I'm going to try to improve on my first solution. I'm going to see if I can write my gpp programs from left to right (insted of from top to bottom), if I can learn something about blockly's value inputs and if I can save my bockly program.

Value inputs in blockly

My first program consisted of statements without parameters. Blockly displays statements from top to bottom. So it made sense to create statement blocks with notches at the top and bottom. If I want to go from left to right (which makes more sense in the gpp context) it would seem that I have to think about a way of having the gpp action blocks be value inputs to a "run" block which executes the blocks. As it turns out, there was no need to do this at all, but it was educational finding out why.

My first stop was the block factory. It was not too hard to turn the statement inputs into a value input to my statement blocks. This is the result in the block factory. The block factory also helpfully adds the code to extract the value of the value input (in the bottom right pane). I say value, but in fact it's the string representation of the value as returned by the block that is inserted in the right hand notch. In the case of an empty right hand notch the value of the value input is an empty string.

This was a bit of an aha moment for me. Although in retrospect it seems obvious. A value block returns a string representing code, just like a statement block. Must often this string will be a value like 3 or "hello world". But, basically, Blockly doesn't care. The only significant difference, as I now understand it, is that Blockly has support for operator precedence to prevent excessive use of parentheses when combining / nesting operations and values. I haven't fully grasped how this works, so that's something that warrants further exploration at some other time.

Gpp actions as array elements

Notwithstanding this insight, my plan is still to have my gpp actions be real values. A tricky thing is that I need to be able to chain the values. What would be a good representation for a chain of gpp actions. An array of course! I picked an array of function names, although I could have made it an array of the functions themselves. This is the code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function getCode(block, name){
	var value_nextactions = Blockly.JavaScript.valueToCode(block, 'NEXTACTIONS', Blockly.JavaScript.ORDER_NONE);
	if(value_nextactions === ""){
		var code = "['" + name + "']";
	} else {
		var code = "['" + name + "', " + value_nextactions.substring(1);
	}
	return [code, Blockly.JavaScript.ORDER_ATOMIC];
}

Blockly.JavaScript.gpp_move_up = function(block) {
	return getCode(block, "moveUp");
};

So the chain of actions is an array which then needs to be passed to a run actions block. Or does it? My earlier insight about what a value input actually is (just random code) now made me realize that I can just do without the run actions block. This doesn't make much sense in a programmer's world where values and statements are pretty different things (even in javascript). But blocks are just strings representing code. So my leftmost block in the gpp chain can execute the run of the array itself. That looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function getCode(block, name){
	var value_nextactions = Blockly.JavaScript.valueToCode(block, 'NEXTACTIONS', Blockly.JavaScript.ORDER_NONE);
	if(value_nextactions === ""){
		var code = "viewModel.run(['" + name + "'])";
	} else {
		var code = "viewModel.run(['" + name + "', " + value_nextactions.substring(15);
	}
	return [code, Blockly.JavaScript.ORDER_ATOMIC];
}

Blockly.JavaScript.gpp_move_up = function(block) {
	return getCode(block, "moveUp");
};

Once I realized that I could do without the run block, I also realized that the whole array and the run function weren't necessary either. I could just have the value inputs return the action function calls. In fact the exact same code that the vertical statement blocks returned in my first version. Ah well, I'm leaving it with my array and run code because it's interesting and works just as well.

Save and load

Blockly supports saving your code to the cloud and to local storage. These are the docs. That's cool, but I want the flexibility of knowing what's going on under the hood instead of just using the high level storage APIs. One thing I would like to be able to do is to predefine a program to show in Blockly when a user hits a page. It took me a while to figure it out because there aren't really any docs for the API at this level. Browsing through the example code I finally found the code to load and save blocks to xml. How you store the xml is then up to you. Here's the code that I use for my "Hoi" (hi in Dutch) gpp program.

1
2
3
Blockly.Xml.domToWorkspace(Blockly.mainWorkspace,$("#hiBlocks")[0]); // loads xml from dom into workspace

Blockly.Xml.domToPrettyText(Blockly.Xml.workspaceToDom(Blockly.mainWorkspace)) // exports workspace as pretty xml

For now I can create the program I want in blockly, call workspaceToDom from the google developer tools and paste the xml into my page. With domToWorkspace I can load it into Blockly during initialization. At some point I'll probably look into the storage API when I want to give my users the option of saving their work. But with this done I'm pretty satisified with my understanding of Blockly and I've got a nice demonstration with which I can bridge from the offline gpp lesson into working with Blockly. I've put everything together here

17-3-2015

Part 3: Blockly with JS interpreter

Got it!

Got it is a fun mathematical game for two that I first came across in primary school when my 5th grade teacher, Mrs Bingh, taught it to me and my friend Tim. Much, much later I came across it again on the nrich website while I was looking for subjects for my enriching math lessons. Now it's come up again as a possible subject for my programming lessons and a fun way to further my knowledge and experience with Blockly.

In my previous posts I developed a Blockly version of graph paper programming. I made it easy for myself by limiting the allowed blocks to my own custom blocks. That meant I had complete control of the emitted javascript. For this next program I want to use standard Blockly blocks in addition to my custom blocks. That means I'll have to have my javascript play nicely with the javascript that Blockly's standard blocks emit. As if that's not enough I want to hook up the JavaScript interpreter. That should let me highlight the program's statements as they execute, helping the students to understand how their programs work (or don't).

What's the challenge

Starting off I'm not completely sure what I'm going to ask my students to program. Got it is a fairly simple game, and simple to win if you've figured it out. But for (most) primary school students it's not immediately obvious what the winning strategy is. By varying the target and the number a player can take per turn it's also possible to make it a little more challenging. I'm guessing it will be an interesting challenge to have the kids program a player's strategy. Maybe they can play against eachother or maybe against a computer player.

The original nrich version of got it is completely abstract. I'm going to make it a little more interesting by having the players aim for a big candy cane. On the way lesser candies must be eaten. My first goal is to program the got it engine and hook up a UI to it so that the players can see what is going on. I've just recently had a serious look at coffeescript and liked it so I thought I'd try my hand at writing my engine in that. Digression: I think coffeescript may also be a nice step from block programming to text programming while staying in the browser. Pencil code does just that: allowing students to switch between block and coffeescript code views. For the UI I'll be using knockout. This post is about Blockly so anyone interested in the details of the engine or the UI will have to dive into the source code.

JavaScript interpreter

The JavaScript interpreter is a very cool piece of code that implements a JavaScript interpreter in javascript. Code.org uses the interpreter to highlight code as it executes and to allow students to step through their code to see what does what. However, getting the javascript interpreter to work is not trivial. Running "pure" javascript code in the interpreter is easy but getting that code to interact with code outside the interpreter sandbox is difficult. The Blockly docs has some example code, and so does the interpreter page itself, but I had to follow the advice on the interpreter docs page and look at the implementation of Interpreter.prototype.initGlobalScope itself to develop my understanding. I don't want to dive to deeply into this subject here, but I will add one useful example of my own. JS interpreter doesn't have an implementation of console.log, which it obviously needs ;-). To implement console.log in the interpreter entails adding a console object AND explicitly adding the log function to it. Here's the code.

1
2
3
4
5
6
myConsole = interpreter.createObject(interpreter.OBJECT);
interpreter.setProperty(scope, 'console', myConsole);
wrapper = function(obj) {
	return interpreter.createPrimitive(console.log(obj));
};
interpreter.setProperty(myConsole, 'log', interpreter.createNativeFunction(wrapper));

Interfacing between Blockly and the got it engine

Coming up with a way to integrate Blockly into my got it engine seemed like a trivial task before I got started, but it I took quite a few wrong turns before I got to a happy place. Here are the most important design constraints I came up with along the way

The best way to show you the interface is to show you the code that is now generated by Blockly. Some of the variable names are in Dutch because that's the language my students speak. You can see their English equivalents in the player1Turn function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var Begin_aantal_snoepjes;
var Max_snoepjes_per_beurt;

var start = function(){
  Begin_aantal_snoepjes = 23;
  Max_snoepjes_per_beurt = 4;
  createViewModel(Begin_aantal_snoepjes, Max_snoepjes_per_beurt);
}
var player1Turn = function(player){
  Max_snoepjes_per_beurt = maxCandyPerTurn;
  Begin_aantal_snoepjes = initialCandyCount;
  var Aantal_snoepjes_over = currentCandyCount;

  setCandyCount(1);
}

There are three external variables: initialCandyCount, maxCandyPerTurn, currentCandyCount. And there are two functions: createViewModel and setCandyCount. createViewModel should probably be called newGame because that is what it does. It resets the state of the game based on the initialCandyCount and maxCandyPerTurn variables. setCandyCount is called each time player1 has a turn and sets the number of candies player1 will take. In the example code the player always takes 1 candy, but the students can use Blockly to determine the value they want to call setCandyCount with. One of the things that is nice about this is that I can call into start (on some external event like a new game button click) to setup a new game and I can call into player1Turn when player1 has his turn.

The user experience

Take a look at the finished product to see how it all comes together. I've split the available blocks into required and optional categories to limit the blocks the students are required to consider. A new game button and a next turn button allows the user to control the game. To challenge the students, their opponent is the unbeatable "mark the merciless". Unbeatable that is, unless you make exactly the right move at each turn.

A final tweak to the user experience (and the initial reason to use the interpreter) is to get the blocks to light up as they are being executed. That could be useful for the students to understand what's going on during debugging. Ideally they should also really have some sort of watch window, but that's out of scope for now. Getting the highlighting to work is fairly straightforward based on this example provided by the Blockly team. View the source of the demo and look at the inline javascript. Don't forget the Blockly.mainWorkspace.traceOn(true) call before executing the code otherwise you won't see any higlighting. The example has a step button to execute each block step by step. I don't want that fine grained control, just the highlighting, so I'm using setTimeout to slow down the execution of the blocks but to keep going till the execution is done.

It took me a few evenings work to get to this point but I'm really satisfied with the result. Not only have I got a fun game / programming challenge for my students. I've also developed my understanding of Blockly and JS interpreter. I also have some code with which I'm pretty sure I can speed up the development of my next Blockly challenge.



mark@MeesterMark.nl