def simulate(batch_file, preset_filename, bot_paths, seed, override_settings,
             *queues_sizes):
    result_queue = queues_sizes[0][0]
    result_queue._internal_size = queues_sizes[0][1]
    StateHandler.instance.shared_info = {
        "result_queue": result_queue,
    }
    send_queues = [q for q, _ in queues_sizes[1::2]]
    for i, (_, size) in enumerate(queues_sizes[1::2]):
        send_queues[i]._internal_size = size
    recv_queues = [q for q, _ in queues_sizes[2::2]]
    for i, (_, size) in enumerate(queues_sizes[2::2]):
        recv_queues[i]._internal_size = size

    Randomiser.createGlobalRandomiserWithSeed(seed)

    preset_file = find_abs(preset_filename, allowed_areas=preset_locations())
    with open(preset_file, "r") as f:
        config = yaml.safe_load(f)
    config["settings"] = config.get("settings", {})
    recursive_merge(config["settings"], override_settings)

    config["robots"] = config.get("robots", []) + bot_paths

    initialiseFromConfig(config, send_queues, recv_queues)
Exemple #2
0
 def initWithKwargs(self, **kwargs):
     self.in_error = False
     self.first_launch = True
     batch = kwargs.get("batch_file", None)
     self.batch = batch
     if batch is None:
         # We are simply viewing the bots to edit or manage.
         self.bot_keys = []
     else:
         self.key_index = 0
         with open(batch, "r") as f:
             b_config = yaml.safe_load(f)
         preset = b_config["preset_file"]
         fname = find_abs(preset, allowed_areas=preset_locations())
         with open(fname, "r") as f:
             p_config = yaml.safe_load(f)
         self.bot_keys = p_config["bot_names"]
         self.bot_values = [None] * len(self.bot_keys)
         self.preview_images = [None] * len(self.bot_keys)
     self.bot_select_index = 0
     self.select_enable = False
     self.code_enable = False
     self.edit_enable = False
     self.remove_enable = False
     self.bot_index = -1
     self.next = kwargs.get("next", None)
     self.next_kwargs = kwargs.get("next_kwargs", {})
     super().initWithKwargs(**kwargs)
Exemple #3
0
def run_sim(sim_path, edit=False):
    from ev3sim.validation.batch_files import BatchValidator

    if not BatchValidator.validate_file(sim_path):
        return raise_error(
            f"There is something wrong with the sim {sim_path}, and so it cannot be opened or used."
        )
    if not edit:
        return [ScreenObjectManager.SCREEN_SIM], [{
            "batch": sim_path,
        }]
    import importlib

    with open(sim_path, "r") as f:
        conf = yaml.safe_load(f)
    with open(find_abs(conf["preset_file"], preset_locations())) as f:
        preset = yaml.safe_load(f)
    if "visual_settings" not in preset:
        return raise_error("This preset cannot be edited.")
    mname, cname = preset["visual_settings"].rsplit(".", 1)
    klass = getattr(importlib.import_module(mname), cname)

    return [ScreenObjectManager.SCREEN_SETTINGS], [{
        "file": sim_path,
        "settings": klass,
        "allows_filename_change": True,
        "extension": "sim",
    }]
Exemple #4
0
 def clickSimBots(self, preset):
     abs_path = find_abs(preset, allowed_areas=preset_locations())
     with open(abs_path, "r") as f:
         preset_config = yaml.safe_load(f)
     sim_path = find_abs(preset_config["sim_location"],
                         allowed_areas=batch_locations())
     ScreenObjectManager.instance.pushScreen(
         ScreenObjectManager.SCREEN_BOTS,
         batch_file=sim_path,
     )
Exemple #5
0
    def clickSimSettings(self, preset):
        import importlib

        abs_path = find_abs(preset, allowed_areas=preset_locations())
        with open(abs_path, "r") as f:
            preset_config = yaml.safe_load(f)
        sim_path = find_abs(preset_config["sim_location"],
                            allowed_areas=batch_locations())
        mname, cname = preset_config["visual_settings"].rsplit(".", 1)
        klass = getattr(importlib.import_module(mname), cname)
        ScreenObjectManager.instance.pushScreen(
            ScreenObjectManager.SCREEN_SETTINGS,
            file=sim_path,
            settings=klass,
            allows_filename_change=False,
            extension="sim",
        )
Exemple #6
0
def fromOptions(options):
    if "filename" in options:
        import yaml

        fname = find_abs(options["filename"])
        with open(fname, "r") as f:
            config = yaml.safe_load(f)
            return fromOptions(config)
    if "class_path" not in options:
        raise ValueError(
            "Your options has no 'class_path' or 'filename' entry (Or the file you reference has no 'class_path' entry')"
        )
    import importlib

    if isinstance(options["class_path"], str):
        mname, cname = options["class_path"].rsplit(".", 1)

        klass = getattr(importlib.import_module(mname), cname)
    else:
        from importlib.machinery import SourceFileLoader

        module = SourceFileLoader(
            "not_main", find_abs(options["class_path"][0],
                                 preset_locations())).load_module()
        klass = getattr(module, options["class_path"][1])
    topObj = klass(*options.get("args", []), **options.get("kwargs", {}))
    # Add any settings for this interactor, if applicable.
    # This only works for package presets. Not workspace ones.
    if "settings_name" in options:
        name = options["settings_name"]
        if "settings_defn" not in options:
            raise ValueError(
                f"Expected a settings object to add with group name {name}")
        mname, cname = options["settings_defn"].rsplit(".", 1)
        obj = getattr(importlib.import_module(mname), cname)
        SettingsManager.instance.addSettingGroup(name, obj)
        # We need to remove this setting once the simulation ends, so save the name.
        topObj._settings_name = name
    return topObj
Exemple #7
0
    def spawnTiles(self):
        self.tiles = []
        for i, tile in enumerate(self.TILE_DEFINITIONS):
            self.tiles.append({})
            import yaml

            path = find_abs(tile["path"], allowed_areas=preset_locations())
            with open(path, "r") as f:
                t = yaml.safe_load(f)
            self.maxZpos = 0
            base_pos = np.array(tile.get("position", [0, 0]))
            # Transfer to rescue space.
            base_pos = [base_pos[0] * self.TILE_LENGTH, base_pos[1] * self.TILE_LENGTH]
            base_rotation = tile.get("rotation", 0) * np.pi / 180
            flip = tile.get("flip", False)
            for obj in t["elements"]:
                rel_pos = np.array(obj.get("position", [0, 0]))
                if flip:
                    rel_pos[0] = -rel_pos[0]
                    if obj.get("name", "") == "Image":
                        obj["flip"] = [True, False]
                    if obj.get("name", "") == "Arc":
                        obj["rotation"] = 180 - obj.get("rotation", 0)
                        obj["angle"] = -obj["angle"]
                obj["rotation"] = (obj.get("rotation", 0)) * np.pi / 180 + base_rotation
                obj["position"] = local_space_to_world_space(rel_pos, base_rotation, base_pos)
                obj["sensorVisible"] = True
                k = obj["key"]
                obj["key"] = f"Tile-{i}-{k}"
                self.maxZpos = max(self.maxZpos, obj.get("zPos", 0))
            t["elements"].append(
                {
                    "position": local_space_to_world_space(np.array([0, 0]), base_rotation, base_pos),
                    "rotation": base_rotation,
                    "type": "visual",
                    "name": "Rectangle",
                    "width": self.TILE_LENGTH,
                    "height": self.TILE_LENGTH,
                    "fill": None,
                    "stroke_width": 0.1,
                    "stroke": "rescue_outline_color",
                    "zPos": self.maxZpos + 0.1,
                    "key": f"Tile-{i}-outline",
                    "sensorVisible": False,
                }
            )
            self.tiles[-1]["type"] = t.get("type", "follow")
            self.tiles[-1]["follows"] = []
            self.tiles[-1]["roam_status"] = []
            self.tiles[-1]["world_pos"] = base_pos
            self.tiles[-1]["rotation"] = base_rotation
            self.tiles[-1]["flip"] = flip
            if self.tiles[-1]["type"] == "follow":
                self.tiles[-1]["entries"] = t["entries"]
                self.tiles[-1]["exits"] = t["exits"]
                mname, cname = t.get("checker").rsplit(".", 1)
                import importlib

                klass = getattr(importlib.import_module(mname), cname)
                with open(find_abs(t["ui"], allowed_areas=preset_locations()), "r") as f:
                    self.tiles[-1]["ui_elem"] = yaml.safe_load(f)
                for j, point in enumerate(t["follow_points"]):
                    if isinstance(point[0], (list, tuple)):
                        self.tiles[-1]["follows"].append([])
                        self.tiles[-1]["roam_status"].append([])
                        for path in point:
                            self.tiles[-1]["follows"][-1].append([])
                            self.tiles[-1]["roam_status"][-1].append([])
                            for point2 in path:
                                if isinstance(point2, str):
                                    self.tiles[-1]["roam_status"][-1][-1][-1] = point2
                                else:
                                    if flip:
                                        point2[0] = -point2[0]
                                    self.tiles[-1]["follows"][-1][-1].append(
                                        local_space_to_world_space(
                                            np.array(point2), tile.get("rotation", 0) * np.pi / 180, base_pos
                                        )
                                    )
                                    self.tiles[-1]["roam_status"][-1][-1].append(None)
                    else:
                        if isinstance(point, str):
                            self.tiles[-1]["roam_status"][-1] = point
                        else:
                            if flip:
                                point[0] = -point[0]
                            self.tiles[-1]["follows"].append(
                                local_space_to_world_space(
                                    np.array(point), tile.get("rotation", 0) * np.pi / 180, base_pos
                                )
                            )
                            self.tiles[-1]["roam_status"].append(None)
                self.tiles[-1]["checker"] = klass(self.tiles[-1]["follows"], i, self, **t.get("checker_kwargs", {}))
            else:
                self.tiles[-1]["green_conns"] = t.get("green_conns", [])
            self.tiles[-1]["all_elems"] = ScriptLoader.instance.loadElements(t["elements"])
        connecting_objs = []
        for tile in self.tiles:
            # We need to add connections between green tiles if they exist.
            if tile["type"] == "follow":
                continue
            under, right, under_right = self._checkConnectingRescueTiles(tile["world_pos"])
            if under_right and under and right:
                # Draw a big square connecting all 4 tiles.
                key = "c1-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1])
                connecting_objs.append(
                    {
                        "type": "visual",
                        "name": "Rectangle",
                        "width": 50,
                        "height": 50,
                        "fill": "grass_color",
                        "zPos": 0.3,
                        "key": key,
                        "position": [
                            tile["world_pos"][0] + self.TILE_LENGTH / 2,
                            tile["world_pos"][1] + self.TILE_LENGTH / 2,
                        ],
                        "sensorVisible": True,
                    }
                )
            else:
                if under:
                    key = "c2-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1])
                    connecting_objs.append(
                        {
                            "type": "visual",
                            "name": "Rectangle",
                            "width": 20,
                            "height": 50,
                            "fill": "grass_color",
                            "zPos": 0.3,
                            "key": key,
                            "position": [tile["world_pos"][0], tile["world_pos"][1] + self.TILE_LENGTH / 2],
                            "sensorVisible": True,
                        }
                    )
                if right:
                    key = "c3-" + str(tile["world_pos"][0]) + "-" + str(tile["world_pos"][1])
                    connecting_objs.append(
                        {
                            "type": "visual",
                            "name": "Rectangle",
                            "width": 50,
                            "height": 20,
                            "fill": "grass_color",
                            "zPos": 0.3,
                            "key": key,
                            "position": [tile["world_pos"][0] + self.TILE_LENGTH / 2, tile["world_pos"][1]],
                            "sensorVisible": True,
                        }
                    )
        self.connecting_objs = ScriptLoader.instance.loadElements(connecting_objs)
Exemple #8
0
    def playSim(self, preset):
        abs_path = find_abs(preset, allowed_areas=preset_locations())
        with open(abs_path, "r") as f:
            preset_config = yaml.safe_load(f)
        sim_path = find_abs(preset_config["sim_location"],
                            allowed_areas=batch_locations())
        with open(sim_path, "r") as f:
            sim_config = yaml.safe_load(f)
        to_remove = []
        for index in range(len(sim_config["bots"])):
            # Try loading this bot.
            try:
                with open(
                        os.path.join(
                            find_abs(sim_config["bots"][index],
                                     bot_locations()), "config.bot"),
                        "r") as f:
                    bot_config = yaml.safe_load(f)
                if not BotValidator.validate_json(bot_config):
                    to_remove.append(index)
                if bot_config.get("type", "python") == "python":
                    fname = bot_config.get("script", "code.py")
                else:
                    fname = bot_config.get("script", "program.ev3")
                if not os.path.exists(
                        os.path.join(
                            find_abs(sim_config["bots"][index],
                                     bot_locations()), fname)):

                    def action():
                        with open(
                                os.path.join(
                                    find_abs(sim_config["bots"][index],
                                             bot_locations()), fname),
                                "w") as f:
                            f.write("# Put your code here!\n")

                    ScreenObjectManager.instance.forceCloseError(
                        f"Your bot {sim_config['bots'][index]} does not contain the file {fname}. You may have renamed or deleted it by accident. In order to use this bot, you need to add this file back. Click \"Add {fname}\" to create this file, or do it manually.",
                        (f"Add {fname}", action),
                    )
                    return
            except:
                to_remove.append(index)
        if to_remove:
            for index in to_remove[::-1]:
                del sim_config["bots"][index]
            with open(sim_path, "w") as f:
                f.write(yaml.dump(sim_config))
        if not sim_config["bots"]:
            # We cannot play, there no are valid bots.
            return ScreenObjectManager.instance.pushScreen(
                ScreenObjectManager.SCREEN_BOTS,
                batch_file=sim_path,
                next=ScreenObjectManager.instance.SCREEN_SIM,
                next_kwargs={"batch": sim_path},
            )
        return ScreenObjectManager.instance.pushScreen(
            ScreenObjectManager.instance.SCREEN_SIM,
            batch=sim_path,
        )
    def drawTileDialog(self):
        class TilePicker(pygame_gui.elements.UIWindow):
            def kill(self2):
                self.mode = self.MODE_NORMAL
                self._all_objs.remove(self2)
                super().kill()

            def process_event(self2, event: pygame.event.Event) -> bool:
                if event.type == pygame.MOUSEWHEEL:
                    self.scroll_container.vert_scroll_bar.scroll_position -= event.y * 10
                    self.scroll_container.vert_scroll_bar.scroll_position = min(
                        max(
                            self.scroll_container.vert_scroll_bar.
                            scroll_position,
                            self.scroll_container.vert_scroll_bar.top_limit,
                        ),
                        self.scroll_container.vert_scroll_bar.bottom_limit -
                        self.scroll_container.vert_scroll_bar.sliding_button.
                        relative_rect.height,
                    )
                    x_pos = 0
                    y_pos = (
                        self.scroll_container.vert_scroll_bar.scroll_position +
                        self.scroll_container.vert_scroll_bar.
                        arrow_button_height)
                    self.scroll_container.vert_scroll_bar.sliding_button.set_relative_position(
                        (x_pos, y_pos))
                    self.scroll_container.vert_scroll_bar.start_percentage = (
                        self.scroll_container.vert_scroll_bar.scroll_position /
                        self.scroll_container.vert_scroll_bar.scrollable_height
                    )
                    self.scroll_container.vert_scroll_bar.has_moved_recently = True
                if event.type == pygame.USEREVENT and event.user_type == pygame_gui.UI_BUTTON_PRESSED:
                    if event.ui_object_id.split(".")[-1].startswith("tile-"):
                        index = int(
                            event.ui_object_id.split(".")[-1].split("-")[1])
                        self.placeTile(index)
                        self2.kill()
                        self.regenerateObjects()
                        return True
                return super().process_event(event)

        picker_size = (self._size[0] * 0.7, self._size[1] * 0.7)
        self.picker = TilePicker(
            rect=pygame.Rect(self._size[0] * 0.15, self._size[1] * 0.15,
                             *picker_size),
            manager=self,
            window_display_title="Pick Tile Type",
            object_id=pygame_gui.core.ObjectID("tile_dialog"),
        )
        self._all_objs.append(self.picker)

        button_size = (picker_size[0] - 120) / 3
        button_pos = lambda i: ((button_size + 15) * (i % 3), 10 +
                                (button_size + 15) * (i // 3))

        self.tile_buttons = []
        self.tile_images = []
        self.scroll_container = pygame_gui.elements.UIScrollingContainer(
            relative_rect=pygame.Rect(20, 10, picker_size[0] - 60,
                                      picker_size[1] - 80),
            container=self.picker,
            manager=self,
        )
        self._all_objs.append(self.scroll_container)
        for i in range(len(self.tile_locations)):
            rect = pygame.Rect(*button_pos(i), button_size, button_size)
            self.tile_buttons.append(
                pygame_gui.elements.UIButton(
                    relative_rect=rect,
                    text=f"{i}",
                    manager=self,
                    container=self.scroll_container,
                    object_id=pygame_gui.core.ObjectID(f"tile-{i}-button",
                                                       "invis_button"),
                ))
            with open(
                    find_abs(f"tiles/definitions/{self.tile_locations[i]}",
                             preset_locations()), "r") as f:
                conf = yaml.safe_load(f)
            self.tile_images.append(
                pygame_gui.elements.UIImage(
                    relative_rect=rect,
                    image_surface=pygame.image.load(
                        find_abs(conf["preview"], preset_locations())),
                    manager=self,
                    container=self.scroll_container,
                    object_id=pygame_gui.core.ObjectID(f"tile-{i}-image"),
                ))
        self._all_objs.extend(self.tile_buttons)
        self._all_objs.extend(self.tile_images)
        self.scroll_container.set_scrollable_area_dimensions(
            (picker_size[0] - 80,
             (button_size + 15) * ((len(self.tile_locations) + 2) // 3)))
Exemple #10
0
    def resetRescueVisual(self):
        from ev3sim.visual.manager import ScreenObjectManager
        from ev3sim.simulation.loader import ScriptLoader
        from ev3sim.presets.rescue import RescueInteractor

        ScriptLoader.instance.reset()
        ScriptLoader.instance.startUp()
        ScreenObjectManager.instance.resetVisualElements()
        with open(find_abs("rescue.yaml", preset_locations()), "r") as f:
            conf = yaml.safe_load(f)
        utils.GLOBAL_COLOURS.update(conf.get("colours", {}))

        r = RescueInteractor()
        r.TILE_DEFINITIONS = self.current_tiles
        r.CAN_SPAWN_POSITION = (self.previous_info.get("settings", {}).get(
            "rescue", {}).get("CAN_SPAWN_POSITION", [0, 0]))
        self.customMap = {
            "SCREEN_WIDTH": self._size[0],
            "SCREEN_HEIGHT": self._size[1],
            "MAP_WIDTH": 293.3,
            "MAP_HEIGHT": 200,
        }

        placeableArea = visualFactory(
            name="Rectangle",
            width=8 * 30,
            height=6 * 30,
            position=(15 + self.tile_offset[0], -15 + self.tile_offset[1]),
            fill="#6f6f6f",
        )
        placeableArea.customMap = self.customMap
        placeableArea.calculatePoints()
        ScreenObjectManager.instance.registerVisual(placeableArea,
                                                    "placeableArea")
        remove = []
        for key in ScreenObjectManager.instance.objects:
            if key.startswith("tile-entry"):
                remove.append(key)
        for key in remove:
            ScreenObjectManager.instance.unregisterVisual(key)
        r.spawnTiles()
        for index, tile in enumerate(r.tiles):
            direction, rotation = self.getDirsAndRotations(tile)
            if tile["type"] == "follow":
                for i, entry_dir in enumerate(tile["entries"]):
                    startArrow = visualFactory(
                        name="Polygon",
                        verts=[
                            [1.96, 0],
                            [0.21, 1.75],
                            [0.21, 0.5],
                            [-1.4, 0.5],
                            [-1.4, -0.5],
                            [0.21, -0.5],
                            [0.21, -1.75],
                            [1.96, 0],
                        ],
                        fill="#219ebc",
                        stroke_width=0,
                        zPos=0.1,
                        sensorVisible=False,
                        rotation=rotation[entry_dir],
                    )
                    startArrow.key = f"tile-{index}-entry-{i}"
                    startArrow.position = [
                        tile["world_pos"][0] + self.tile_offset[0] +
                        direction[entry_dir][0] * 11,
                        tile["world_pos"][1] + self.tile_offset[1] +
                        direction[entry_dir][1] * 11,
                    ]
                    startArrow.customMap = self.customMap
                    startArrow.calculatePoints()
                    ScreenObjectManager.instance.registerVisual(
                        startArrow, startArrow.key)

            for obj in tile["all_elems"]:
                obj.position = [
                    obj.position[0] + self.tile_offset[0],
                    obj.position[1] + self.tile_offset[1],
                ]
                if isinstance(obj, IVisualElement):
                    obj.customMap = self.customMap
                    obj.calculatePoints()
                elif isinstance(obj, BaseObject):
                    obj.visual.customMap = self.customMap
                    obj.visual.calculatePoints()
        for obj in r.connecting_objs:
            obj.customMap = self.customMap
            obj.position = [
                obj.position[0] + self.tile_offset[0],
                obj.position[1] + self.tile_offset[1],
            ]
        r.spawnCan()
        r.can_obj.visual.customMap = self.customMap
        r.can_obj.body.position = [
            a + b for a, b in zip(r.can_obj.body.position, self.tile_offset)
        ]
        r.can_obj.position = np.array(r.can_obj.body.position)
        r.can_obj.visual.calculatePoints()
        self.can_obj = r.can_obj
        self.current_tile_objects = r.tiles
        self.updateSelectPlacement()