Branch data Line data Source code
1 : : // Copyright 2026 Garena Online Private Limited
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <algorithm>
16 : : #include <cmath>
17 : : #include <string>
18 : : #include <utility>
19 : : #include <vector>
20 : :
21 : : #include "envpool/minigrid/impl/minigrid_env.h"
22 : : #include "envpool/minigrid/impl/minigrid_task_utils.h"
23 : :
24 : : namespace minigrid {
25 : :
26 : 86 : EmptyTask::EmptyTask(int size, Pos agent_start_pos, int agent_start_dir,
27 : 86 : int max_steps, int agent_view_size)
28 : : : MiniGridTask("empty", max_steps, agent_view_size, true, 6),
29 : 86 : size_(size),
30 : 86 : agent_start_pos_(std::move(agent_start_pos)),
31 [ + - ]: 86 : agent_start_dir_(agent_start_dir) {
32 : 86 : } // NOLINT(whitespace/indent_namespace)
33 : :
34 : 99 : void EmptyTask::GenGrid() {
35 : 99 : ClearGrid(size_, size_);
36 : 99 : WallRect(0, 0, size_, size_);
37 [ + - ]: 99 : PutObj(WorldObj(kGoal, kGreen), size_ - 2, size_ - 2);
38 [ + + ]: 99 : goal_pos_ = {size_ - 2, size_ - 2};
39 [ + + ]: 99 : if (agent_start_pos_.first >= 0) {
40 : : agent_pos_ = agent_start_pos_;
41 : 60 : agent_dir_ = agent_start_dir_;
42 : : } else {
43 : 39 : PlaceAgent(1, 1, size_ - 2, size_ - 2, true);
44 : : }
45 : 99 : SetMission("get to the green goal square", 0);
46 : 99 : }
47 : :
48 : 64 : DoorKeyTask::DoorKeyTask(int size, int max_steps)
49 [ + - ]: 128 : : MiniGridTask("doorkey", max_steps, 7, false, 6), size_(size) {}
50 : :
51 : 64 : void DoorKeyTask::GenGrid() {
52 : 64 : ClearGrid(size_, size_);
53 : 64 : WallRect(0, 0, size_, size_);
54 [ + - ]: 64 : PutObj(WorldObj(kGoal, kGreen), size_ - 2, size_ - 2);
55 : 64 : goal_pos_ = {size_ - 2, size_ - 2};
56 : 64 : int split_idx = RandInt(2, size_ - 2);
57 : 64 : VertWall(split_idx, 0);
58 : 64 : PlaceAgent(0, 0, split_idx, size_, true);
59 : 64 : int door_idx = RandInt(1, size_ - 2);
60 [ + - + - ]: 128 : PutObj(MakeDoor(kYellow, true, false), split_idx, door_idx);
61 [ + - - + : 128 : PlaceObj(WorldObj(kKey, kYellow), 0, 0, split_idx, size_);
- - ]
62 : 64 : SetMission("use the key to open the door and then get to the goal", 0);
63 : 64 : }
64 : :
65 : 26 : DistShiftTask::DistShiftTask(int width, int height, Pos agent_start_pos,
66 : 26 : int agent_start_dir, int strip2_row, int max_steps)
67 : : : MiniGridTask("distshift", max_steps, 7, true, 6),
68 : 26 : agent_start_pos_(std::move(agent_start_pos)),
69 : 26 : agent_start_dir_(agent_start_dir),
70 [ + - ]: 26 : strip2_row_(strip2_row) {
71 : 26 : width_ = width;
72 : 26 : height_ = height;
73 : 26 : }
74 : :
75 : 40 : void DistShiftTask::GenGrid() {
76 : 40 : ClearGrid(width_, height_);
77 : 40 : WallRect(0, 0, width_, height_);
78 [ + - ]: 40 : PutObj(WorldObj(kGoal, kGreen), width_ - 2, 1);
79 : 40 : goal_pos_ = {width_ - 2, 1};
80 [ + + ]: 160 : for (int i = 0; i < width_ - 6; ++i) {
81 [ + - ]: 120 : PutObj(WorldObj(kLava), 3 + i, 1);
82 [ + - ]: 240 : PutObj(WorldObj(kLava), 3 + i, strip2_row_);
83 : : }
84 [ + - ]: 40 : if (agent_start_pos_.first >= 0) {
85 : : agent_pos_ = agent_start_pos_;
86 : 40 : agent_dir_ = agent_start_dir_;
87 : : } else {
88 : 0 : PlaceAgent();
89 : : }
90 : 40 : SetMission("get to the green goal square", 0);
91 : 40 : }
92 : :
93 : 39 : LavaGapTask::LavaGapTask(int size, Type obstacle_type, int max_steps)
94 : : : MiniGridTask("lavgap", max_steps, 7, false, 6),
95 : 39 : size_(size),
96 [ + - ]: 78 : obstacle_type_(obstacle_type) {} // NOLINT(whitespace/indent_namespace)
97 : :
98 : 59 : void LavaGapTask::GenGrid() {
99 : 59 : ClearGrid(size_, size_);
100 : 59 : WallRect(0, 0, size_, size_);
101 : : agent_pos_ = {1, 1};
102 : 59 : agent_dir_ = 0;
103 [ + - ]: 59 : goal_pos_ = {size_ - 2, size_ - 2};
104 [ + - ]: 59 : PutObj(WorldObj(kGoal, kGreen), goal_pos_.first, goal_pos_.second);
105 : 59 : Pos gap_pos{RandInt(2, size_ - 2), RandInt(1, size_ - 1)};
106 : 59 : VertWall(gap_pos.first, 1, size_ - 2, obstacle_type_,
107 : 59 : DefaultColor(obstacle_type_));
108 : 59 : SetEmpty(gap_pos.first, gap_pos.second);
109 [ - + ]: 59 : SetMission(obstacle_type_ == kLava
110 : : ? "avoid the lava and get to the green goal square"
111 : : : "find the opening and get to the green goal square",
112 : : 0);
113 : 59 : }
114 : :
115 : 104 : CrossingTask::CrossingTask(int size, int num_crossings, Type obstacle_type,
116 : 104 : int max_steps)
117 : : : MiniGridTask("crossing", max_steps, 7, false, 6),
118 : 104 : size_(size),
119 : 104 : num_crossings_(num_crossings),
120 [ + - ]: 208 : obstacle_type_(obstacle_type) {} // NOLINT(whitespace/indent_namespace)
121 : :
122 : 150 : void CrossingTask::GenGrid() {
123 [ - + - - ]: 150 : CHECK_EQ(size_ % 2, 1);
124 : 150 : ClearGrid(size_, size_);
125 : 150 : WallRect(0, 0, size_, size_);
126 : : agent_pos_ = {1, 1};
127 : 150 : agent_dir_ = 0;
128 [ + - ]: 150 : goal_pos_ = {size_ - 2, size_ - 2};
129 [ + - ]: 300 : PutObj(WorldObj(kGoal, kGreen), goal_pos_.first, goal_pos_.second);
130 : :
131 : 150 : std::vector<std::pair<bool, int>> rivers;
132 [ + + ]: 643 : for (int i = 2; i < size_ - 2; i += 2) {
133 [ + - ]: 493 : rivers.emplace_back(true, i);
134 [ + - ]: 493 : rivers.emplace_back(false, i);
135 : : }
136 : 150 : std::shuffle(rivers.begin(), rivers.end(), *gen_ref_);
137 [ + - ]: 150 : rivers.resize(num_crossings_);
138 : 150 : std::vector<int> rivers_v;
139 : 150 : std::vector<int> rivers_h;
140 [ + + ]: 580 : for (const auto& river : rivers) {
141 [ + + ]: 430 : if (river.first) {
142 [ + - ]: 187 : rivers_v.push_back(river.second);
143 : : } else {
144 [ + - ]: 243 : rivers_h.push_back(river.second);
145 : : }
146 : : }
147 : 150 : std::sort(rivers_v.begin(), rivers_v.end());
148 : 150 : std::sort(rivers_h.begin(), rivers_h.end());
149 [ + + ]: 393 : for (int y : rivers_h) {
150 [ + + ]: 2186 : for (int x = 1; x < size_ - 1; ++x) {
151 [ + - + - ]: 3886 : PutObj(WorldObj(obstacle_type_), x, y);
152 : : }
153 : : }
154 [ + + ]: 338 : for (int x : rivers_v) {
155 [ + + ]: 1683 : for (int y = 1; y < size_ - 1; ++y) {
156 [ + - + - ]: 2990 : PutObj(WorldObj(obstacle_type_), x, y);
157 : : }
158 : : }
159 : :
160 : : std::vector<bool> path;
161 [ + - ]: 150 : path.insert(path.end(), rivers_v.size(), true);
162 [ + - ]: 149 : path.insert(path.end(), rivers_h.size(), false);
163 : 150 : std::shuffle(path.begin(), path.end(), *gen_ref_);
164 : :
165 [ + - + - ]: 300 : std::vector<int> limits_v = {0};
166 : 150 : limits_v.insert(limits_v.end(), rivers_v.begin(), rivers_v.end());
167 [ + - ]: 150 : limits_v.push_back(size_ - 1);
168 [ + - + - ]: 150 : std::vector<int> limits_h = {0};
169 : 150 : limits_h.insert(limits_h.end(), rivers_h.begin(), rivers_h.end());
170 [ + - ]: 150 : limits_h.push_back(size_ - 1);
171 : : int room_i = 0;
172 : : int room_j = 0;
173 : 150 : for (bool is_horizontal_move : path) {
174 : : int x = 0;
175 : : int y = 0;
176 [ + + ]: 431 : if (is_horizontal_move) {
177 [ + - ]: 188 : x = limits_v[room_i + 1];
178 [ + - ]: 188 : y = RandInt(limits_h[room_j] + 1, limits_h[room_j + 1]);
179 : : room_i += 1;
180 : : } else {
181 [ + - ]: 243 : x = RandInt(limits_v[room_i] + 1, limits_v[room_i + 1]);
182 : 242 : y = limits_h[room_j + 1];
183 : : room_j += 1;
184 : : }
185 [ + - ]: 430 : SetEmpty(x, y);
186 : : }
187 [ + + + - ]: 352 : SetMission(obstacle_type_ == kLava
188 : : ? "avoid the lava and get to the green goal square"
189 : : : "find the opening and get to the green goal square",
190 : : 0);
191 : 150 : }
192 : :
193 : 86 : DynamicObstaclesTask::DynamicObstaclesTask(int size, Pos agent_start_pos,
194 : : int agent_start_dir, int n_obstacles,
195 : 86 : int max_steps)
196 : : : MiniGridTask("dynamic_obstacles", max_steps, 7, true, 2),
197 : 86 : size_(size),
198 : 86 : agent_start_pos_(std::move(agent_start_pos)),
199 : 86 : agent_start_dir_(agent_start_dir),
200 [ + - - + ]: 172 : n_obstacles_(n_obstacles <= size / 2 + 1 ? n_obstacles : size / 2) {
201 : 86 : } // NOLINT(whitespace/indent_namespace)
202 : :
203 : 614 : void DynamicObstaclesTask::GenGrid() {
204 : 614 : ClearGrid(size_, size_);
205 : 614 : WallRect(0, 0, size_, size_);
206 [ + - ]: 614 : PutObj(WorldObj(kGoal, kGreen), size_ - 2, size_ - 2);
207 [ + + ]: 614 : goal_pos_ = {size_ - 2, size_ - 2};
208 [ + + ]: 614 : if (agent_start_pos_.first >= 0) {
209 : : agent_pos_ = agent_start_pos_;
210 : 371 : agent_dir_ = agent_start_dir_;
211 : : } else {
212 : 243 : PlaceAgent();
213 : : }
214 : : obstacle_pos_.clear();
215 [ + + ]: 2611 : for (int i = 0; i < n_obstacles_; ++i) {
216 [ + - - + : 3994 : obstacle_pos_.push_back(PlaceObj(WorldObj(kBall, kBlue), 0, 0, width_,
- - ]
217 : 1997 : height_, RejectFn(), 100));
218 : : }
219 : 614 : SetMission("get to the green goal square", 0);
220 : 614 : }
221 : :
222 : 3163 : void DynamicObstaclesTask::BeforeStep(Act act, const WorldObj& pre_fwd) {
223 [ + + + + : 3163 : pre_front_blocked_ = act == kForward && pre_fwd.GetType() != kGoal &&
+ + ]
224 : : pre_fwd.GetType() != kEmpty;
225 : 3163 : std::vector<Pos> new_pos = obstacle_pos_;
226 [ + + ]: 14960 : for (std::size_t i = 0; i < obstacle_pos_.size(); ++i) {
227 : 11800 : Pos old_pos = obstacle_pos_[i];
228 [ - + ]: 11800 : int top_x = std::max(old_pos.first - 1, 0);
229 [ - + ]: 11800 : int top_y = std::max(old_pos.second - 1, 0);
230 [ - + ]: 11800 : int end_x = std::min(old_pos.first + 2, width_);
231 [ - + ]: 11800 : int end_y = std::min(old_pos.second + 2, height_);
232 [ + - ]: 23379 : for (int attempt = 0; attempt < 100; ++attempt) {
233 [ + - ]: 23379 : int x = RandInt(top_x, end_x);
234 [ + - ]: 23401 : int y = RandInt(top_y, end_y);
235 : : Pos pos{x, y};
236 [ + - + + : 46784 : if (GetCell(x, y).GetType() != kEmpty || pos == agent_pos_) {
+ + ]
237 : : continue;
238 : : }
239 [ + - ]: 11821 : PutObj(WorldObj(kBall, kBlue), x, y);
240 [ + - ]: 11814 : SetEmpty(old_pos.first, old_pos.second);
241 : : new_pos[i] = pos;
242 : : break;
243 : : }
244 : : }
245 [ + - ]: 3160 : obstacle_pos_ = new_pos;
246 : 3155 : }
247 : :
248 : 3160 : void DynamicObstaclesTask::AfterStep(Act act, const WorldObj& pre_fwd,
249 : : const Pos& fwd_pos,
250 : : const WorldObj& pre_carrying,
251 : : float* reward, bool* terminated) {
252 [ + + + + ]: 3160 : if (act == kForward && pre_front_blocked_) {
253 : 513 : *reward = -1.0f;
254 : 513 : *terminated = true;
255 : : }
256 : 3160 : }
257 : :
258 : 1224 : MiniGridDebugState DynamicObstaclesTask::DebugState() const {
259 : 1224 : MiniGridDebugState state = MiniGridTask::DebugState();
260 [ + - ]: 1224 : state.obstacle_positions.reserve(obstacle_pos_.size() * 2);
261 [ + + ]: 5712 : for (const Pos& pos : obstacle_pos_) {
262 [ + - ]: 4488 : state.obstacle_positions.push_back(pos.first);
263 [ + - ]: 4488 : state.obstacle_positions.push_back(pos.second);
264 : : }
265 : 1224 : return state;
266 : 0 : }
267 : :
268 : 47 : FetchTask::FetchTask(int size, int num_objs, int max_steps)
269 : : : MiniGridTask("fetch", max_steps, 7, true, 6),
270 : 47 : size_(size),
271 [ + - ]: 94 : num_objs_(num_objs) {} // NOLINT(whitespace/indent_namespace)
272 : :
273 : 65 : void FetchTask::GenGrid() {
274 : 65 : ClearGrid(size_, size_);
275 : 65 : HorzWall(0, 0);
276 : 65 : HorzWall(0, size_ - 1);
277 : 65 : VertWall(0, 0);
278 : 65 : VertWall(size_ - 1, 0);
279 : : std::vector<std::pair<Type, Color>> objs;
280 [ + + ]: 217 : while (static_cast<int>(objs.size()) < num_objs_) {
281 [ + - + - ]: 152 : Type type = RandElem(std::vector<Type>{kKey, kBall});
282 [ + - - + ]: 152 : Color color = RandColor();
283 [ + - - + : 304 : PlaceObj(WorldObj(type, color));
- - ]
284 [ + - ]: 152 : objs.emplace_back(type, color);
285 : : }
286 [ + - ]: 65 : PlaceAgent();
287 [ + - ]: 65 : int target_idx = RandInt(0, static_cast<int>(objs.size()));
288 [ + - ]: 65 : target_type_ = objs[target_idx].first;
289 : 65 : target_color_ = objs[target_idx].second;
290 [ + - ]: 65 : int syntax_idx = RandInt(0, 5);
291 [ + - ]: 65 : SetMission(MissionFetch(syntax_idx, target_color_, target_type_),
292 : 65 : syntax_idx * 12 + static_cast<int>(target_color_) * 2 +
293 [ + + ]: 65 : (target_type_ == kBall ? 1 : 0));
294 : 65 : }
295 : :
296 [ + + ]: 1832 : void FetchTask::AfterStep(Act act, const WorldObj& pre_fwd, const Pos& fwd_pos,
297 : : const WorldObj& pre_carrying, float* reward,
298 : : bool* terminated) {
299 [ + + ]: 1832 : if (carrying_.GetType() == kEmpty) {
300 : : return;
301 : : }
302 : 18 : *terminated = true;
303 [ + + ]: 18 : if (carrying_.GetType() == target_type_ &&
304 [ + + ]: 16 : carrying_.GetColor() == target_color_) {
305 : 14 : *reward = SuccessReward();
306 : : } else {
307 : 4 : *reward = 0.0f;
308 : : }
309 : : }
310 : :
311 : 39 : GoToDoorTask::GoToDoorTask(int size, int max_steps)
312 [ + - ]: 78 : : MiniGridTask("goto_door", max_steps, 7, true, 6), size_(size) {}
313 : :
314 : 480 : void GoToDoorTask::GenGrid() {
315 : 480 : ClearGrid(size_, size_);
316 : 481 : int active_width = RandInt(5, size_ + 1);
317 : 481 : int active_height = RandInt(5, size_ + 1);
318 : 481 : WallRect(0, 0, active_width, active_height);
319 : : std::vector<Pos> door_pos = {
320 : 481 : {RandInt(2, active_width - 2), 0},
321 : 481 : {RandInt(2, active_width - 2), active_height - 1},
322 : 481 : {0, RandInt(2, active_height - 2)},
323 : 481 : {active_width - 1, RandInt(2, active_height - 2)},
324 : 481 : };
325 : : std::vector<Color> door_colors;
326 [ + + ]: 3132 : while (static_cast<int>(door_colors.size()) <
327 : : static_cast<int>(door_pos.size())) {
328 [ + - + + ]: 2651 : Color color = RandColor();
329 [ + + ]: 2654 : if (std::find(door_colors.begin(), door_colors.end(), color) !=
330 : : door_colors.end()) {
331 : 732 : continue;
332 : : }
333 [ + - ]: 1922 : door_colors.push_back(color);
334 : : }
335 [ + + ]: 2404 : for (std::size_t i = 0; i < door_pos.size(); ++i) {
336 [ - + + - ]: 3846 : PutObj(MakeDoor(door_colors[i], false, false), door_pos[i].first,
337 : : door_pos[i].second);
338 : : }
339 [ + - ]: 481 : PlaceAgent(0, 0, active_width, active_height, true);
340 [ + - ]: 481 : int door_idx = RandInt(0, static_cast<int>(door_pos.size()));
341 [ + - ]: 481 : target_pos_ = door_pos[door_idx];
342 : 481 : target_type_ = kDoor;
343 : 481 : target_color_ = door_colors[door_idx];
344 [ + - ]: 481 : SetMission(MissionGoToDoor(target_color_), static_cast<int>(target_color_));
345 : 480 : }
346 : :
347 : 1397 : void GoToDoorTask::AfterStep(Act act, const WorldObj& pre_fwd,
348 : : const Pos& fwd_pos, const WorldObj& pre_carrying,
349 : : float* reward, bool* terminated) {
350 [ + + ]: 1397 : if (act == kToggle) {
351 : 232 : *terminated = true;
352 : 232 : return;
353 : : }
354 [ + + ]: 1165 : if (act == kDone) {
355 : : if (IsAdjacent(agent_pos_, target_pos_)) {
356 : 31 : *reward = SuccessReward();
357 : : }
358 : 211 : *terminated = true;
359 : : }
360 : : }
361 : :
362 : 26 : GoToObjectTask::GoToObjectTask(int size, int num_objs, int max_steps)
363 : : : MiniGridTask("goto_object", max_steps, 7, true, 6),
364 : 26 : size_(size),
365 [ + - ]: 52 : num_objs_(num_objs) {} // NOLINT(whitespace/indent_namespace)
366 : :
367 : 320 : void GoToObjectTask::GenGrid() {
368 : 320 : ClearGrid(size_, size_);
369 : 320 : WallRect(0, 0, size_, size_);
370 : : std::vector<std::pair<Type, Color>> objs;
371 : : std::vector<Pos> positions;
372 [ + + ]: 972 : while (static_cast<int>(objs.size()) < num_objs_) {
373 : : Type type =
374 [ + - + - ]: 652 : RandElem(std::vector<Type>(kObjectTypes.begin(), kObjectTypes.end()));
375 [ + - + + ]: 651 : Color color = RandColor();
376 [ + + ]: 651 : if (std::find(objs.begin(), objs.end(),
377 [ + + ]: 651 : std::pair<Type, Color>{type, color}) != objs.end()) {
378 : 12 : continue;
379 : : }
380 [ + - - + : 1279 : positions.push_back(PlaceObj(WorldObj(type, color)));
- - ]
381 [ + - ]: 640 : objs.emplace_back(type, color);
382 : : }
383 [ + - ]: 320 : PlaceAgent();
384 [ + - ]: 320 : int idx = RandInt(0, static_cast<int>(objs.size()));
385 [ + + + ]: 320 : target_pos_ = positions[idx];
386 : 320 : target_type_ = objs[idx].first;
387 : 320 : target_color_ = objs[idx].second;
388 : 320 : SetMission(
389 [ + - ]: 320 : MissionGoToObject(target_color_, target_type_),
390 [ + + + ]: 320 : static_cast<int>(target_color_) * 3 + MissionObjectIndex(target_type_));
391 : 320 : }
392 : :
393 : 934 : void GoToObjectTask::AfterStep(Act act, const WorldObj& pre_fwd,
394 : : const Pos& fwd_pos, const WorldObj& pre_carrying,
395 : : float* reward, bool* terminated) {
396 [ + + ]: 934 : if (act == kToggle) {
397 : 154 : *terminated = true;
398 : 154 : return;
399 : : }
400 [ + + ]: 780 : if (act == kDone) {
401 : : if (IsAdjacent(agent_pos_, target_pos_)) {
402 : 19 : *reward = SuccessReward();
403 : : }
404 : 140 : *terminated = true;
405 : : }
406 : : }
407 : :
408 : 34 : PutNearTask::PutNearTask(int size, int num_objs, int max_steps)
409 : : : MiniGridTask("put_near", max_steps, 7, true, 6),
410 : 34 : size_(size),
411 [ + - ]: 68 : num_objs_(num_objs) {} // NOLINT(whitespace/indent_namespace)
412 : :
413 : 70 : void PutNearTask::GenGrid() {
414 : 70 : ClearGrid(size_, size_);
415 : 69 : HorzWall(0, 0);
416 : 69 : HorzWall(0, size_ - 1);
417 : 69 : VertWall(0, 0);
418 : 70 : VertWall(size_ - 1, 0);
419 : : std::vector<std::pair<Type, Color>> objs;
420 : : std::vector<Pos> positions;
421 : 227 : auto near_existing = [&](const Pos& candidate) {
422 : 227 : return std::any_of(positions.begin(), positions.end(), [&](const Pos& pos) {
423 [ - - - - : 200 : return std::abs(pos.first - candidate.first) <= 1 &&
- - - - -
- + + +
+ ]
424 [ - - - - : 107 : std::abs(pos.second - candidate.second) <= 1;
- - - - -
- + + +
+ ]
425 : 227 : });
426 : : };
427 [ + + ]: 256 : while (static_cast<int>(objs.size()) < num_objs_) {
428 : : Type type =
429 [ + - + - ]: 186 : RandElem(std::vector<Type>(kObjectTypes.begin(), kObjectTypes.end()));
430 [ + - + + ]: 186 : Color color = RandColor();
431 [ + + ]: 186 : if (std::find(objs.begin(), objs.end(),
432 [ + + ]: 186 : std::pair<Type, Color>{type, color}) != objs.end()) {
433 : 10 : continue;
434 : : }
435 : : positions.push_back(
436 [ - + + - : 351 : PlaceObj(WorldObj(type, color), 0, 0, width_, height_, near_existing));
+ - - - ]
437 [ + - ]: 176 : objs.emplace_back(type, color);
438 : : }
439 [ + - ]: 70 : PlaceAgent();
440 [ + - ]: 70 : int move_idx = RandInt(0, static_cast<int>(objs.size()));
441 : 70 : move_pos_ = positions[move_idx];
442 : 70 : move_type_ = objs[move_idx].first;
443 : 70 : move_color_ = objs[move_idx].second;
444 : : int target_idx = move_idx;
445 [ + + ]: 212 : while (target_idx == move_idx) {
446 [ + - ]: 142 : target_idx = RandInt(0, static_cast<int>(objs.size()));
447 : : }
448 [ + + + ]: 70 : target_pos_ = positions[target_idx];
449 : 70 : target_type_ = objs[target_idx].first;
450 : 70 : target_color_ = objs[target_idx].second;
451 : 70 : SetMission(
452 [ + - ]: 70 : MissionPutNear(move_color_, move_type_, target_color_, target_type_),
453 [ + + + ]: 70 : ((static_cast<int>(move_color_) * 3 + MissionObjectIndex(move_type_)) *
454 : 70 : 18) +
455 [ + + + ]: 70 : (static_cast<int>(target_color_) * 3) +
456 : : MissionObjectIndex(target_type_));
457 : 69 : }
458 : :
459 : 1198 : void PutNearTask::AfterStep(Act act, const WorldObj& pre_fwd,
460 : : const Pos& fwd_pos, const WorldObj& pre_carrying,
461 : : float* reward, bool* terminated) {
462 [ + + + + ]: 1198 : if (act == kPickup && carrying_.GetType() != kEmpty &&
463 [ + + ]: 25 : (carrying_.GetType() != move_type_ ||
464 [ + + ]: 22 : carrying_.GetColor() != move_color_)) {
465 : 7 : *terminated = true;
466 : 7 : return;
467 : : }
468 [ + + + + ]: 1191 : if (act == kDrop && pre_carrying.GetType() != kEmpty) {
469 [ + + ]: 16 : if (GetCell(fwd_pos.first, fwd_pos.second) == pre_carrying &&
470 [ + + ]: 8 : std::abs(fwd_pos.first - target_pos_.first) <= 1 &&
471 [ + + ]: 7 : std::abs(fwd_pos.second - target_pos_.second) <= 1) {
472 : 4 : *reward = SuccessReward();
473 : : }
474 : 8 : *terminated = true;
475 : : }
476 : : }
477 : :
478 : 26 : RedBlueDoorTask::RedBlueDoorTask(int size, int max_steps)
479 [ + - ]: 52 : : MiniGridTask("red_blue_door", max_steps, 7, false, 6), size_(size) {}
480 : :
481 : 28 : void RedBlueDoorTask::GenGrid() {
482 : 28 : ClearGrid(2 * size_, size_);
483 : 28 : WallRect(0, 0, 2 * size_, size_);
484 : 28 : WallRect(size_ / 2, 0, size_, size_);
485 : 28 : PlaceAgent(size_ / 2, 0, size_, size_, true);
486 : 28 : red_door_pos_ = {size_ / 2, RandInt(1, size_ - 1)};
487 : 28 : blue_door_pos_ = {size_ / 2 + size_ - 1, RandInt(1, size_ - 1)};
488 [ + - ]: 28 : PutObj(MakeDoor(kRed, false, false), red_door_pos_.first,
489 : : red_door_pos_.second);
490 [ + - ]: 28 : PutObj(MakeDoor(kBlue, false, false), blue_door_pos_.first,
491 : : blue_door_pos_.second);
492 : 28 : SetMission("open the red door then the blue door", 0);
493 : 28 : }
494 : :
495 : 1225 : void RedBlueDoorTask::BeforeStep(Act act, const WorldObj& pre_fwd) {
496 [ - + ]: 1224 : red_open_before_ =
497 : 1225 : GetCell(red_door_pos_.first, red_door_pos_.second).GetDoorOpen();
498 [ - + ]: 1226 : blue_open_before_ =
499 : 1224 : GetCell(blue_door_pos_.first, blue_door_pos_.second).GetDoorOpen();
500 : 1226 : }
501 : :
502 : 1226 : void RedBlueDoorTask::AfterStep(Act act, const WorldObj& pre_fwd,
503 : : const Pos& fwd_pos,
504 : : const WorldObj& pre_carrying, float* reward,
505 : : bool* terminated) {
506 : : bool red_open_after =
507 : 1226 : GetCell(red_door_pos_.first, red_door_pos_.second).GetDoorOpen();
508 : : bool blue_open_after =
509 : 1225 : GetCell(blue_door_pos_.first, blue_door_pos_.second).GetDoorOpen();
510 [ + + ]: 1225 : if (blue_open_after) {
511 [ - + ]: 2 : if (red_open_before_) {
512 : 0 : *reward = SuccessReward();
513 : : }
514 : 2 : *terminated = true;
515 [ + + - + ]: 1223 : } else if (red_open_after && blue_open_before_) {
516 : 0 : *terminated = true;
517 : : }
518 : 1225 : }
519 : :
520 : 21 : LockedRoomTask::LockedRoomTask(int size, int max_steps)
521 [ + - ]: 42 : : MiniGridTask("locked_room", max_steps, 7, false, 6), size_(size) {}
522 : :
523 : 21 : void LockedRoomTask::GenGrid() {
524 : 21 : ClearGrid(size_, size_);
525 [ + + ]: 420 : for (int i = 0; i < size_; ++i) {
526 [ + - ]: 399 : PutObj(WorldObj(kWall, kGrey), i, 0);
527 [ + - ]: 798 : PutObj(WorldObj(kWall, kGrey), i, size_ - 1);
528 : : }
529 [ + + ]: 420 : for (int j = 0; j < size_; ++j) {
530 [ + - ]: 399 : PutObj(WorldObj(kWall, kGrey), 0, j);
531 [ + - ]: 798 : PutObj(WorldObj(kWall, kGrey), size_ - 1, j);
532 : : }
533 : 21 : int left_wall = size_ / 2 - 2;
534 : 21 : int right_wall = size_ / 2 + 2;
535 [ + + ]: 420 : for (int j = 0; j < size_; ++j) {
536 [ + - + - ]: 798 : PutObj(WorldObj(kWall, kGrey), left_wall, j);
537 [ + - ]: 798 : PutObj(WorldObj(kWall, kGrey), right_wall, j);
538 : : }
539 : : struct LockedRoomInfo {
540 : : Pos top;
541 : : Pos size;
542 : : Pos door_pos;
543 : : Color color{kRed};
544 : : bool locked{false};
545 : : };
546 : : std::vector<LockedRoomInfo> rooms;
547 [ + + ]: 84 : for (int n = 0; n < 3; ++n) {
548 : 63 : int j = n * (size_ / 3);
549 [ + + ]: 504 : for (int i = 0; i < left_wall; ++i) {
550 [ + - ]: 882 : PutObj(WorldObj(kWall, kGrey), i, j);
551 : : }
552 [ + + ]: 566 : for (int i = right_wall; i < size_; ++i) {
553 [ + - ]: 1006 : PutObj(WorldObj(kWall, kGrey), i, j);
554 : : }
555 : 63 : int room_w = left_wall + 1;
556 [ + - ]: 63 : int room_h = size_ / 3 + 1;
557 : 63 : rooms.emplace_back(
558 [ + - + - ]: 63 : LockedRoomInfo{{0, j}, {room_w, room_h}, {left_wall, j + 3}});
559 : 63 : rooms.emplace_back(
560 [ + - ]: 63 : LockedRoomInfo{{right_wall, j}, {room_w, room_h}, {right_wall, j + 3}});
561 : : }
562 [ + - ]: 21 : int locked_idx = RandInt(0, static_cast<int>(rooms.size()));
563 [ + - ]: 21 : rooms[locked_idx].locked = true;
564 : : goal_pos_ = {
565 : 21 : RandInt(rooms[locked_idx].top.first + 1,
566 [ + - ]: 21 : rooms[locked_idx].top.first + rooms[locked_idx].size.first - 1),
567 : 21 : RandInt(
568 : : rooms[locked_idx].top.second + 1,
569 [ + - ]: 21 : rooms[locked_idx].top.second + rooms[locked_idx].size.second - 1)};
570 [ + - ]: 21 : PutObj(WorldObj(kGoal, kGreen), goal_pos_.first, goal_pos_.second);
571 [ + - ]: 21 : std::vector<Color> colors(kColors.begin(), kColors.end());
572 [ + + ]: 147 : for (auto& room : rooms) {
573 [ + - ]: 126 : int idx = RandInt(0, static_cast<int>(colors.size()));
574 : 126 : room.color = colors[idx];
575 : : colors.erase(colors.begin() + idx);
576 [ - + + - ]: 252 : PutObj(MakeDoor(room.color, room.locked, false), room.door_pos.first,
577 : : room.door_pos.second);
578 : : }
579 : : int key_room_idx = locked_idx;
580 [ + + ]: 54 : while (key_room_idx == locked_idx) {
581 [ + - ]: 33 : key_room_idx = RandInt(0, static_cast<int>(rooms.size()));
582 : : }
583 : 21 : Pos key_pos{RandInt(rooms[key_room_idx].top.first + 1,
584 [ + - ]: 21 : rooms[key_room_idx].top.first +
585 [ + - ]: 21 : rooms[key_room_idx].size.first - 1),
586 : 21 : RandInt(rooms[key_room_idx].top.second + 1,
587 : 21 : rooms[key_room_idx].top.second +
588 [ + - ]: 21 : rooms[key_room_idx].size.second - 1)};
589 [ - + + - ]: 21 : PutObj(WorldObj(kKey, rooms[locked_idx].color), key_pos.first,
590 : : key_pos.second);
591 [ + - ]: 21 : PlaceAgent(left_wall, 0, right_wall - left_wall, size_, true);
592 : : SetMission(
593 [ + - ]: 21 : MissionLockedRoom(rooms[locked_idx].color, rooms[key_room_idx].color), 0);
594 : 21 : }
595 : :
596 : : } // namespace minigrid
|