/* Path utilities useful for world creators */ require("./../rur.js"); require("./../drawing/visible_world.js"); /** @function print_path * @memberof RUR * @instance * @summary This function prints the path followed by the default robot, where * the values ['x', 'y'] are used to draw the trace on the screen. Values are * only appended to the path when they change; thus, turns and other actions * performed at a given location are ignored. The initial position is * considered to be part of the path. * */ RUR.print_path = function () { "use strict"; var history, path, world, x_init, y_init, robot; world = RUR.get_current_world(); if (world.robots === undefined || world.robots.length === 0) { throw new RUR.ReeborgError("Missing robot; cannot print path."); } robot = world.robots[0]; history = robot._trace_history; if (robot.initial_position !== undefined) { x_init = robot.initial_position[0]; y_init = robot.initial_position[1]; } else { console.warn("Initial_position not defined for robot in print_path; robot =", robot); x_init = robot.x; y_init = robot.y; } path = compute_path(x_init, y_init, history); RUR._write_ln(path); }; function compute_path(x_init, y_init, history) { var x, y, prev_x, prev_y, path; prev_x = x_init; prev_y = y_init; path = [[prev_x, prev_y]]; for (i=0; i < history.length; i++) { x = history[i]['grid_x']; y = history[i]['grid_y']; if (x != prev_x || y != prev_y) { path.push([x, y]); prev_x = x; prev_y = y; } } return path; } /** @function check_path * @memberof RUR * @instance * @summary This function compares the path followed by the default robot * with that which was desired. * * @param {list} desired_path A desired path, as printed by `RUR.print_path`. * * @param {Object} [options] A Javascript object (similar to a Python dict). * * @param {string} [options.failure] If the followed path was **not** the specified * one and `options.failure` is specified, an exception will be raised and * `options.failure` will be shown. * * @param {string} [options.success] If the followed path **was** the specified * one and `options.success` is specified, an exception will be raised and * `options.success` will be shown. * * @param {string} [options.show_path] If the followed path was not the specified * one and `options.show_path` is set to `true`, the `desired_path` * will be shown. If this is desired, we suggest to use the string `"true"` which * will be valid in both Python and Javascript. * If the correct path is followed, and you wish to show the `desired_path`, * simply call `RUR.show_path()` explicitly with the relevant arguments * prior to calling `RUR.check_path()`. * * @param {string} [options.color] If the desired path is shown and `options.color` * is specified, it will be the color used to show the path. * * @returns {bool} True if the correct path was followed, false otherwise **and** * if the relevant option `options.success` or `options.failure` * is not specified. * */ RUR.check_path = function (desired_path, options) { "use strict"; var history, i, world, desired_x, desired_y, path_taken, x, y, robot; var success = true; world = RUR.get_current_world(); if (world.robots === undefined || world.robots.length === 0) { throw new RUR.ReeborgError("Missing robot; cannot check path."); } robot = world.robots[0]; history = robot._trace_history; if (robot.initial_position !== undefined) { x = robot.initial_position[0]; y = robot.initial_position[1]; } else { console.warn("Initial_position not defined for robot in check_path; robot =", robot); x = robot.x; y = robot.y; } path_taken = compute_path(x, y, history); if (desired_path.length > path_taken.length){ console.log("desired longer than taken"); success = false; } else if (desired_path.length < path_taken.length){ console.log("desired shorter than taken"); success = false; } else { for (i=0; i < path_taken.length; i++) { x = path_taken[i][0]; y = path_taken[i][1]; desired_x = desired_path[i][0]; desired_y = desired_path[i][1]; if (x != desired_x || y != desired_y) { console.log("difference at", x, y); success = false; break; } } } if (success) { if (options) { if (options.success) { RUR.success_custom_message = options.success; throw new RUR.ReeborgOK(options.success); } } return true; } if (options) { if (options.show_path) { if (options.color) { RUR.show_path(desired_path, options.color); } else { RUR.show_path(desired_path); } } if (options.failure) { RUR.failure_custom_message = options.failure; throw new RUR.ReeborgError(options.failure); } } return false; }; /** @function show_path * @memberof RUR * @instance * @summary This function draws a path which Reeborg should follow. * To stop drawing the path, call the function with no arguments. * * @param {list} path A path, as printed by RUR.print_path. * @param {string} [color] The color to be used to draw the path; * the default is `"lightsteelblue"`. * */ RUR.show_path = function (path, color) { var world = RUR.get_current_world(); if (path === undefined) { world._CORRECT_PATH = []; } else { world._CORRECT_PATH = path; } if (color === undefined) { world._CORRECT_PATH_COLOR = "lightsteelblue"; } else { world._CORRECT_PATH_COLOR = color; } RUR.record_frame("show_path"); };