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)
def captureBotImage(self, directory, filename): self.resetVisualElements() from os.path import join from ev3sim.simulation.loader import ScriptLoader from ev3sim.robot import initialise_bot, RobotInteractor from ev3sim.simulation.randomisation import Randomiser Randomiser.createGlobalRandomiserWithSeed(0) ScriptLoader.instance.reset() ScriptLoader.instance.startUp() elems = {} initialise_bot(elems, find_abs(filename, [directory]), "", 0) ScriptLoader.instance.loadElements(elems.get("elements", [])) for interactor in ScriptLoader.instance.active_scripts: if isinstance(interactor, RobotInteractor): interactor.connectDevices() interactor.initialiseDevices() for interactor in ScriptLoader.instance.active_scripts: interactor.startUp() interactor.tick(0) interactor.afterPhysics() screen = pygame.Surface((480, 480), pygame.SRCALPHA) custom_map = { "SCREEN_WIDTH": 480, "SCREEN_HEIGHT": 480, "MAP_WIDTH": 25, "MAP_HEIGHT": 25, } for elem in self.objects.values(): elem.customMap = custom_map elem.calculatePoints() self.applyToScreen(screen, bg=pygame.Color(self.instance.background_colour)) colorkey = pygame.Color(self.instance.background_colour) for x in range(480): for y in range(480): val = screen.get_at((x, y)) val.a = 0 if (val.r == colorkey.r and val.g == colorkey.g and val.b == colorkey.b) else 255 screen.set_at((x, y), val) self.resetVisualElements() ScriptLoader.instance.reset() config_path = join(find_abs(filename, [directory]), "config.bot") with open(config_path, "r") as f: config = yaml.safe_load(f) pygame.image.save(screen, join(find_abs(filename, [directory]), config.get("preview_path", "preview.png")))
def single_run(preset_filename, robots, bind_addr, seed, batch_file=None, override_settings={}): if batch_file: ScreenObjectManager.BATCH_FILE = batch_file ScreenObjectManager.PRESET_FILE = preset_filename import ev3sim try: latest_version = get_version_pypi("ev3sim") ScreenObjectManager.NEW_VERSION = latest_version != ev3sim.__version__ if ScreenObjectManager.NEW_VERSION: update_message = f"""\ ========================================================================================== There is a new version of ev3sim available ({latest_version}). Keeping an up to date version of ev3sim ensures you have the latest bugfixes and features. Please update ev3sim by running the following command: python -m pip install -U ev3sim ========================================================================================== """ print(update_message) except: ScreenObjectManager.NEW_VERSION = False Randomiser.createGlobalRandomiserWithSeed(seed) preset_file = find_abs(preset_filename, allowed_areas=[ "local", "local/presets/", "package", "package/presets/" ]) with open(preset_file, "r") as f: config = yaml.safe_load(f) config["robots"] = config.get("robots", []) + robots shared_data = { "tick": 0, # Current tick. "write_stack": deque(), # All write actions are processed through this. "data_queue": {}, # Simulation data for each bot. "active_count": {}, # Keeps track of which code connection each bot has. "bot_locks": {}, # Threading Locks and Conditions for each bot to wait for connection actions. "bot_communications_data": {}, # Buffers and information for all bot communications. "tick_updates": {}, # Simply a dictionary where the simulation tick will push static data, so the other methods are aware of when the simulation has exited. "events": {}, # Any events that should be sent to robots. } result_bucket = Queue(maxsize=1) from threading import Thread from ev3sim.simulation.communication import start_server_with_shared_data def run(shared_data, result): try: runFromConfig(config, shared_data) except Exception as e: result.put(("Simulation", e)) return result.put(True) # Handle any other settings modified by the preset. settings = config.get("settings", {}) settings.update(override_settings) for keyword, value in settings.items(): run = mock.patch(keyword, value)(run) comm_thread = Thread(target=start_server_with_shared_data, args=(shared_data, result_bucket, bind_addr), daemon=True) sim_thread = Thread(target=run, args=(shared_data, result_bucket), daemon=True) comm_thread.start() sim_thread.start() try: with result_bucket.not_empty: while not result_bucket._qsize(): result_bucket.not_empty.wait(0.1) r = result_bucket.get() # Chuck it back on the queue so that other threads know we are quitting. result_bucket.put(r) if r is not True: print( f"An error occurred in the {r[0]} thread. Raising an error now..." ) time.sleep(1) raise r[1] except KeyboardInterrupt: pass