Custom blocks a arguments of While loop

658 views
Skip to first unread message

KVM

unread,
Nov 15, 2017, 10:25:29 AM11/15/17
to Blockly
Hello all,

I have created a little maze with a robot and I use Blockly to generate code to try to solve it. I can move the robot using Javascript commands which are Blockly blocks. So far so good.
I am currently breaking my head over arguments of if-statements and while loops. Mainly, I have tried two things:

1. create a variable, 'not_goal_reached' which says whether or not the robot has reached the goal position (cross). Code:
function not_done() {
  var goal_location = get_goal_position()
  var goal_x = goal_location[0];
  var goal_y = goal_location[1];
  console.log('in not done');
  //console.log(player.x!= goal_x || player.y != goal_y)
  return (player.x!= goal_x || player.y != goal_y);
};

Blockly.Blocks['not_goal_reached'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("not at goal")
    this.setOutput(true, "Boolean");
    this.setColour(230);
    this.setTooltip('');
    this.setHelpUrl('');
  }
};

Blockly.JavaScript['not_goal_reached'] = function(block) {
  
  var code = 'not_done()';
  // TODO: Change ORDER_NONE to the correct strength.
  //console.log(code)
  return [code, Blockly.JavaScript.ORDER_ATOMIC];
};

However, when using this block in an If or While statement. I always get a Javascript error that does not help me to find the solution:
TypeError: Cannot read property 'toBoolean' of undefined
    at Interpreter.stepConditionalExpression (acorn_interpreter.js:148)
    at Interpreter.step (acorn_interpreter.js:45)
    at nextStep (index.html:79)

I use the Acorn js interpreter:
window.LoopTrap = 2000;
  //Blockly.JavaScript.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = Blockly.JavaScript.workspaceToCode(workspace);
console.log(code);
var myInterpreter = new Interpreter(code, initInterpreter);
//Blockly.JavaScript.INFINITE_LOOP_TRAP = null
  

  var counter = 0;
  function nextStep() {
        try {
        if (myInterpreter.step()) {
          counter+=1;
          console.log(counter);
          if (counter < window.LoopTrap) {
              window.setTimeout(nextStep, 30);
              
            }
          else {
            throw "Infinite Loop!"
          }
        }
      }
  catch (e) {
        //alert(e);
        console.log(e)
    }
  } 
  
nextStep();

Problem: javascript error I can not solve :(


2. I created my own While block that does not require input. This While block checks internally whether or not the robot has reached the goal and then processes the DO statements:
Blockly.Blocks['repeat_forever'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("While not at goal");
    this.appendStatementInput("DO")
        .appendField("Do");

    this.setPreviousStatement(true);
    this.setColour(230);
    this.setTooltip('');
    this.setHelpUrl('');
  }
};



Blockly.JavaScript['repeat_forever'] = function(block) {
  var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  // TODO: Assemble JavaScript into code variable.
  //if (Blockly.JavaScript.INFINITE_LOOP_TRAP) {
  //  branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,
  //     '\'block_id_' + block.id + '\'') + branch;
  //  console.log(branch);
  //}

  var code = 'while (' + 'not_done()' + ') {' + branch + '}';
  console.log(code)
  return [code, Blockly.JavaScript.ORDER_ATOMIC];

};


This works, BUT, here I have the problem that my internal function 'not_done' is only evaluated once (at code generation) to while(true) (since the first time the robot is of course not at the goal location yet). This block correctly applies the DO codes but does not halt (since while (true)). If I add quotes around 'not_done()' the function is evaluated once apparently, but then I receive the same Javascript error as above (Cannot read property 'toBoolean' of undefined)

Am I missing something here? Thanks a lot for your time!

Greetings

K
blockly_overview.jpeg

Victor Ng

unread,
Nov 15, 2017, 4:17:17 PM11/15/17
to Blockly
In your code generator, try changing "Blockly.JavaScript.ORDER_ATOMIC" to "Blockly.JavaScript.ORDER_FUNCTION_CALL".

KVM

unread,
Nov 16, 2017, 12:47:10 PM11/16/17
to Blockly
Hello Victor,

Thank you for your reply. I changed the code to:

Blockly.Blocks['not_goal_reached'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("not at goal")
    this.setOutput(true, "Boolean");
    this.setColour(230);
    this.setTooltip('');
    this.setHelpUrl('');
  }
};

Blockly.JavaScript['not_goal_reached'] = function(block) {
  
  var code = 'not_done()';
  // TODO: Change ORDER_NONE to the correct strength.
  //console.log(code)
  return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];
};


Blockly.Blocks['repeat_forever'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("While not at goal");
    this.appendStatementInput("DO")
        .appendField("Do");

    this.setPreviousStatement(true);
    this.setColour(230);
    this.setTooltip('');
    this.setHelpUrl('');
  }
};



Blockly.JavaScript['repeat_forever'] = function(block) {
  var branch = Blockly.JavaScript.statementToCode(block, 'DO');
  // TODO: Assemble JavaScript into code variable.
  //if (Blockly.JavaScript.INFINITE_LOOP_TRAP) {
  //  branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g,
  //     '\'block_id_' + block.id + '\'') + branch;
  //  console.log(branch);
  //}

  var code = 'while (' + 'not_done()' + ') {' + branch + '}';
  console.log(code)
  return [code, Blockly.JavaScript.ORDER_FUNCTION_CALL];

};

But the problem persists. I receive the following output:

while (not_done()) {  
  move_left();
}
index.html:81 1
index.html:81 2
index.html:81 3
index.html:81 4
maze.js:284 in not done
index.html:81 5
index.html:81 6
index.html:93 TypeError: Cannot read property 'toBoolean' of undefined
    at Interpreter.stepDoWhileStatement (acorn_interpreter.js:150)
    at Interpreter.step (acorn_interpreter.js:45)
    at nextStep (index.html:79)

The first paragraph is the generated code. This looks fine.
The counter is the number of times myInterpreter.step() is executed. This is not the same as the number of turns of the robot, since it is not turning at all.
There is also one output message, indicating that the test to see whether the maze is solved (not_done()) is executed once and then, two 'steps later', I receive the same error as above :(

Does anybody have an idea on how to solve this? I added my prototype to my Google Drive: https://drive.google.com/file/d/0BzRlknhh7WayN0xQeVhWWk9wSEk/view?usp=sharing 
The important files are maze.js and index.html

Thanks a lot for your time,
Regards
K

Victor Ng

unread,
Nov 16, 2017, 12:50:06 PM11/16/17
to Blockly
Sorry, I meant to say to try that with your first attempt.

With your second attempt, I believe you should simply return the code and not an array:

var code = 'while (' + 'not_done()' + ') {' + branch + '}';
return code;

KVM

unread,
Nov 17, 2017, 2:31:41 AM11/17/17
to Blockly
I am afraid the result is the same when using:

Blockly.JavaScript['repeat_forever'] = function(block) {
  var branch = Blockly.JavaScript.statementToCode(block, 'DO');

  var code = 'while (' + 'not_done()' + ') {' + branch + '}';
  console.log(code)
  return code;//[code, Blockly.JavaScript.ORDER_FUNCTION_CALL];

};

Output:
The generated code is identical to the previous result and seems OK. It must be something under the hood.

//generated code:
while (not_done()) {
  move_left();

TypeError: Cannot read property 'toBoolean' of undefined
    at Interpreter.stepDoWhileStatement (acorn_interpreter.js:150)
    at Interpreter.step (acorn_interpreter.js:45)
    at nextStep (index.html:79)

Any other ideas? Are there some (acorn) debug options that I can activate in order to have more meaningful output maybe?

Regards,

K
Message has been deleted

kristof.va...@gmail.com

unread,
Nov 17, 2017, 3:41:37 PM11/17/17
to blo...@googlegroups.com
Sure, The project is now very small and located here: https://github.com/kristofvanmoffaert/maze

Thanks

On Fri, Nov 17, 2017 at 8:45 PM, 'Victor Ng' via Blockly <blo...@googlegroups.com> wrote:
Could you share a small example that exhibits the problem without the whole project? I'm always a bit uneasy about downloading zip files from the web :)

--
You received this message because you are subscribed to a topic in the Google Groups "Blockly" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/blockly/1xnBHc7K6s0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to blockly+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Victor Ng

unread,
Nov 17, 2017, 4:57:46 PM11/17/17
to Blockly
It looks like a bug with the version of JS interpreter (https://github.com/NeilFraser/JS-Interpreter) that you're using. If you update to the latest one, that should fix your problem.

Although I did notice a couple of minor things you might want to fix:
1) When defining the native function in JS interpreter for "not_done", the wrapper should be:

wrapper = function() {
  return not_done();
}

2) "repeat_forever" should simply return code, not an array of values.
To unsubscribe from this group and all its topics, send an email to blockly+u...@googlegroups.com.

Victor Ng

unread,
Nov 17, 2017, 5:00:55 PM11/17/17
to Blockly
Also, it appears that you're using an older version of Blockly (based on highlighting?). You may want to be grab the latest version from https://github.com/google/blockly.

KVM

unread,
Nov 19, 2017, 10:26:32 AM11/19/17
to Blockly
Thank you, Victor, this seems to have solved the problem. Thanks a lot for your time and help!

Regards,

K
Reply all
Reply to author
Forward
0 new messages