Select adjacent crops first
This commit is contained in:
@@ -280,4 +280,5 @@ class JobStates(LegacyJobStates):
|
||||
self.g.path = []
|
||||
self.g.look_at = None
|
||||
self.gather_crop_states.state = self.gather_crop_states.idle
|
||||
self.gather_crop_states.active_section_anchor = None
|
||||
self.state = self.idle
|
||||
|
||||
@@ -23,6 +23,61 @@ class GatherCropStates:
|
||||
def init(self):
|
||||
self.state = self.find_new_crop
|
||||
|
||||
def _select_crop(self, candidates, crop_types, center):
|
||||
"""Stay with a connected same-species patch, nearest patch first."""
|
||||
adjacent_offsets = ((1, 0, 0), (-1, 0, 0),
|
||||
(0, 0, 1), (0, 0, -1))
|
||||
remaining = set(crop_types)
|
||||
component_for = {}
|
||||
component_sizes = {}
|
||||
component_id = 0
|
||||
|
||||
while remaining:
|
||||
seed = remaining.pop()
|
||||
species = crop_types[seed]
|
||||
stack = [seed]
|
||||
component = [seed]
|
||||
component_for[seed] = component_id
|
||||
while stack:
|
||||
x, y, z = stack.pop()
|
||||
for dx, dy, dz in adjacent_offsets:
|
||||
adjacent = (x + dx, y + dy, z + dz)
|
||||
if (adjacent in remaining and
|
||||
crop_types[adjacent] == species):
|
||||
remaining.remove(adjacent)
|
||||
component_for[adjacent] = component_id
|
||||
component.append(adjacent)
|
||||
stack.append(adjacent)
|
||||
component_sizes[component_id] = len(component)
|
||||
component_id += 1
|
||||
|
||||
eligible = [position for position in candidates
|
||||
if position not in self.bad_crops and
|
||||
position in component_for]
|
||||
if not eligible:
|
||||
return None, 0
|
||||
|
||||
active_component = component_for.get(self.active_section_anchor)
|
||||
active_candidates = [position for position in eligible
|
||||
if component_for[position] == active_component]
|
||||
if active_candidates:
|
||||
section_candidates = active_candidates
|
||||
else:
|
||||
# Begin with the nearest available patch. Once selected, keep its
|
||||
# connected component active until no mature crops remain there.
|
||||
first_crop = min(eligible, key=lambda position: (
|
||||
utils.phyp(center, position), position))
|
||||
selected_component = component_for[first_crop]
|
||||
section_candidates = [
|
||||
position for position in eligible
|
||||
if component_for[position] == selected_component
|
||||
]
|
||||
|
||||
crop = min(section_candidates, key=lambda position: (
|
||||
utils.phyp(center, position), position))
|
||||
self.active_section_anchor = crop
|
||||
return crop, component_sizes[component_for[crop]]
|
||||
|
||||
def find_new_crop(self):
|
||||
print('Finding new crop...')
|
||||
w = self.g.world
|
||||
@@ -36,17 +91,23 @@ class GatherCropStates:
|
||||
]
|
||||
|
||||
candidates = w.find_blocks_indexed(p, mature_crops, 50)
|
||||
crop_ids = (blocks.WHEAT_IDS | blocks.POTATO_IDS |
|
||||
blocks.CARROT_IDS | blocks.BEETROOT_IDS)
|
||||
crop_positions = w.find_blocks_indexed(p, crop_ids, 50)
|
||||
crop_types = {
|
||||
position: blocks.BLOCKS.get(w.block_at(*position))
|
||||
for position in crop_positions
|
||||
}
|
||||
crop, section_size = self._select_crop(candidates, crop_types, p)
|
||||
|
||||
for crop in candidates:
|
||||
if crop not in self.bad_crops:
|
||||
break
|
||||
else: # for
|
||||
if crop is None:
|
||||
print('No good crops left; retrying after a short wait.')
|
||||
self.retry_after = time.monotonic() + 15.0
|
||||
self.state = self.wait_for_crops
|
||||
return
|
||||
|
||||
print('Found crop:', crop)
|
||||
print('Found crop:', crop,
|
||||
'(same-species section size={})'.format(section_size))
|
||||
self.crop = crop
|
||||
self.type_id = w.block_at(*crop)
|
||||
self.state = self.nav_to_crop
|
||||
@@ -178,6 +239,7 @@ class GatherCropStates:
|
||||
self.target_seed = None
|
||||
self.seed_deadline = None
|
||||
self.seed_wait_logged = False
|
||||
self.active_section_anchor = None
|
||||
self.retry_after = 0.0
|
||||
self.bad_crops = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user