require("./../rur.js"); require("./../translator.js"); require("./../default_tiles/tiles.js"); require("./output.js"); require("./../recorder/record_frame.js"); require("./exceptions.js"); require("./../world_get/world_get.js"); require("./../utils/supplant.js"); require("./../utils/key_exist.js"); require("./../world_api/walls.js"); require("./../world_api/obstacles.js"); require("./../world_api/background_tile.js"); require("./../world_api/pushables.js"); require("./../world_api/robot.js"); require("./../world_api/composition.js"); require("./../world_api/is_fatal.js"); RUR.control = {}; RUR.control.move = function (robot) { "use strict"; var position, next_x, next_y, orientation, pushable_in_the_way, tile, tiles, x_beyond, y_beyond, recording_state, next_position, current_x, current_y, message; if (RUR.control.wall_in_front(robot)) { throw new RUR.WallCollisionError(RUR.translate("Ouch! I hit a wall!")); } position = RUR.get_position_in_front(robot); next_x = position.x; next_y = position.y; // attempt a move, by first saving the current position current_x = robot.x; current_y = robot.y; robot.x = next_x; robot.y = next_y; // If we move, are we going to push something else in front of us? pushable_in_the_way = RUR.get_pushable(next_x, next_y); if (pushable_in_the_way !== null) { next_position = RUR.get_position_in_front(robot); x_beyond = next_position.x; y_beyond = next_position.y; if (RUR.control.wall_in_front(robot) || RUR.get_pushable(x_beyond, y_beyond) || RUR.is_solid_obstacle(x_beyond, y_beyond) || RUR.is_robot(x_beyond, y_beyond)) { // reverse the move robot.x = current_x; robot.y = current_y; throw new RUR.ReeborgError(RUR.translate("Something is blocking the way!")); } else { RUR._push_pushable(pushable_in_the_way, next_x, next_y, x_beyond, y_beyond); RUR.transform_tile(pushable_in_the_way, x_beyond, y_beyond); } } // We can now complete the move if (robot._is_leaky !== undefined && !robot._is_leaky) { // avoid messing the trace if and when we resume having a leaky robot robot._prev_x = robot.x; robot._prev_y = robot.y; } else { robot._prev_x = current_x; robot._prev_y = current_y; } RUR.state.sound_id = "#move-sound"; // A move has been performed ... but it may have been a fatal decision message = RUR.is_fatal_position(robot.x, robot.y, robot); if (message) { throw new RUR.ReeborgError(message); } RUR.record_frame("move", robot.__id); }; // leave end of line comments below such as using += 1 // as I (indirectly) refer to these comments in the programming tutorial RUR.control.turn_left = function(robot){ "use strict"; var random; if (robot._orientation == RUR.RANDOM_ORIENTATION) { random = Math.floor(Math.random() * 4); robot._orientation = random; robot._prev_orientation = random; } else { robot._prev_orientation = robot._orientation; robot._orientation ++; robot._orientation %= 4; } robot._prev_x = robot.x; robot._prev_y = robot.y; RUR.state.sound_id = "#turn-sound"; if (robot._is_leaky !== undefined && !robot._is_leaky) { // update to avoid drawing from previous point. robot._prev_orientation = robot._orientation; } RUR.record_frame("turn_left", robot.__id); }; RUR.control.__turn_right = function(robot){ "use strict"; robot._prev_orientation = (robot._orientation+2)%4; // fix so that oil trace looks right robot._prev_x = robot.x; robot._prev_y = robot.y; robot._orientation += 3; robot._orientation %= 4; if (robot._is_leaky !== undefined && !robot._is_leaky) { // update to avoid drawing from previous point. robot._prev_orientation = robot._orientation; } RUR.record_frame("__turn_right", robot.__id); }; RUR.control.pause = function (ms) { RUR.record_frame("pause", {pause_time:ms}); }; RUR.control.done = function () { RUR.state.done_executed = true; throw new RUR.ReeborgError(RUR.translate("Done!")); }; RUR.control.put = function(robot, arg){ var arg_in_english, objects_carried, obj_type, all_objects; RUR.state.sound_id = "#put-sound"; arg_in_english = confirm_object_is_known(arg); all_objects = get_names_of_objects_carried(robot.objects); put_check_for_error (arg, arg_in_english, all_objects, robot.objects); // no error, we can proceed robot_put_or_toss_object(robot, arg_in_english, "put"); }; RUR.control.toss = function(robot, arg){ var arg_in_english, objects_carried, obj_type, all_objects; arg_in_english = confirm_object_is_known(arg); all_objects = get_names_of_objects_carried(robot.objects); put_check_for_error (arg, arg_in_english, all_objects, robot.objects); // no error, we can proceed robot_put_or_toss_object(robot, arg_in_english, "throw"); }; function confirm_object_is_known(arg) { var arg_in_english; if (arg !== undefined) { arg_in_english = RUR.translate_to_english(arg); if (RUR.KNOWN_THINGS.indexOf(arg_in_english) == -1){ throw new RUR.ReeborgError(RUR.translate("Unknown object").supplant({obj: arg})); } } return arg_in_english; } function get_names_of_objects_carried(objects_carried) { var obj_type, all_objects = []; for (obj_type in objects_carried) { if (objects_carried.hasOwnProperty(obj_type)) { all_objects.push(obj_type); } } return all_objects; } function put_check_for_error (arg, arg_in_english, all_objects, carried) { "use strict"; if (arg !== undefined) { if (all_objects.length === 0){ throw new RUR.MissingObjectError(RUR.translate("I don't have any object to put down!").supplant({obj:arg})); } if (carried[arg_in_english] === undefined) { throw new RUR.MissingObjectError(RUR.translate("I don't have any object to put down!").supplant({obj:arg})); } } else { if (all_objects.length === 0){ throw new RUR.MissingObjectError(RUR.translate("I don't have any object to put down!").supplant({obj: RUR.translate("object")})); } else if (all_objects.length > 1){ throw new RUR.MissingObjectError(RUR.translate("I carry too many different objects. I don't know which one to put down!")); } } } robot_put_or_toss_object = function (robot, obj, action) { "use strict"; var objects_carried, coords, obj_type, position, x, y; RUR.utils.ensure_key_for_obj_exists(RUR.get_current_world(), "objects"); if (action == "put") { x = robot.x; y = robot.y; } else if (action == "throw") { position = RUR.get_position_in_front(robot); x = position.x; y = position.y; } else { throw new RUR.ReeborgError("Fatal error, unknown action in put/throw :", action); } coords = x + "," + y; if (obj === undefined){ //obj = Object.keys(robot.objects)[0]; // we have already ensured that there is only one objects_carried = robot.objects; for (obj_type in objects_carried) { if (objects_carried.hasOwnProperty(obj_type)) { obj = obj_type; } } } if (robot.objects[obj] != "infinite") { robot.objects[obj] -= 1; } if (robot.objects[obj] === 0) { delete robot.objects[obj]; } RUR.utils.ensure_key_for_obj_exists(RUR.get_current_world().objects, coords); if (RUR.get_current_world().objects[coords][obj] === undefined) { RUR.get_current_world().objects[coords][obj] = 1; } else { RUR.get_current_world().objects[coords][obj] += 1; } RUR.transform_tile(obj, x, y); RUR.record_frame(action, [robot.__id, obj]); }; function is_fatal_thing(thing, robot) { var protections; protections = RUR.get_protections(robot); if (RUR.get_property(thing, "fatal")) { if (protections.indexOf(RUR.get_property(thing, "fatal")) === -1) { return true; } } return false; } RUR.control.take = function(robot, arg){ var translated_arg, objects_here, message; RUR.state.sound_id = "#take-sound"; if (arg !== undefined) { translated_arg = RUR.translate_to_english(arg); if (RUR.KNOWN_THINGS.indexOf(translated_arg) == -1){ throw new RUR.ReeborgError(RUR.translate("Unknown object").supplant({obj: arg})); } } objects_here = RUR.world_get.object_at_robot_position(robot, arg); if (arg !== undefined) { if (Array.isArray(objects_here) && objects_here.length === 0) { throw new RUR.MissingObjectError(RUR.translate("No object found here").supplant({obj: arg})); } else if(is_fatal_thing(arg, robot)) { message = RUR.get_property(arg, 'message'); if (!message) { message = "I picked up a fatal object."; } throw new RUR.ReeborgError(RUR.translate(message)); } else { take_object_and_give_to_robot(robot, arg); } } else if (Array.isArray(objects_here) && objects_here.length === 0){ throw new RUR.MissingObjectError(RUR.translate("No object found here").supplant({obj: RUR.translate("object")})); } else if (objects_here.length > 1){ throw new RUR.MissingObjectError(RUR.translate("Many objects are here; I do not know which one to take!")); } else if(is_fatal_thing(objects_here[0], robot)) { message = RUR.get_property(objects_here[0], 'message'); if (!message) { message = "I picked up a fatal object."; } throw new RUR.ReeborgError(RUR.translate(message)); } else { take_object_and_give_to_robot(robot, objects_here[0]); } }; take_object_and_give_to_robot = function (robot, obj) { var objects_here, coords; obj = RUR.translate_to_english(obj); coords = robot.x + "," + robot.y; RUR.get_current_world().objects[coords][obj] -= 1; if (RUR.get_current_world().objects[coords][obj] === 0){ delete RUR.get_current_world().objects[coords][obj]; // Testing for empty array. // In Javascript []==[] is false and ![] is false ... // Python is so much nicer than Javascript. objects_here = RUR.world_get.object_at_robot_position(robot); if (Array.isArray(objects_here) && objects_here.length === 0){ delete RUR.get_current_world().objects[coords]; } } RUR.utils.ensure_key_for_obj_exists(robot, "objects"); if (robot.objects[obj] === undefined){ robot.objects[obj] = 1; } else { if (robot.objects[obj] != "infinite") { robot.objects[obj]++; } } RUR.record_frame("take", [robot.__id, obj]); }; RUR.control.build_wall = function (robot){ RUR.state.sound_id = "#build-sound"; switch (robot._orientation){ case RUR.EAST: RUR.add_wall("east", robot.x, robot.y); // records automatically break; case RUR.NORTH: RUR.add_wall("north", robot.x, robot.y); break; case RUR.WEST: RUR.add_wall("west", robot.x, robot.y); break; case RUR.SOUTH: RUR.add_wall("south", robot.x, robot.y); break; default: throw new RUR.ReeborgError("Should not happen: unhandled case in RUR.control.build_wall()."); } }; RUR.control.wall_in_front = function (robot) { switch (robot._orientation){ case RUR.EAST: return RUR._is_wall("east", robot.x, robot.y); case RUR.NORTH: return RUR._is_wall("north", robot.x, robot.y); case RUR.WEST: return RUR._is_wall("west", robot.x, robot.y); case RUR.SOUTH: return RUR._is_wall("south", robot.x, robot.y); case RUR.RANDOM_ORIENTATION: throw new RUR.ReeborgError(RUR.translate("I am too dizzy!")); default: throw new RUR.ReeborgError("Should not happen: unhandled case in RUR.control.wall_in_front()."); } }; RUR.control.wall_on_right = function (robot) { var result, saved_recording_state; saved_recording_state = RUR._recording_(false); RUR.control.__turn_right(robot); result = RUR.control.wall_in_front(robot); RUR.control.turn_left(robot); RUR._recording_(saved_recording_state); return result; }; RUR.control.front_is_clear = function(robot){ var tile, tiles, solid, name, position, next_x, next_y; if( RUR.control.wall_in_front(robot)) { return false; } position = RUR.get_position_in_front(robot); next_x = position.x; next_y = position.y; if (RUR.is_fatal_position(next_x, next_y, robot) && RUR.is_detectable_position(next_x, next_y)) { return false; } return true; }; RUR.control.right_is_clear = function(robot){ var result, saved_recording_state; saved_recording_state = RUR._recording_(false); RUR.control.__turn_right(robot); result = RUR.control.front_is_clear(robot); RUR.control.turn_left(robot); RUR._recording_(saved_recording_state); return result; }; RUR.control.is_facing_north = function (robot) { return robot._orientation === RUR.NORTH; }; RUR.control.think = function (delay) { var old_delay = RUR.PLAYBACK_TIME_PER_FRAME; RUR.PLAYBACK_TIME_PER_FRAME = delay; return old_delay; }; RUR.control.at_goal = function (robot) { var goal = RUR.get_current_world().goal; if (goal !== undefined){ if (goal.position !== undefined) { return (robot.x === goal.position.x && robot.y === goal.position.y); } throw new RUR.ReeborgError(RUR.translate("There is no position as a goal in this world!")); } throw new RUR.ReeborgError(RUR.translate("There is no goal in this world!")); }; RUR.control.carries_object = function (robot, obj) { var obj_type, all_objects, carried=false; if (robot === undefined || robot.objects === undefined) { return 0; } all_objects = {}; if (obj === undefined) { for (obj_type in robot.objects) { if (robot.objects.hasOwnProperty(obj_type)) { all_objects[RUR.translate(obj_type)] = robot.objects[obj_type]; carried = true; } } if (carried) { return all_objects; } else { return 0; } } else { obj = RUR.translate_to_english(obj); for (obj_type in robot.objects) { if (robot.objects.hasOwnProperty(obj_type) && obj_type == obj) { return robot.objects[obj_type]; } } return 0; } }; RUR.control.set_model = function(robot, model){ var default_robot; robot.model = model; default_robot = RUR.get_current_world().robots[0]; if (default_robot.__id == robot.__id) { RUR.user_selected_model = undefined; // overrides the user's choice } RUR.record_frame("set_model", robot.__id); }; /** @function set_model * @memberof RUR * @instance * @summary This function, intended for world creators, allow to set the * model for the default robot, overriding the user's default choice. * * @param {string} model The name of the model */ RUR.set_model = function(model){ var robot; robot = RUR.get_current_world().robots[0]; robot.model = model; RUR.user_selected_model = undefined; // overrides the user's choice RUR.record_frame("RUR.set_model", robot.__id); }; RUR.control.set_trace_color = function(robot, color){ robot._trace_color = color; }; RUR.control.set_trace_style = function(robot, style){ robot._trace_style = style; }; if (RUR.state === undefined){ RUR.state = {}; } RUR.state.sound_on = false; RUR.control.sound = function(on){ if(!on){ RUR.state.sound_on = false; return; } RUR.state.sound_on = true; };