plancraft 0.3.14__py3-none-any.whl → 0.3.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,23 @@
1
+ import copy
1
2
  import time
3
+ from collections import Counter
2
4
 
3
5
  import networkx as nx
4
6
 
5
- from plancraft.environment.recipes import RECIPES, BaseRecipe
7
+ from plancraft.environment.actions import (
8
+ MoveAction,
9
+ SmeltAction,
10
+ StopAction,
11
+ )
12
+ from plancraft.environment.recipes import (
13
+ RECIPES,
14
+ BaseRecipe,
15
+ ShapedRecipe,
16
+ ShapelessRecipe,
17
+ SmeltingRecipe,
18
+ id_to_item,
19
+ )
20
+ from plancraft.environment.items import all_data
6
21
 
7
22
  RECIPE_GRAPH = nx.DiGraph()
8
23
 
@@ -14,6 +29,14 @@ for item, recipes in RECIPES.items():
14
29
  RECIPE_GRAPH.add_edge(ingredient, recipe.result.item)
15
30
 
16
31
 
32
+ MAX_STACK_SIZE = {}
33
+ for data_item in all_data["items"]:
34
+ if data_item["stackable"]:
35
+ MAX_STACK_SIZE[data_item["type"]] = data_item["stackSize"]
36
+ else:
37
+ MAX_STACK_SIZE[data_item["type"]] = 1
38
+
39
+
17
40
  def get_ancestors(target: str):
18
41
  return list(nx.ancestors(RECIPE_GRAPH, source=target))
19
42
 
@@ -107,3 +130,370 @@ def optimal_planner(
107
130
 
108
131
  except TimeoutError:
109
132
  return None
133
+
134
+
135
+ def item_set_id_to_type(item_set_ids: set[int]):
136
+ return set(id_to_item(i) for i in item_set_ids)
137
+
138
+
139
+ def find_free_inventory_slot(
140
+ inventory: dict, from_slot: int, from_item_type=None, from_item_quantity=None
141
+ ) -> int:
142
+ # find a free slot in the inventory for the item in from_slot
143
+ if from_item_type is None:
144
+ from_item_type = inventory[from_slot]["type"]
145
+ if from_item_quantity is None:
146
+ from_item_quantity = inventory[from_slot]["quantity"]
147
+
148
+ empty_slots = set(range(10, 46)) - set(inventory.keys()) - set([from_slot])
149
+
150
+ type_to_slot = {}
151
+ slot_to_quantity = {}
152
+ for slot, item in inventory.items():
153
+ if slot == from_slot:
154
+ continue
155
+ item_type = item["type"]
156
+ if item_type not in type_to_slot:
157
+ type_to_slot[item_type] = [slot]
158
+ else:
159
+ type_to_slot[item_type].append(slot)
160
+
161
+ slot_to_quantity[slot] = item["quantity"]
162
+
163
+ assert from_item_type is not None, f"Item not found in slot {from_slot}"
164
+
165
+ # if there is a free slot with the same item type
166
+ if from_item_type in type_to_slot:
167
+ for slot in type_to_slot[from_item_type]:
168
+ if (
169
+ slot_to_quantity[slot] + from_item_quantity
170
+ <= MAX_STACK_SIZE[from_item_type]
171
+ ):
172
+ return slot
173
+ if len(empty_slots) > 0:
174
+ return empty_slots.pop()
175
+
176
+ raise ValueError("No free slot found")
177
+
178
+
179
+ def find_item_in_inventory(
180
+ target: str, inventory: dict, min_quantity_needed: set = set()
181
+ ) -> int:
182
+ for slot, item in inventory.items():
183
+ if item["type"] == target and item["quantity"] > 0:
184
+ # if we don't need to keep an item in the slot, we can use it
185
+ if slot not in min_quantity_needed:
186
+ return slot
187
+ # if we need to keep an item in the slot, we can only use it quantity>1
188
+ elif item["quantity"] > 1:
189
+ return slot
190
+
191
+
192
+ def get_inventory_counter(inventory: dict) -> Counter:
193
+ counter = Counter()
194
+ for slot, item in inventory.items():
195
+ if slot == 0:
196
+ continue
197
+ counter[item["type"]] += item["quantity"]
198
+ return counter
199
+
200
+
201
+ def get_crafting_slot_item(inventory: dict) -> dict:
202
+ for slot, item in inventory.items():
203
+ if slot == 0 and item["quantity"] > 0:
204
+ return item
205
+ return None
206
+
207
+
208
+ def update_inventory(
209
+ inventory: dict, slot_from: int, slot_to: int, quantity: int
210
+ ) -> dict:
211
+ """
212
+ decrements quantity of item in slot_from
213
+ NOTE: we don't care about incrementing the items in slot_to
214
+
215
+ """
216
+ new_inventory = dict(inventory)
217
+ from_item = new_inventory[slot_from]
218
+ if slot_to not in new_inventory:
219
+ new_inventory[slot_to] = {"type": from_item["type"], "quantity": quantity}
220
+ else:
221
+ new_inventory[slot_to]["quantity"] += quantity
222
+
223
+ new_inventory[slot_from]["quantity"] -= quantity
224
+ if new_inventory[slot_from]["quantity"] <= 0:
225
+ del new_inventory[slot_from]
226
+ return new_inventory
227
+
228
+
229
+ def get_plan(observation: dict):
230
+ # this simply recovering the target item to craft
231
+ inventory_counter = get_inventory_counter(observation["inventory"])
232
+ return optimal_planner(target=observation["target"], inventory=inventory_counter)
233
+
234
+
235
+ def decompose_subgoal(
236
+ current_inventory: dict, plan_recipe, new_inventory: dict[str, int]
237
+ ) -> list[str]:
238
+ """
239
+ For a given plan_recipe and inventory, output the list of action to craft recipe
240
+ """
241
+ subplan = []
242
+ new_inventory_counter = Counter(new_inventory)
243
+ current_inventory_counter = get_inventory_counter(current_inventory)
244
+ items_to_use_counter = current_inventory_counter - new_inventory_counter
245
+ new_items = new_inventory_counter - current_inventory_counter
246
+ assert len(new_items) == 1
247
+
248
+ # if plan_recipe is a smelting recipe
249
+ if isinstance(plan_recipe, SmeltingRecipe):
250
+ assert len(items_to_use_counter) == 1, "smelting only supports one item"
251
+ for item, quantity in items_to_use_counter.items():
252
+ from_slot = find_item_in_inventory(item, current_inventory)
253
+ out_item_type, out_item_quantity = (
254
+ plan_recipe.result.item,
255
+ plan_recipe.result.count,
256
+ )
257
+ # find a free slot in the inventory for the item that will be smelted
258
+ free_slot = find_free_inventory_slot(
259
+ current_inventory,
260
+ from_slot=from_slot,
261
+ from_item_type=out_item_type,
262
+ from_item_quantity=out_item_quantity,
263
+ )
264
+ action = SmeltAction(
265
+ slot_from=from_slot, slot_to=free_slot, quantity=quantity
266
+ )
267
+ subplan.append(str(action))
268
+
269
+ # update inventory to decrement quantity of item in from_slot and increment quantity of item in free_slot
270
+ current_inventory = dict(current_inventory)
271
+ if free_slot not in current_inventory:
272
+ current_inventory[free_slot] = {
273
+ "type": out_item_type,
274
+ "quantity": out_item_quantity,
275
+ }
276
+ else:
277
+ current_inventory[free_slot]["quantity"] += quantity
278
+
279
+ current_inventory[from_slot]["quantity"] -= quantity
280
+ if current_inventory[from_slot]["quantity"] <= 0:
281
+ del current_inventory[from_slot]
282
+
283
+ return subplan, current_inventory
284
+
285
+ elif isinstance(plan_recipe, ShapelessRecipe):
286
+ crafting_slot = 1
287
+ min_quantity_needed = set()
288
+ while crafting_slot < 10:
289
+ # if something is already in the crafting slot
290
+ if (
291
+ crafting_slot in current_inventory
292
+ and current_inventory[crafting_slot]["quantity"] > 0
293
+ ):
294
+ # check it is a desired item
295
+ crafting_slot_item = current_inventory[crafting_slot]["type"]
296
+ # if it is a desired item, skip it
297
+ if (
298
+ crafting_slot_item in items_to_use_counter
299
+ and items_to_use_counter[crafting_slot_item] > 0
300
+ ):
301
+ items_to_use_counter[crafting_slot_item] -= 1
302
+ if items_to_use_counter[crafting_slot_item] == 0:
303
+ del items_to_use_counter[crafting_slot_item]
304
+ min_quantity_needed.add(crafting_slot)
305
+ crafting_slot += 1
306
+ continue
307
+ # if it is not a desired item, move it to a free slot
308
+ else:
309
+ free_slot = find_free_inventory_slot(
310
+ current_inventory, from_slot=crafting_slot
311
+ )
312
+ action = MoveAction(
313
+ slot_from=crafting_slot,
314
+ slot_to=free_slot,
315
+ quantity=current_inventory[crafting_slot]["quantity"],
316
+ )
317
+ subplan.append(str(action))
318
+ current_inventory = update_inventory(
319
+ current_inventory,
320
+ crafting_slot,
321
+ free_slot,
322
+ current_inventory[crafting_slot]["quantity"],
323
+ )
324
+
325
+ # if there are still items to add
326
+ if len(items_to_use_counter) != 0:
327
+ item = next(iter(items_to_use_counter))
328
+ from_slot = find_item_in_inventory(
329
+ item, current_inventory, min_quantity_needed
330
+ )
331
+ action = MoveAction(
332
+ slot_from=from_slot, slot_to=crafting_slot, quantity=1
333
+ )
334
+ subplan.append(str(action))
335
+ current_inventory = update_inventory(
336
+ current_inventory, from_slot, crafting_slot, 1
337
+ )
338
+ items_to_use_counter[item] -= 1
339
+ if items_to_use_counter[item] == 0:
340
+ del items_to_use_counter[item]
341
+
342
+ # update state of inventory
343
+ crafting_slot += 1
344
+
345
+ # if plan_recipe is a shaped recipe
346
+ elif isinstance(plan_recipe, ShapedRecipe):
347
+ min_quantity_needed = set()
348
+ seen_kernel = set()
349
+ for i, row in enumerate(plan_recipe.kernel):
350
+ for j, item_set in enumerate(row):
351
+ inventory_position = (i * 3) + j + 1
352
+ seen_kernel.add(inventory_position)
353
+ valid_items = item_set_id_to_type(item_set)
354
+
355
+ # if the inventory position is needed to be empty
356
+ if (
357
+ valid_items == {None}
358
+ and inventory_position in current_inventory
359
+ and current_inventory[inventory_position]["quantity"] > 0
360
+ ):
361
+ free_slot = find_free_inventory_slot(
362
+ current_inventory, from_slot=inventory_position
363
+ )
364
+ action = MoveAction(
365
+ slot_from=inventory_position,
366
+ slot_to=free_slot,
367
+ quantity=current_inventory[inventory_position]["quantity"],
368
+ )
369
+ current_inventory = update_inventory(
370
+ current_inventory,
371
+ inventory_position,
372
+ free_slot,
373
+ current_inventory[inventory_position]["quantity"],
374
+ )
375
+ subplan.append(str(action))
376
+ continue
377
+
378
+ # if the inventory position is needed to be filled
379
+ added_item = False
380
+ for item in valid_items:
381
+ # check if item is already added
382
+ if added_item:
383
+ break
384
+
385
+ # if item is already in the correct position, skip
386
+ if (
387
+ inventory_position in current_inventory
388
+ and current_inventory[inventory_position]["type"] == item
389
+ ) and current_inventory[inventory_position]["quantity"] > 0:
390
+ min_quantity_needed.add(inventory_position)
391
+ # decrement the quantity of the items to use
392
+ items_to_use_counter[item] -= 1
393
+ if items_to_use_counter[item] == 0:
394
+ del items_to_use_counter[item]
395
+ break
396
+
397
+ if items_to_use_counter[item] > 0:
398
+ # check and remove any item in the inventory position
399
+ if (
400
+ inventory_position in current_inventory
401
+ and current_inventory[inventory_position]["quantity"] > 0
402
+ and current_inventory[inventory_position]["type"] != item
403
+ ):
404
+ free_slot = find_free_inventory_slot(
405
+ current_inventory, from_slot=inventory_position
406
+ )
407
+ action = MoveAction(
408
+ slot_from=inventory_position,
409
+ slot_to=free_slot,
410
+ quantity=current_inventory[inventory_position][
411
+ "quantity"
412
+ ],
413
+ )
414
+ current_inventory = update_inventory(
415
+ current_inventory,
416
+ inventory_position,
417
+ free_slot,
418
+ current_inventory[inventory_position]["quantity"],
419
+ )
420
+ subplan.append(str(action))
421
+
422
+ # move item to correct position
423
+ from_slot = find_item_in_inventory(
424
+ item, current_inventory, min_quantity_needed
425
+ )
426
+ action = MoveAction(
427
+ slot_from=from_slot,
428
+ slot_to=inventory_position,
429
+ quantity=1,
430
+ )
431
+ items_to_use_counter[item] -= 1
432
+ added_item = True
433
+ # update state of inventory
434
+ current_inventory = update_inventory(
435
+ current_inventory, from_slot, inventory_position, 1
436
+ )
437
+ subplan.append(str(action))
438
+
439
+ # ensure all other items are removed
440
+ leftover_kernel = set(range(1, 10)) - seen_kernel
441
+ for slot in leftover_kernel:
442
+ if slot in current_inventory and current_inventory[slot]["quantity"] > 0:
443
+ free_slot = find_free_inventory_slot(current_inventory, from_slot=slot)
444
+ action = MoveAction(
445
+ slot_from=slot,
446
+ slot_to=free_slot,
447
+ quantity=current_inventory[slot]["quantity"],
448
+ )
449
+ current_inventory = update_inventory(
450
+ current_inventory,
451
+ slot,
452
+ free_slot,
453
+ current_inventory[slot]["quantity"],
454
+ )
455
+ subplan.append(str(action))
456
+ else:
457
+ raise NotImplementedError(f"Recipe type {type(plan_recipe)} not supported")
458
+
459
+ # move crafted item to free slot
460
+ current_inventory[0] = {
461
+ "type": plan_recipe.result.item,
462
+ "quantity": plan_recipe.result.count,
463
+ }
464
+ free_slot = find_free_inventory_slot(current_inventory, from_slot=0)
465
+ subplan.append(
466
+ str(
467
+ MoveAction(
468
+ slot_from=0, slot_to=free_slot, quantity=plan_recipe.result.count
469
+ )
470
+ )
471
+ )
472
+ current_inventory = update_inventory(
473
+ current_inventory, 0, free_slot, plan_recipe.result.count
474
+ )
475
+ # decrement all quantities of items present in crafting slots
476
+ for i in range(1, 10):
477
+ if i in current_inventory:
478
+ current_inventory[i]["quantity"] -= 1
479
+ if current_inventory[i]["quantity"] <= 0:
480
+ del current_inventory[i]
481
+
482
+ return subplan, current_inventory
483
+
484
+
485
+ def get_subplans(observation: dict) -> tuple[list[list[str]], list]:
486
+ current_inventory = copy.deepcopy(observation["inventory"])
487
+ plan = get_plan(observation)
488
+ # get action
489
+ if plan is None or len(plan) == 0:
490
+ return [[str(StopAction())]], []
491
+ # plan_recipe, new_inventory = plan[0]
492
+ subplans = []
493
+ # Calculate the subplans for each step in the plan
494
+ for plan_recipe, new_inventory in plan:
495
+ subplan, current_inventory = decompose_subgoal(
496
+ current_inventory, plan_recipe, new_inventory
497
+ )
498
+ subplans.append(subplan)
499
+ return subplans, plan
@@ -5,17 +5,10 @@ from collections import Counter
5
5
  import numpy as np
6
6
  from loguru import logger
7
7
 
8
- from plancraft.environment.items import ALL_ITEMS, all_data
9
- from plancraft.environment.planner import get_ancestors, optimal_planner
8
+ from plancraft.environment.items import ALL_ITEMS
9
+ from plancraft.environment.planner import get_ancestors, optimal_planner, MAX_STACK_SIZE
10
10
  from plancraft.environment.recipes import RECIPES
11
11
 
12
- MAX_STACK_SIZE = {}
13
- for data_item in all_data["items"]:
14
- if data_item["stackable"]:
15
- MAX_STACK_SIZE[data_item["type"]] = data_item["stackSize"]
16
- else:
17
- MAX_STACK_SIZE[data_item["type"]] = 1
18
-
19
12
 
20
13
  def sample_distractors(
21
14
  exclude_set: set = None, num_distractors: int = 16
@@ -1,108 +1,17 @@
1
- import copy
2
- from collections import Counter
3
-
4
1
  import torch
5
2
 
6
3
  from plancraft.config import EvalConfig
7
- from plancraft.environment.actions import (
8
- MoveAction,
9
- SmeltAction,
10
- StopAction,
11
- )
12
- from plancraft.environment.planner import optimal_planner
13
- from plancraft.environment.recipes import (
14
- ShapedRecipe,
15
- ShapelessRecipe,
16
- SmeltingRecipe,
17
- id_to_item,
18
- )
19
- from plancraft.environment.sampler import MAX_STACK_SIZE
4
+ from plancraft.environment.planner import get_subplans
20
5
  from plancraft.models.base import PlancraftBaseModel
21
6
  from plancraft.models.bbox_model import IntegratedBoundingBoxModel
22
7
 
23
8
 
24
- def item_set_id_to_type(item_set_ids: set[int]):
25
- return set(id_to_item(i) for i in item_set_ids)
26
-
27
-
28
- def find_free_inventory_slot(inventory: dict, from_slot: int) -> int:
29
- # find a free slot in the inventory for the item in from_slot
30
- from_item_type = inventory[from_slot]["type"]
31
- from_item_quantity = inventory[from_slot]["quantity"]
32
-
33
- empty_slots = set(range(10, 46)) - set(inventory.keys()) - set([from_slot])
34
-
35
- type_to_slot = {}
36
- slot_to_quantity = {}
37
- for slot, item in inventory.items():
38
- if slot == from_slot:
39
- continue
40
- item_type = item["type"]
41
- if item_type not in type_to_slot:
42
- type_to_slot[item_type] = [slot]
43
- else:
44
- type_to_slot[item_type].append(slot)
45
-
46
- slot_to_quantity[slot] = item["quantity"]
47
-
48
- assert from_item_type is not None, f"Item not found in slot {from_slot}"
49
-
50
- # if there is a free slot with the same item type
51
- if from_item_type in type_to_slot:
52
- for slot in type_to_slot[from_item_type]:
53
- if (
54
- slot_to_quantity[slot] + from_item_quantity
55
- <= MAX_STACK_SIZE[from_item_type]
56
- ):
57
- return slot
58
- if len(empty_slots) > 0:
59
- return empty_slots.pop()
60
-
61
- raise ValueError("No free slot found")
62
-
63
-
64
- def find_item_in_inventory(target: str, inventory: dict) -> int:
65
- for slot, item in inventory.items():
66
- if item["type"] == target and item["quantity"] > 0:
67
- return slot
68
-
69
-
70
- def get_inventory_counter(inventory: dict) -> Counter:
71
- counter = Counter()
72
- for slot, item in inventory.items():
73
- if slot == 0:
74
- continue
75
- counter[item["type"]] += item["quantity"]
76
- return counter
77
-
78
-
79
- def get_crafting_slot_item(inventory: dict) -> dict:
80
- for slot, item in inventory.items():
81
- if slot == 0 and item["quantity"] > 0:
82
- return item
83
- return None
84
-
85
-
86
- def update_inventory(
87
- inventory: dict, slot_from: int, slot_to: int, quantity: int
88
- ) -> dict:
89
- """
90
- decrements quantity of item in slot_from
91
- NOTE: we don't care about incrementing the items in slot_to
92
-
93
- """
94
- new_inventory = dict(inventory)
95
- new_inventory[slot_from]["quantity"] -= quantity
96
- return new_inventory
97
-
98
-
99
9
  class OracleModel(PlancraftBaseModel):
100
10
  """
101
11
  Oracle model returns actions that solve the task optimally
102
12
  """
103
13
 
104
14
  def __init__(self, cfg: EvalConfig):
105
- self.plans = []
106
15
  self.subplans = []
107
16
  self.use_fasterrcnn = cfg.plancraft.use_fasterrcnn
108
17
 
@@ -117,118 +26,15 @@ class OracleModel(PlancraftBaseModel):
117
26
  self.bbox_model.cuda()
118
27
 
119
28
  def reset(self):
120
- self.plans = []
121
- self.subplans = []
122
-
123
- def get_plan(self, observation: dict):
124
- # this simply recovering the target item to craft
125
- inventory_counter = get_inventory_counter(observation["inventory"])
126
- return optimal_planner(
127
- target=observation["target"], inventory=inventory_counter
128
- )
129
-
130
- def get_next_action(self, observation: dict) -> MoveAction | SmeltAction:
131
- if len(self.subplans) > 0:
132
- return self.subplans.pop(0)
133
- if len(self.plans) == 0:
134
- raise ValueError("No more steps in plan")
135
-
136
- if self.bbox_model is not None:
137
- observed_inventory = self.bbox_model.get_inventory(
138
- observation["image"].copy()
139
- )
140
- else:
141
- observed_inventory = copy.deepcopy(observation["inventory"])
142
-
143
- # take item from crafting slot
144
- if slot_item := get_crafting_slot_item(observed_inventory):
145
- # move item from crafting slot to inventory
146
- free_slot = find_free_inventory_slot(observed_inventory, from_slot=0)
147
- return MoveAction(
148
- slot_from=0, slot_to=free_slot, quantity=slot_item["quantity"]
149
- )
150
-
151
- plan_recipe, new_inventory = self.plans.pop(0)
152
29
  self.subplans = []
153
- new_inventory_counter = Counter(new_inventory)
154
- current_inventory = observed_inventory
155
- current_inventory_counter = get_inventory_counter(current_inventory)
156
- items_to_use_counter = current_inventory_counter - new_inventory_counter
157
- new_items = new_inventory_counter - current_inventory_counter
158
- if not self.use_fasterrcnn:
159
- assert len(new_items) == 1
160
-
161
- if isinstance(plan_recipe, ShapelessRecipe):
162
- crafting_slot = 1
163
- # add each item to crafting slots
164
- for item, quantity in items_to_use_counter.items():
165
- n = 0
166
- while n < quantity:
167
- from_slot = find_item_in_inventory(item, current_inventory)
168
-
169
- # skip if from_slot is the crafting slot
170
- if from_slot == crafting_slot:
171
- crafting_slot += 1
172
- n += 1
173
- continue
174
-
175
- action = MoveAction(
176
- slot_from=from_slot, slot_to=crafting_slot, quantity=1
177
- )
178
- # update state of inventory
179
- current_inventory = update_inventory(
180
- current_inventory, from_slot, crafting_slot, 1
181
- )
182
- self.subplans.append(action)
183
- crafting_slot += 1
184
- n += 1
185
-
186
- # if plan_recipe is a smelting recipe
187
- elif isinstance(plan_recipe, SmeltingRecipe):
188
- assert len(items_to_use_counter) == 1, "smelting only supports one item"
189
- for item, quantity in items_to_use_counter.items():
190
- from_slot = find_item_in_inventory(item, current_inventory)
191
- free_slot = find_free_inventory_slot(
192
- current_inventory, from_slot=from_slot
193
- )
194
- action = SmeltAction(
195
- slot_from=from_slot, slot_to=free_slot, quantity=quantity
196
- )
197
- self.subplans.append(action)
198
-
199
- # if plan_recipe is a shaped recipe
200
- elif isinstance(plan_recipe, ShapedRecipe):
201
- for i, row in enumerate(plan_recipe.kernel):
202
- for j, item_set in enumerate(row):
203
- inventory_position = (i * 3) + j + 1
204
- valid_items = item_set_id_to_type(item_set)
205
- for item in valid_items:
206
- if items_to_use_counter[item] > 0:
207
- from_slot = find_item_in_inventory(item, current_inventory)
208
- action = MoveAction(
209
- slot_from=from_slot,
210
- slot_to=inventory_position,
211
- quantity=1,
212
- )
213
- items_to_use_counter[item] -= 1
214
- # update state of inventory
215
- current_inventory = update_inventory(
216
- current_inventory, from_slot, inventory_position, 1
217
- )
218
- self.subplans.append(action)
219
- break
220
- else:
221
- raise NotImplementedError(f"Recipe type {type(plan_recipe)} not supported")
222
-
223
- return self.subplans.pop(0)
224
30
 
225
31
  def step(self, observation: dict, **kwargs) -> str:
226
32
  # get action
227
- if len(self.plans) == 0:
228
- self.plans = self.get_plan(observation)
229
- if self.plans is None:
230
- self.plans = []
231
- return str(StopAction())
232
-
233
- action = self.get_next_action(observation)
234
- return str(action)
33
+ if len(self.subplans) == 0:
34
+ subplans, _ = get_subplans(observation)
35
+ # flatten subplans since they are nested for each subgoal
36
+ flattened_subplans = [item for sublist in subplans for item in sublist]
37
+ self.subplans = flattened_subplans
38
+
39
+ action = self.subplans.pop(0)
40
+ return action
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plancraft
3
- Version: 0.3.14
3
+ Version: 0.3.16
4
4
  Summary: Plancraft: an evaluation dataset for planning with LLM agents
5
5
  License: MIT License
6
6
 
@@ -14,10 +14,10 @@ plancraft/environment/__init__.py,sha256=XFsFny4lH195AwAmL-WeCaF9ZCMgc7IgXIwhQ8F
14
14
  plancraft/environment/actions.py,sha256=AQxFaK4YW53mPwhuPhHrDF9wENSVjPHSWk0v77I1thw,9460
15
15
  plancraft/environment/env.py,sha256=A4532st7JFBYBF_Nh0CEEi3ZTLJAeaB3t9PAIVSemj0,16390
16
16
  plancraft/environment/items.py,sha256=Z9rhSyVDEoHF1pxRvhyiT94tyQJaWHi3wUHVcamz82o,221
17
- plancraft/environment/planner.py,sha256=eJExz3OxSzurIEdH9LOtMwFH9ApqMQ3CokVhmbV6Px0,3953
17
+ plancraft/environment/planner.py,sha256=uIOJjIoyT_4pxeWeTKb8BkLJyKZG0-AMoEOkZs6Ua9A,19340
18
18
  plancraft/environment/prompts.py,sha256=8QXclX0ygpL02uZichE1AVkbdn_0HGteD5bzo0FZGOU,6947
19
19
  plancraft/environment/recipes.py,sha256=0vwzOU86eZmGN2EpZVSIvzxpx0AOBWNPxTtAOFBN2A0,19570
20
- plancraft/environment/sampler.py,sha256=lTSiGfmrew0G7ewOWtz6dtt58Mj0rAg6PW8BIbBegXA,7646
20
+ plancraft/environment/sampler.py,sha256=79hLpTU0ajvMPoBsvSe8tE88x31c8Vlczb3tJZJcau0,7441
21
21
  plancraft/environment/search.py,sha256=Dmdvj04kMvPlwvoWSc2261LTXV8RbMpS4FODV1YoZKs,1847
22
22
  plancraft/environment/assets/constants.json,sha256=kyOIOh82CTTMMGEIS60k5k6M-6fkEmYDoGAnvi3Zx5k,1379016
23
23
  plancraft/environment/assets/minecraft_font.ttf,sha256=AzoK9cgggXwjFPHtIO7uz-YaDrminl3nvB-VsaTvTAk,60992
@@ -1917,10 +1917,10 @@ plancraft/models/base.py,sha256=uhG1tRmsBerJzW8qHoLyLEYpveDv0co7AAhi4mSfyO4,661
1917
1917
  plancraft/models/bbox_model.py,sha256=3b1IEspoHiVUR6GOWjEbp4YoxRhGkzKt-eOiwaN8NXo,17091
1918
1918
  plancraft/models/dummy.py,sha256=856oEX6NquXSIIfQLTEFFeB8ib7VUUs5cB0TVHAiFvI,1248
1919
1919
  plancraft/models/generators.py,sha256=F76_iPiqxUjDIrQwF58tzM0bLM91OkZJ0sBqBuki5wY,13939
1920
- plancraft/models/oracle.py,sha256=jDCE6zVFvbwFpDzQZTkHIlRwMud1yMJ4LVIdfpt5ddU,8449
1920
+ plancraft/models/oracle.py,sha256=tMp9mTwD70T3qohj-LZhJFjHYWyiVHDh8gu27asVimI,1342
1921
1921
  plancraft/models/utils.py,sha256=E-sZohvolWgGbpHQKgAgkgIfUJoVnT5pMt6JP8xLHKg,4034
1922
1922
  plancraft/train/dataset.py,sha256=oFqEd4LG9oEQ-71teh0Wf7-jJbtybT2ZibfM2bBdBkM,5474
1923
- plancraft-0.3.14.dist-info/METADATA,sha256=2LWU4DAq1vYAlcWLU_c3AAbVkqoyHWRJ6EFiMCtF2jM,11148
1924
- plancraft-0.3.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1925
- plancraft-0.3.14.dist-info/licenses/LICENSE,sha256=YGR8ehDB4t-T-lOQKMfKNR-2zsOU7E3E5NA8t25HKE0,1070
1926
- plancraft-0.3.14.dist-info/RECORD,,
1923
+ plancraft-0.3.16.dist-info/METADATA,sha256=FIfCMBzCVuDWFCf5cPPKXLdm1EHbgKRpQ2eT5khTMN0,11148
1924
+ plancraft-0.3.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1925
+ plancraft-0.3.16.dist-info/licenses/LICENSE,sha256=YGR8ehDB4t-T-lOQKMfKNR-2zsOU7E3E5NA8t25HKE0,1070
1926
+ plancraft-0.3.16.dist-info/RECORD,,