/** * @classdesc Class that handles the simulation. */ class Game { /** * @constructor * @param agents {{morphologies: Array, policies: Array, positions: Array}} - Morphologies, policies and positions of the agents * @param cppn_input_vector {Array} - 3-dimensional array that encodes the CPPN * @param water_level {number} * @param creepers_width {number} * @param creepers_height {number} * @param creepers_spacing {number} * @param smoothing {number} * @param creepers_type {boolean} * @param ground {Array} - List of points {x, y} composing the ground * @param ceiling {Array} - List of points {x, y} composing the ceiling * @param align_terrain {Object} */ constructor(agents, cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type, ground, ceiling, align_terrain) { this.run_fps = 60; this.obs = []; this.rewards = []; this.initWorld(agents, cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type, ground, ceiling, align_terrain); this.running = false; } /** * Initializes the environment. * @param agents {{morphologies: Array, policies: Array, positions: Array}} - Morphologies, policies and positions of the agents * @param cppn_input_vector {Array} - 3-dimensional array that encodes the CPPN * @param water_level {number} * @param creepers_width {number} * @param creepers_height {number} * @param creepers_spacing {number} * @param smoothing {number} * @param creepers_type {boolean} * @param ground {Array} - List of points {x, y} composing the ground * @param ceiling {Array} - List of points {x, y} composing the ceiling * @param align_terrain {Object} */ initWorld(agents, cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type, ground, ceiling, align_terrain) { this.env = new MultiAgentsContinuousParkour( agents, 3, smoothing, 200, 90, 20, creepers_type, ground, ceiling, align_terrain); this.env.set_environment(cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type); let step_rets = this.env.reset(); this.obs.push([...step_rets.map(e => e[0])]); this.rewards.push([...step_rets.map(e => e[1])]); } /** * Pauses the simulation. */ pause(){ clearInterval(this.runtime); this.running = false; } /** * Runs the simulation. * @returns {Promise} */ async run(){ // Loads the policy for each agent before launching the simulation for(let agent of window.game.env.agents){ if(agent.policy.path != null){ agent.model = await tf.loadGraphModel(agent.policy.path + '/model.json'); } else{ agent.model = null; } } // Creates a repeated interval over time this.runtime = setInterval(() => { this.play(); }, 1000 / this.run_fps); this.running = true; } /** * * @param agents {{morphologies: Array, policies: Array, positions: Array}} - Morphologies, policies and positions of the agents * @param cppn_input_vector {Array} - 3-dimensional array that encodes the CPPN * @param water_level {number} * @param creepers_width {number} * @param creepers_height {number} * @param creepers_spacing {number} * @param smoothing {number} * @param creepers_type {boolean} * @param ground {Array} - List of points {x, y} composing the ground * @param ceiling {Array} - List of points {x, y} composing the ceiling * @param align_terrain {Object} */ reset(agents, cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type, ground, ceiling, align_terrain){ this.pause(); let zoom = window.game.env.zoom; let scroll = [...window.game.env.scroll]; this.initWorld(agents, cppn_input_vector, water_level, creepers_width, creepers_height, creepers_spacing, smoothing, creepers_type, ground, ceiling, align_terrain); // Keeps the previous zoom and scroll window.game.env.set_zoom(zoom); window.game.env.set_scroll(null, scroll[0], scroll[1]); this.env.render(); } /** * Plays one simulation step. */ play() { // Gets the actions to execute for each agent for(let agent of window.game.env.agents){ let state = this.obs[this.obs.length - 1][agent.id]; // Generates the actions thanks to the agent's policy model if(agent.model != null){ let envState = tf.tensor(state,[1, state.length]); let inputs = { "Placeholder_1:0": envState }; let output = 'main/mul:0' agent.actions = agent.model.execute(inputs, output).arraySync()[0]; } // Generates random actions else /*if(agent.policy.name == "random")*/{ agent.actions = Array.from({length: agent.agent_body.get_action_size()}, () => Math.random() * 2 - 1); } // Generates motionless actions /*else{ agent.actions = Array.from({length: agent.agent_body.get_action_size()}, () => 0); }*/ } // Runs one step and stores the resulted states for each agent let step_rets = this.env.step(); this.obs.push([...step_rets.map(e => e[0])]); this.rewards.push([...step_rets.map(e => e[1])]); this.env.render(); } }