11import itertools
2+ from collections import defaultdict
23
34import crafter
45import gym
@@ -78,7 +79,7 @@ def rotation_matrix(v1, v2):
7879 return rotation_matrix
7980
8081
81- def describe_loc (ref , P ):
82+ def describe_loc_precise (ref , P ):
8283 """
8384 Describe the location of P relative to ref.
8485 Example: `1 step south and 4 steps west`
@@ -100,21 +101,45 @@ def distange_to_string(distance, direction):
100101 return " and " .join (desc ) if desc else "at your location"
101102
102103
104+ def describe_loc_old (ref , P ):
105+ desc = []
106+ if ref [1 ] > P [1 ]:
107+ desc .append ("north" )
108+ elif ref [1 ] < P [1 ]:
109+ desc .append ("south" )
110+ if ref [0 ] > P [0 ]:
111+ desc .append ("west" )
112+ elif ref [0 ] < P [0 ]:
113+ desc .append ("east" )
114+
115+ distance = abs (ref [1 ] - P [1 ]) + abs (ref [0 ] - P [0 ])
116+ distance_str = f"{ distance } step{ 's' if distance > 1 else '' } to your { '-' .join (desc )} "
117+
118+ return distance_str
119+
120+
103121def get_edge_items (semantic , item_idx ):
104122 item_mask = semantic == item_idx
105123 not_item_mask = semantic != item_idx
106124 item_edge = ndimage .binary_dilation (not_item_mask ) & item_mask
107125 return item_edge
108126
109127
110- def describe_env (info ):
128+ def describe_env (
129+ info ,
130+ unique_items = True ,
131+ precise_location = True ,
132+ skip_items = ["grass" , "sand" , "path" ],
133+ edge_only_items = ["water" ],
134+ ):
111135 assert info ["semantic" ][info ["player_pos" ][0 ], info ["player_pos" ][1 ]] == player_idx
112136 semantic = info ["semantic" ][
113137 info ["player_pos" ][0 ] - info ["view" ][0 ] // 2 : info ["player_pos" ][0 ] + info ["view" ][0 ] // 2 + 1 ,
114138 info ["player_pos" ][1 ] - info ["view" ][1 ] // 2 + 1 : info ["player_pos" ][1 ] + info ["view" ][1 ] // 2 ,
115139 ]
116140 center = np .array ([info ["view" ][0 ] // 2 , info ["view" ][1 ] // 2 - 1 ])
117141 result = ""
142+ describe_loc = describe_loc_precise if precise_location else describe_loc_old
118143 obj_info_list = []
119144
120145 facing = info ["player_facing" ]
@@ -127,17 +152,15 @@ def describe_env(info):
127152 target_item = id_to_item [target_id ]
128153
129154 # skip grass, sand or path so obs here, since we are not displaying them
130- if target_id in [id_to_item .index (o ) for o in [ "grass" , "sand" , "path" ] ]:
155+ if target_id in [id_to_item .index (o ) for o in skip_items ]:
131156 target_item = "nothing"
132157
133158 obs = "You face {} at your front." .format (target_item )
134159 else :
135160 obs = "You face nothing at your front."
136161
137162 # Edge detection
138- edge_only_items = ["water" ]
139163 edge_masks = {}
140-
141164 for item_name in edge_only_items :
142165 item_idx = id_to_item .index (item_name )
143166 edge_masks [item_idx ] = get_edge_items (semantic , item_idx )
@@ -153,11 +176,26 @@ def describe_env(info):
153176 continue
154177
155178 # skip grass, sand or path so obs is not too long
156- if idx in [id_to_item .index (o ) for o in [ "grass" , "sand" , "path" ] ]:
179+ if idx in [id_to_item .index (o ) for o in skip_items ]:
157180 continue
158181
159182 obj_info_list .append ((id_to_item [idx ], describe_loc (np .array ([0 , 0 ]), np .array ([i , j ]) - center )))
160183
184+ # filter out items, so we only display closest item of each type
185+ if unique_items :
186+ closest_obj_info_list = defaultdict (str )
187+ for item_name , loc in obj_info_list :
188+ loc_dist = int (loc .split (" " )[0 ])
189+ current_dist = (
190+ int (closest_obj_info_list [item_name ].split (" " )[0 ])
191+ if closest_obj_info_list [item_name ]
192+ else float ("inf" )
193+ )
194+
195+ if current_dist > loc_dist :
196+ closest_obj_info_list [item_name ] = loc
197+ obj_info_list = [(name , loc ) for name , loc in closest_obj_info_list .items ()]
198+
161199 if len (obj_info_list ) > 0 :
162200 status_str = "You see:\n {}" .format ("\n " .join (["- {} {}" .format (name , loc ) for name , loc in obj_info_list ]))
163201 else :
@@ -192,13 +230,25 @@ def describe_status(info):
192230 return ""
193231
194232
195- def describe_frame (info ):
233+ def describe_frame (
234+ info ,
235+ unique_items = True ,
236+ precise_location = True ,
237+ skip_items = ["grass" , "sand" , "path" ],
238+ edge_only_items = ["water" ],
239+ ):
196240 try :
197241 result = ""
198242
199243 result += describe_status (info )
200244 result += "\n \n "
201- result += describe_env (info )
245+ result += describe_env (
246+ info ,
247+ unique_items = unique_items ,
248+ precise_location = precise_location ,
249+ skip_items = skip_items ,
250+ edge_only_items = edge_only_items ,
251+ )
202252 result += "\n \n "
203253
204254 return result .strip (), describe_inventory (info )
@@ -216,6 +266,10 @@ def __init__(
216266 env ,
217267 task = "" ,
218268 max_episode_steps = 2 ,
269+ unique_items = True ,
270+ precise_location = True ,
271+ skip_items = ["grass" , "sand" , "path" ],
272+ edge_only_items = ["water" ],
219273 ):
220274 super ().__init__ (env )
221275 self .score_tracker = 0
@@ -224,6 +278,11 @@ def __init__(
224278 self .max_steps = max_episode_steps
225279 self .achievements = None
226280
281+ self .unique_items = unique_items
282+ self .precise_location = precise_location
283+ self .skip_items = skip_items
284+ self .edge_only_items = edge_only_items
285+
227286 def get_text_action (self , action ):
228287 return self .language_action_space ._values [action ]
229288
@@ -257,7 +316,13 @@ def step(self, action):
257316
258317 def process_obs (self , obs , info ):
259318 img = Image .fromarray (self .env .render ()).convert ("RGB" )
260- long_term_context , short_term_context = describe_frame (info )
319+ long_term_context , short_term_context = describe_frame (
320+ info ,
321+ unique_items = self .unique_items ,
322+ precise_location = self .precise_location ,
323+ skip_items = self .skip_items ,
324+ edge_only_items = self .edge_only_items ,
325+ )
261326
262327 return {
263328 "text" : {
0 commit comments