82
82
83
83
84
84
class TerrainMetadata :
85
+ """
86
+ ## Description
87
+ This is metadata object handler for the BipedalWalker environment.
88
+
89
+ <!-- ## References -->
90
+
91
+ ## Credits
92
+ Created by Arthur Plautz Ventura
93
+
94
+ """
95
+
85
96
def __init__ (self , metadata : dict = {}):
86
- self ._states , self ._counters = [], [] # Control parameters
87
- self ._metadata = {0 : [], 1 : [], 2 : [], 3 : []} # Random values for terrain types
97
+ self ._states = [] # Control parameters
98
+ self ._metadata = {1 : [], 2 : [], 3 : []} # Random values for terrain types
99
+ self ._variations = True
100
+ self .__generate = False
88
101
89
102
if metadata :
90
103
self .__from_dict (metadata ) # Copy values from existing metadata
91
104
else :
92
105
self .__generate = True # New values should be generated
93
106
107
+ @property
108
+ def grass_variations (self ):
109
+ return self ._variations
110
+
111
+ def _pit_length (self , metadata = None ):
112
+ return 4
113
+
114
+ def _stairs_length (self , metadata ):
115
+ _ , stair_width , stair_steps = metadata
116
+ return stair_width * stair_steps
117
+
118
+ def _stump_length (self , metadata ):
119
+ return metadata
120
+
121
+ def get_obstacles_length (self ):
122
+ total_length = 0
123
+ state_length = {
124
+ 1 : self ._stump_length ,
125
+ 2 : self ._stairs_length ,
126
+ 3 : self ._pit_length ,
127
+ }
128
+
129
+ n_states = len (self ._states )
130
+ metadata = deepcopy (self ._metadata )
131
+ for state in self ._states :
132
+ length_map = state_length [state ]
133
+ total_length += length_map (metadata [state ].pop (0 ))
134
+ return total_length , n_states
135
+
94
136
def get_dict (self ):
95
137
return dict (
96
138
states = deepcopy (self ._states ),
97
- counters = deepcopy (self ._counters ),
98
139
metadata = deepcopy (self ._metadata ),
140
+ variations = self ._variations ,
99
141
)
100
142
101
143
def __from_dict (self , metadata : dict ):
102
- self ._states : list = deepcopy (metadata .get ("states" ))
103
- self ._counters : list = deepcopy (metadata .get ("counters" ))
104
- self ._metadata : list = deepcopy (metadata .get ("metadata" ))
105
- self .__generate = False
144
+ if metadata .get ("designed" , False ):
145
+ self ._variations = metadata .get ("variations" , True )
146
+ for state_obj in metadata .get ("states" , []):
147
+ state = state_obj ["state" ]
148
+ self ._states .append (state )
149
+ self ._metadata [state ].append (state_obj ["metadata" ])
150
+ else :
151
+ self ._states = metadata .get ("states" , self ._states )
152
+ self ._metadata = metadata .get ("metadata" , self ._metadata )
153
+ self ._variations = metadata .get ("variations" , self ._variations )
106
154
107
155
def mode (self ) -> bool :
108
156
return self .__generate
@@ -119,12 +167,6 @@ def get_state(self) -> int:
119
167
def add_state (self , state : int ):
120
168
self ._states .append (state )
121
169
122
- def get_counter (self ) -> int :
123
- return self ._counters .pop (0 )
124
-
125
- def add_counter (self , counter : int ):
126
- self ._counters .append (counter )
127
-
128
170
129
171
class ContactDetector (contactListener ):
130
172
def __init__ (self , env ):
@@ -334,6 +376,13 @@ def terrain_metadata(self):
334
376
335
377
def _generate_terrain (self , hardcore ):
336
378
generate = self ._terrain_metadata .mode ()
379
+ if not generate :
380
+ obstacles_length , n_obstacles = (
381
+ self ._terrain_metadata .get_obstacles_length ()
382
+ )
383
+ self .terrain_grass = (TERRAIN_LENGTH - obstacles_length ) // n_obstacles
384
+ else :
385
+ self .terrain_grass = TERRAIN_GRASS
337
386
338
387
GRASS , STUMP , STAIRS , PIT , _STATES_ = range (5 )
339
388
state = GRASS
@@ -352,13 +401,9 @@ def _generate_terrain(self, hardcore):
352
401
self .terrain_x .append (x )
353
402
354
403
if state == GRASS and not oneshot :
355
- if generate :
356
- velocity = 0.8 * velocity + 0.01 * np .sign (TERRAIN_HEIGHT - y )
357
- if i > TERRAIN_STARTPAD :
358
- velocity += self .np_random .uniform (- 1 , 1 ) / SCALE # 1
359
- self ._terrain_metadata .set_metadata (state = GRASS , value = velocity )
360
- else :
361
- velocity = self ._terrain_metadata .get_metadata (state = GRASS )
404
+ velocity = 0.8 * velocity + 0.01 * np .sign (TERRAIN_HEIGHT - y )
405
+ if self ._terrain_metadata .grass_variations and i > TERRAIN_STARTPAD :
406
+ velocity += self .np_random .uniform (- 1 , 1 ) / SCALE # 1
362
407
y += velocity
363
408
364
409
elif state == PIT and oneshot :
@@ -367,6 +412,8 @@ def _generate_terrain(self, hardcore):
367
412
self ._terrain_metadata .set_metadata (state = PIT , value = counter )
368
413
else :
369
414
counter = self ._terrain_metadata .get_metadata (state = PIT )
415
+ if not counter :
416
+ counter = self .np_random .integers (3 , 5 )
370
417
371
418
poly = [
372
419
(x , y ),
@@ -459,11 +506,7 @@ def _generate_terrain(self, hardcore):
459
506
self .terrain_y .append (y )
460
507
counter -= 1
461
508
if counter == 0 :
462
- if generate :
463
- counter = self .np_random .integers (TERRAIN_GRASS / 2 , TERRAIN_GRASS )
464
- self ._terrain_metadata .add_counter (counter )
465
- else :
466
- counter = self ._terrain_metadata .get_counter ()
509
+ counter = self .terrain_grass
467
510
468
511
if state == GRASS and hardcore :
469
512
if generate :
@@ -691,7 +734,7 @@ def step(self, action: np.ndarray):
691
734
if self .game_over or pos [0 ] < 0 :
692
735
reward = - 100
693
736
terminated = True
694
- if pos [0 ] > (TERRAIN_LENGTH - TERRAIN_GRASS ) * TERRAIN_STEP :
737
+ if pos [0 ] > (TERRAIN_LENGTH - self . terrain_grass ) * TERRAIN_STEP :
695
738
terminated = True
696
739
697
740
if self .render_mode == "human" :
0 commit comments