Balance crop section maturity and distance
This commit is contained in:
+40
-12
@@ -18,6 +18,7 @@ from mosfet.info import mobs
|
|||||||
|
|
||||||
class GatherCropStates:
|
class GatherCropStates:
|
||||||
CROPS_PER_BATCH = 16
|
CROPS_PER_BATCH = 16
|
||||||
|
SECTION_MATURITY_WEIGHT = 2.0
|
||||||
|
|
||||||
def idle(self):
|
def idle(self):
|
||||||
return None
|
return None
|
||||||
@@ -57,28 +58,50 @@ class GatherCropStates:
|
|||||||
if position not in self.bad_crops and
|
if position not in self.bad_crops and
|
||||||
position in component_for]
|
position in component_for]
|
||||||
if not eligible:
|
if not eligible:
|
||||||
|
self.active_section_maturity = (0, 0)
|
||||||
return None, 0
|
return None, 0
|
||||||
|
|
||||||
|
mature_by_component = {}
|
||||||
|
candidates_by_component = {}
|
||||||
|
for position in eligible:
|
||||||
|
component = component_for[position]
|
||||||
|
mature_by_component[component] = (
|
||||||
|
mature_by_component.get(component, 0) + 1)
|
||||||
|
candidates_by_component.setdefault(component, []).append(position)
|
||||||
|
|
||||||
active_component = component_for.get(self.active_section_anchor)
|
active_component = component_for.get(self.active_section_anchor)
|
||||||
active_candidates = [position for position in eligible
|
active_candidates = candidates_by_component.get(active_component, [])
|
||||||
if component_for[position] == active_component]
|
|
||||||
if active_candidates:
|
if active_candidates:
|
||||||
section_candidates = active_candidates
|
section_candidates = active_candidates
|
||||||
|
selected_component = active_component
|
||||||
else:
|
else:
|
||||||
# Begin with the nearest available patch. Once selected, keep its
|
# Favor a nearby section if maturity is similar, but allow a
|
||||||
# connected component active until no mature crops remain there.
|
# farther, substantially more-mature section to win. Once chosen,
|
||||||
first_crop = min(eligible, key=lambda position: (
|
# keep working that connected component until it has no mature
|
||||||
|
# crops left, matching the existing patch-stability behavior.
|
||||||
|
ranked_sections = []
|
||||||
|
for component, positions in candidates_by_component.items():
|
||||||
|
nearest_crop = min(positions, key=lambda position: (
|
||||||
utils.phyp(center, position), position))
|
utils.phyp(center, position), position))
|
||||||
selected_component = component_for[first_crop]
|
distance = utils.phyp(center, nearest_crop)
|
||||||
section_candidates = [
|
maturity = (mature_by_component[component] /
|
||||||
position for position in eligible
|
component_sizes[component])
|
||||||
if component_for[position] == selected_component
|
score = distance / (
|
||||||
]
|
1.0 + self.SECTION_MATURITY_WEIGHT * maturity)
|
||||||
|
ranked_sections.append((
|
||||||
|
score, distance, -mature_by_component[component],
|
||||||
|
nearest_crop, component,
|
||||||
|
))
|
||||||
|
selected_component = min(ranked_sections)[-1]
|
||||||
|
section_candidates = candidates_by_component[selected_component]
|
||||||
|
|
||||||
crop = min(section_candidates, key=lambda position: (
|
crop = min(section_candidates, key=lambda position: (
|
||||||
utils.phyp(center, position), position))
|
utils.phyp(center, position), position))
|
||||||
|
section_size = component_sizes[selected_component]
|
||||||
self.active_section_anchor = crop
|
self.active_section_anchor = crop
|
||||||
return crop, component_sizes[component_for[crop]]
|
self.active_section_maturity = (
|
||||||
|
mature_by_component[selected_component], section_size)
|
||||||
|
return crop, section_size
|
||||||
|
|
||||||
def find_new_crop(self):
|
def find_new_crop(self):
|
||||||
print('Finding new crop...')
|
print('Finding new crop...')
|
||||||
@@ -111,8 +134,12 @@ class GatherCropStates:
|
|||||||
self.state = self.cleanup
|
self.state = self.cleanup
|
||||||
return
|
return
|
||||||
|
|
||||||
|
mature_count, total_count = self.active_section_maturity
|
||||||
|
maturity_percent = (100 * mature_count / total_count
|
||||||
|
if total_count else 0)
|
||||||
print('Found crop:', crop,
|
print('Found crop:', crop,
|
||||||
'(same-species section size={})'.format(section_size))
|
'(same-species section: {}/{} mature, {:.0f}%)'.format(
|
||||||
|
mature_count, total_count, maturity_percent))
|
||||||
self.crop = crop
|
self.crop = crop
|
||||||
self.type_id = w.block_at(*crop)
|
self.type_id = w.block_at(*crop)
|
||||||
self.state = self.nav_to_crop
|
self.state = self.nav_to_crop
|
||||||
@@ -248,6 +275,7 @@ class GatherCropStates:
|
|||||||
self.seed_deadline = None
|
self.seed_deadline = None
|
||||||
self.seed_wait_logged = False
|
self.seed_wait_logged = False
|
||||||
self.active_section_anchor = None
|
self.active_section_anchor = None
|
||||||
|
self.active_section_maturity = (0, 0)
|
||||||
self.bad_crops = []
|
self.bad_crops = []
|
||||||
self.completed_crops = 0
|
self.completed_crops = 0
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,26 @@ class TestCropSectionPriority(unittest.TestCase):
|
|||||||
self.assertEqual(next_patch, carrot_a)
|
self.assertEqual(next_patch, carrot_a)
|
||||||
self.assertEqual(next_patch_size, 4)
|
self.assertEqual(next_patch_size, 4)
|
||||||
|
|
||||||
|
def test_farther_section_wins_when_much_more_mature(self):
|
||||||
|
near_patch = {
|
||||||
|
(3, 64, 0), (2, 64, 0), (1, 64, 0), (0, 64, 0),
|
||||||
|
(3, 64, 1), (2, 64, 1), (1, 64, 1), (0, 64, 1),
|
||||||
|
(3, 64, 2), (2, 64, 2),
|
||||||
|
}
|
||||||
|
near_mature = (3, 64, 0)
|
||||||
|
far_patch = {
|
||||||
|
(4, 64, 0), (5, 64, 0), (4, 64, 1), (5, 64, 1),
|
||||||
|
}
|
||||||
|
crop_types = {position: 'wheat' for position in near_patch}
|
||||||
|
crop_types.update({position: 'carrots' for position in far_patch})
|
||||||
|
|
||||||
|
crop, size = self.job._select_crop(
|
||||||
|
[near_mature, *far_patch], crop_types, (0, 64, 0))
|
||||||
|
|
||||||
|
self.assertEqual(crop, (4, 64, 0))
|
||||||
|
self.assertEqual(size, len(far_patch))
|
||||||
|
self.assertEqual(self.job.active_section_maturity, (4, 4))
|
||||||
|
|
||||||
def test_unripe_same_species_blocks_keep_patch_connected(self):
|
def test_unripe_same_species_blocks_keep_patch_connected(self):
|
||||||
mature = (0, 64, 0)
|
mature = (0, 64, 0)
|
||||||
replanted = (1, 64, 0)
|
replanted = (1, 64, 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user