File size: 6,060 Bytes
09a6f7f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
 * @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<void>}
     */
    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();
    }
}