Skip to content

Instantly share code, notes, and snippets.

@sarumaj
Last active October 26, 2025 22:29
Show Gist options
  • Select an option

  • Save sarumaj/3ee162cf2b4c95155da0b5e0534a0820 to your computer and use it in GitHub Desktop.

Select an option

Save sarumaj/3ee162cf2b4c95155da0b5e0534a0820 to your computer and use it in GitHub Desktop.
## CONST
WATER_THRESHOLD = 0.75
MIN_WATER_ITEMS = 100
MIN_POWER_LEVEL = 100000
MIN_FERTILIZER = 100
MIN_ITEM_THRESHOLD = 2500000000
HAY_OVERDUE_MARGIN = 1.2
REVERSE_CACTI_SORT = False
MIN_MAZE_PROBABILITY = 0.0
MAX_MAZE_PROBABILITY = 0.5
PLANTS_REQUIRING_SOIL = [
Entities.Carrot, Entities.Pumpkin,
Entities.Cactus, Entities.Sunflower
]
DRONE_HATS = [
Hats.Brown_Hat, Hats.Carrot_Hat, Hats.Gold_Hat,
Hats.Gray_Hat, Hats.Green_Hat, Hats.Pumpkin_Hat,
Hats.Purple_Hat, Hats.Straw_Hat, Hats.Sunflower_Hat,
Hats.Traffic_Cone, Hats.Tree_Hat, Hats.Wizard_Hat
]
AUTO_UNLOCKS = [
Unlocks.Cactus, Unlocks.Carrots, Unlocks.Dinosaurs,
Unlocks.Expand, Unlocks.Fertilizer, Unlocks.Grass,
Unlocks.Leaderboard, Unlocks.Megafarm, Unlocks.Mazes,
Unlocks.Polyculture, Unlocks.Pumpkins, Unlocks.Speed,
Unlocks.Sunflowers, Unlocks.The_Farmers_Remains, Unlocks.Top_Hat,
Unlocks.Trees, Unlocks.Watering
]
OVERRIDE_CROP_SELECTION = "none"
OVERRIDE_WORLD_SIZE = "none"
OVERRIDE_EXECUTION_SPEED = "none"
## CALC
def calculate_maze_probability():
return max(
min(
1 - min(num_items(Items.Gold) * 100 / (num_items(Items.Wood) + 1), 1),
MAX_MAZE_PROBABILITY
),
MIN_MAZE_PROBABILITY
)
def manhattan_distance(x, y, target_x, target_y):
return abs(x - target_x) + abs(y - target_y)
def max_num_drones():
return min(max_drones(), get_world_size()**2)
def measure_safe(direction="none"):
if direction == "none":
return measure() or 0
return measure(direction) or 0
def find_optimal_grid(num_drones):
sqrt_drones = (num_drones ** 0.5) // 1
# Check if perfect square
if sqrt_drones * sqrt_drones == num_drones:
return (sqrt_drones, sqrt_drones)
# Find the best rectangular grid
# Start from square root and work down to find factors
best_cols = num_drones
best_rows = 1
best_ratio = 0
for rows in range(1, sqrt_drones + 2):
if num_drones % rows == 0:
cols = num_drones // rows
if cols >= rows: # Prefer cols >= rows
ratio = cols / rows
# Prefer ratios closer to 1 (more square-like)
if ratio < best_ratio or best_ratio == 0:
best_ratio = ratio
best_cols = cols
best_rows = rows
return (best_cols, best_rows)
def assign_lanes_to_drone(drone_index, world_size, num_drones_total, horizontal):
if num_drones_total <= 0 or drone_index >= num_drones_total:
return (0, 0, 0, 0)
lanes_per_drone = world_size // num_drones_total
extra_lanes = world_size % num_drones_total
if drone_index < extra_lanes:
# This drone gets an extra lane
num_lanes = lanes_per_drone + 1
offset = drone_index * (lanes_per_drone + 1)
else:
# Standard allocation
num_lanes = lanes_per_drone
offset = extra_lanes * (lanes_per_drone + 1) + (drone_index - extra_lanes) * lanes_per_drone
if horizontal:
return (0, offset, world_size, num_lanes)
return (offset, 0, num_lanes, world_size)
def get_drone_grid_assignment(drone_index, world_size, num_drones_total):
if num_drones_total <= 0:
return (0, 0, world_size, world_size)
if drone_index >= num_drones_total:
return (0, 0, 0, 0) # Invalid drone index
# Find optimal grid dimensions (prefer square, then rectangular with cols > rows)
grid_cols, grid_rows = find_optimal_grid(num_drones_total)
# Calculate this drone's position in the grid
row = drone_index // grid_cols
col = drone_index % grid_cols
# Distribute space evenly, handling remainders
base_width = world_size // grid_cols
extra_width = world_size % grid_cols
base_height = world_size // grid_rows
extra_height = world_size % grid_rows
# Calculate width for this column
if col < extra_width:
section_width = base_width + 1
offset_x = col * (base_width + 1)
else:
section_width = base_width
offset_x = extra_width * (base_width + 1) + (col - extra_width) * base_width
# Calculate height for this row
if row < extra_height:
section_height = base_height + 1
offset_y = row * (base_height + 1)
else:
section_height = base_height
offset_y = extra_height * (base_height + 1) + (row - extra_height) * base_height
return (offset_x, offset_y, section_width, section_height)
def wait_n_seconds(n):
for _ in range(n):
do_a_flip()
def get_speed_factor():
speed_factor = 1.0
for _ in range(num_unlocked(Unlocks.Speed)):
speed_factor *= 1.5
if num_items(Items.Power) > 0:
return speed_factor * 2
return speed_factor
def round(f):
n, r = f // 1, f % 1
if r >= 0.5:
n += 1
return n
## COST
def get_lowest_cost():
lowest = 0
for u in AUTO_UNLOCKS:
cost = get_cost(u) or {}
for key in cost:
current = cost[key]
if current < lowest or lowest == 0:
lowest = current
return lowest
## UPGRADES
def automate_upgrades():
for u in AUTO_UNLOCKS:
cost = get_cost(u) or {}
can_be_unlocked = len(cost) > 0
for key in cost:
if num_items(key) < cost[key]:
can_be_unlocked = False
break
if can_be_unlocked:
unlock(u)
quick_print(
get_time(),
"New unlock:", u,
"count:", num_unlocked(u)
)
## HATS
def find_fashionable_hat(idx):
while num_unlocked(DRONE_HATS[idx%len(DRONE_HATS)]) == 0:
idx += 1
change_hat(DRONE_HATS[idx%len(DRONE_HATS)])
## MOVEMENT
def navigate_to_position(target_x, target_y):
x, y = get_pos_x(), get_pos_y()
while x != target_x or y != target_y:
moved = False
# Handle X movement
if x < target_x and can_move(East):
move(East)
moved = True
elif x > target_x and can_move(West):
move(West)
moved = True
# Handle Y movement
if y < target_y and can_move(North):
move(North)
moved = True
elif y > target_y and can_move(South):
move(South)
moved = True
# Update position
x, y = get_pos_x(), get_pos_y()
# If we couldn't move at all, we're stuck
if not moved:
break
def move_in_snake_way(offset_x, offset_y, grid_size_x, grid_size_y, flip_parity=False):
x = get_pos_x() - offset_x
y = get_pos_y() - offset_y
parity = 0
if flip_parity:
parity = 1
# Forward snake pattern: alternate direction each row, moving North
if y % 2 == parity: # Default even rows: move East
if x < grid_size_x - 1:
return move(East)
# At eastern edge, move North if possible
if y < grid_size_y - 1:
return move(North)
else: # Default odd rows: move West
if x > 0:
return move(West)
# At western edge, move North if possible
if y < grid_size_y - 1:
return move(North)
# Finished scanning
return False
## MAZE
def is_in_the_maze():
entity_type = get_entity_type()
return entity_type == Entities.Treasure or entity_type == Entities.Hedge
def use_weird_substance():
size = get_world_size()
weird_substance = num_items(Items.Weird_Substance)
substance = size * 2**(num_unlocked(Unlocks.Mazes) - 1)
if substance > weird_substance:
substance = weird_substance
if substance <= 0:
return 0, False
use_item(Items.Weird_Substance, substance)
return substance, True
def solve_with_wall_following():
direction_order = [North, East, South, West]
# State tracking
visited = {} # Maps (pos, dir, follow_sign) -> step_number
current_dir_idx = 0
follow_sign = 1 # 1: right-hand, -1: left-hand
# Loop detection
steps_since_last_flip = 0
flip_cooldown = 20 # Minimum steps before considering another flip
loop_threshold = 8 # If we revisit a state within this many steps, it's a loop
def detect_tight_loop():
current_pos = (get_pos_x(), get_pos_y())
current_state = (current_pos, current_dir_idx, follow_sign)
if current_state in visited:
steps_ago = steps_since_last_flip - visited[current_state]
# Tight loop: revisited same state within threshold
return steps_ago < loop_threshold
return False
step_count = 0
max_steps = 1000 # Safety limit
while get_entity_type() == Entities.Hedge and step_count < max_steps:
step_count += 1
current_pos = (get_pos_x(), get_pos_y())
current_state = (current_pos, current_dir_idx, follow_sign)
# Check for loop and flip if needed
if detect_tight_loop() and steps_since_last_flip >= flip_cooldown:
follow_sign *= -1
steps_since_last_flip = 0
quick_print(
get_time(),
"Loop detected! Flipping to", {1: "right", -1:"left"}[follow_sign],
"rule at position", current_pos
)
# Don't clear visited - keep history to avoid re-entering same loops
# Record this state
visited[current_state] = steps_since_last_flip
steps_since_last_flip += 1
# Wall-following logic
# Try to turn toward the wall (right-hand or left-hand)
side_idx = (current_dir_idx + follow_sign) % 4
if can_move(direction_order[side_idx]):
# Can turn toward wall - do it
move(direction_order[side_idx])
current_dir_idx = side_idx
elif can_move(direction_order[current_dir_idx]):
# Can't turn, but can go straight - do it
move(direction_order[current_dir_idx])
else:
# Can't turn or go straight - turn away from wall
current_dir_idx = (current_dir_idx - follow_sign) % 4
# Note: We don't move here, just change direction
# Next iteration will try to move in the new direction
if step_count >= max_steps:
quick_print(get_time(), "Hit step limit - maze unsolvable or too complex")
return False
return get_entity_type() == Entities.Treasure
def solve_maze():
if is_in_the_maze():
solve_with_wall_following()
if get_entity_type() == Entities.Treasure:
harvest()
quick_print(get_time(), "Solved maze, treasure collected")
return True
return False
## PLANTING
def decide_what_to_plant(allow_dinosaur):
if OVERRIDE_CROP_SELECTION != "none":
if allow_dinosaur or OVERRIDE_CROP_SELECTION != Entities.Dinosaur:
return OVERRIDE_CROP_SELECTION
wood = num_items(Items.Wood)
hay = num_items(Items.Hay)
carrot = num_items(Items.Carrot)
power = num_items(Items.Power)
pumpkin = num_items(Items.Pumpkin)
cactus = num_items(Items.Cactus)
bones = num_items(Items.Bone)
minimum_item_threshold = max(MIN_ITEM_THRESHOLD, get_lowest_cost())
hay_overdue_threshold = hay * HAY_OVERDUE_MARGIN
if carrot > minimum_item_threshold and power < MIN_POWER_LEVEL:
return Entities.Sunflower
if hay > minimum_item_threshold and wood < hay_overdue_threshold:
return Entities.Bush
if wood > minimum_item_threshold and hay > minimum_item_threshold and carrot < hay_overdue_threshold:
return Entities.Carrot
if carrot > minimum_item_threshold and pumpkin < hay_overdue_threshold and not allow_dinosaur:
return Entities.Pumpkin
if pumpkin > minimum_item_threshold and cactus < hay_overdue_threshold and not allow_dinosaur:
return Entities.Cactus
if allow_dinosaur and cactus > minimum_item_threshold and bones < hay_overdue_threshold:
return Entities.Dinosaur
return Entities.Grass
def vary_crop(crop):
if crop in [Entities.Tree, Entities.Tree]:
x, y = get_pos_x(), get_pos_y()
if (x*y)%2 == 0:
return Entities.Tree
return Entities.Bush
return crop
def apply_fertilizer_if_possible():
if num_items(Items.Fertilizer) <= MIN_FERTILIZER:
return False
use_item(Items.Fertilizer)
return True
def plant_crop(crop):
ground_type = get_ground_type()
if crop in PLANTS_REQUIRING_SOIL and ground_type != Grounds.Soil:
till()
if can_harvest():
harvest()
if crop == Entities.Dinosaur:
return
plant(crop)
apply_fertilizer_if_possible()
def plant_with_companion(crop):
plant_crop(crop)
if crop == Entities.Dinosaur:
return ("none", 0, 0)
companion_info = get_companion() or "none"
if companion_info == "none":
return ("none", 0, 0)
companion_type, (target_x, target_y) = companion_info
return (companion_type, target_x, target_y)
def ensure_companion(companion_type, target_x, target_y, offset_x, offset_y, grid_size_x, grid_size_y):
# Check if target is within the grid
if not (offset_x <= target_x < offset_x + grid_size_x and
offset_y <= target_y < offset_y + grid_size_y):
return False
navigate_to_position(target_x, target_y)
entity_at_target = get_entity_type()
if entity_at_target != companion_type:
harvest_if_possible()
ground_type = get_ground_type()
if companion_type in PLANTS_REQUIRING_SOIL and ground_type != Grounds.Soil:
till()
plant(companion_type)
return True
def replant_dead_pumpkin():
if get_entity_type() == Entities.Dead_Pumpkin:
plant(Entities.Pumpkin)
return True
return False
## SORT
def custom_sort(arr, reverse=False, method="none"):
if len(arr) <= 1:
return arr
# Choose pivot (using middle element for better average performance)
pivot = arr[len(arr) // 2]
# Partition into three groups using explicit loops
left = []
middle = []
right = []
def method_(x):
return x
key_func = method_
if method != "none":
key_func = method
pivot_keyed = key_func(pivot)
for x in arr:
x_keyed = key_func(x)
if x_keyed < pivot_keyed:
left.append(x)
elif x_keyed == pivot_keyed:
middle.append(x)
else:
right.append(x)
# Recursively sort and combine
if reverse:
return custom_sort(right, reverse, method) + middle + custom_sort(left, reverse, method)
return custom_sort(left, reverse, method) + middle + custom_sort(right, reverse, method)
def sort_cacti_field(offset_x, offset_y, grid_size_x, grid_size_y, sort_rows):
def sort_one_direction(sort_rows, reverse):
if sort_rows:
outer_grid_size, inner_grid_size = grid_size_y, grid_size_x
swap_direction = East # Sort each row (West to East)
else:
outer_grid_size, inner_grid_size = grid_size_x, grid_size_y
swap_direction = North # Sort each column (South to North)
for i in range(outer_grid_size):
swapped = True
pass_num = 0
while swapped and pass_num < inner_grid_size - 1:
swapped = False
for j in range(inner_grid_size - 1):
if sort_rows:
row, col = i, j
else:
row, col = j, i
navigate_to_position(offset_x + col, offset_y + row)
if get_entity_type() != Entities.Cactus:
if can_harvest():
harvest()
if get_ground_type() != Grounds.Soil:
till()
plant(Entities.Cactus)
current_value = measure_safe()
next_value = measure_safe(swap_direction)
should_swap = False
if reverse:
should_swap = current_value < next_value
else:
should_swap = current_value > next_value
if should_swap:
swap(swap_direction)
swapped = True
pass_num += 1
sort_one_direction(sort_rows, REVERSE_CACTI_SORT)
if sort_rows:
return grid_size_y
else:
return grid_size_x
## WATERING
def water_if_needed():
if get_water() > WATER_THRESHOLD or num_items(Items.Water) <= MIN_WATER_ITEMS:
return
use_item(Items.Water)
## HARVESTING
def should_harvest():
if not can_harvest():
return False
entity_type = get_entity_type()
if entity_type == Entities.Hedge:
return False
if entity_type == Entities.Apple:
return False
return True
def harvest_if_possible(expected_item = "none"):
if not should_harvest():
return False
count_before = 0
if expected_item != "none":
count_before = num_items(expected_item)
harvest()
count_after = 1
if expected_item != "none":
count_after = num_items(expected_item)
return count_after > count_before
def harvest_sunflowers_optimally(offset_x, offset_y, grid_size_x, grid_size_y):
sunflower_positions = []
navigate_to_position(offset_x, offset_y)
# Scan the grid and collect all sunflower positions with their petal counts
while True:
if get_entity_type() != Entities.Sunflower:
plant_crop(Entities.Sunflower)
continue
water_if_needed()
while get_entity_type() == Entities.Sunflower and not can_harvest():
wait_n_seconds(1)
petals = measure_safe()
pos = (get_pos_x(), get_pos_y())
sunflower_positions.append((pos, petals))
if not move_in_snake_way(offset_x, offset_y, grid_size_x, grid_size_y):
navigate_to_position(offset_x, offset_y)
break
# Get unique petal counts unordered
unique_petal_counts = set()
for _, petals in sunflower_positions:
unique_petal_counts.add(petals)
# Iteratively harvest sunflowers with each petal count in descending order
for current_petal_count in custom_sort(list(unique_petal_counts), True):
for (pos_x, pos_y), petals in sunflower_positions[:]:
if petals != current_petal_count:
continue
navigate_to_position(pos_x, pos_y)
while get_entity_type() == Entities.Sunflower and not can_harvest():
wait_n_seconds(1)
harvest()
sunflower_positions.remove(((pos_x, pos_y), petals))
for (pos_x, pos_y), _ in sunflower_positions:
navigate_to_position(pos_x, pos_y)
if can_harvest():
harvest()
navigate_to_position(offset_x, offset_y)
def harvest_apples_optimally(index, offset_x, offset_y, grid_size_x, grid_size_y):
change_hat(Hats.Dinosaur_Hat)
navigate_to_position(offset_x, offset_y)
ends_on_right = grid_size_y % 2 == 1
apples_collected = 0
flip_parity = False
effective_grid_size_x = grid_size_x - 1
stuck = False
apple_pos_x, apple_pos_y = (0, 0)
def speedup(apple_pos_x, apple_pos_y):
if (apple_pos_x >= effective_offset_x
and get_pos_y() < apple_pos_y < grid_size_y - 1
and apples_collected < 0.25 * grid_size_x * grid_size_y):
navigate_to_position(apple_pos_x, apple_pos_y)
apple_pos_x, apple_pos_y = measure()
return (apple_pos_x, apple_pos_y), True
return (apple_pos_x, apple_pos_y), False
while True:
effective_offset_x = offset_x
if not ends_on_right:
effective_offset_x = offset_x + 1
if not move_in_snake_way(effective_offset_x, offset_y, effective_grid_size_x, grid_size_y, flip_parity):
current_pos = get_pos_x(), get_pos_y()
if current_pos[1] == grid_size_y - 1: # hit top
if ends_on_right: # move furhter right and down
flip_parity = True
ends_on_right = not ends_on_right
navigate_to_position(effective_grid_size_x, get_pos_y())
navigate_to_position(effective_grid_size_x, offset_y)
else: # ends on left: move further left and down
flip_parity = False
ends_on_right = grid_size_y % 2 == 1
navigate_to_position(offset_x, get_pos_y())
navigate_to_position(offset_x, offset_y)
navigate_to_position(effective_offset_x, offset_y)
(apple_pos_x, apple_pos_y), boosted = speedup(apple_pos_x, apple_pos_y)
if boosted:
apples_collected += 1
else: # collision with tail mid-air, resolve by going one up or down
if not move(North):
move(South)
if current_pos == (get_pos_x(), get_pos_y()):
stuck = True
break
entity_type = get_entity_type()
if entity_type == Entities.Apple and not stuck:
apple_pos_x, apple_pos_y = measure()
apples_collected += 1
(apple_pos_x, apple_pos_y), boosted = speedup(apple_pos_x, apple_pos_y)
if boosted:
apples_collected += 1
if entity_type != Entities.Apple and can_harvest():
harvest()
find_fashionable_hat(index)
quick_print(
get_time(),
"Acquired dinosaur tail of length:", apples_collected,
)
return apples_collected
## HARVEST_PREPARATION
def prepare_cacti(index, offset_x, offset_y, grid_size_x, grid_size_y):
size = get_world_size()
num_drones_total = num_drones()
if index > 0:
return True, offset_x, offset_y, grid_size_x, grid_size_y
size = get_world_size()
num_drones_to_spawn = max_num_drones()
for sort_rows in (True, False):
spawned_sort_drones = []
while num_drones() > 1:
wait_n_seconds(1)
def create_sort_task(idx, ox, oy, gx, gy, sr):
def task():
find_fashionable_hat(idx)
navigate_to_position(ox, oy)
quick_print(get_time(), "Sort rone", idx, "arrived at:", get_pos_x(), get_pos_y())
lanes = sort_cacti_field(ox, oy, gx, gy, sr)
quick_print(get_time(), "Sort drone:", idx, "completed", lanes, "lanes")
return task
for j in range(0, num_drones_to_spawn - num_drones()):
drone_idx = j + 1
nox, noy, ngx, ngy = assign_lanes_to_drone(drone_idx, size, num_drones_to_spawn, sort_rows)
drone = spawn_drone(create_sort_task(drone_idx, nox, noy, ngx, ngy, sort_rows))
if drone:
spawned_sort_drones.append(drone)
quick_print(get_time(), "Spawned sort drone", drone_idx, "was for rows:", sort_rows)
nox, noy, ngx, ngy = assign_lanes_to_drone(0, size, num_drones_to_spawn, sort_rows)
create_sort_task(0, nox, noy, ngx, ngy, sort_rows)()
for drone in spawned_sort_drones[:]:
wait_for(drone)
spawned_sort_drones.remove(drone)
quick_print(get_time(), "Sorted all, were rows:", sort_rows)
return False, offset_x, offset_y, grid_size_x, grid_size_y
def prepare_pumpkins(index, offset_x, offset_y, grid_size_x, grid_size_y):
not_replanted_cnt = 0
while True:
replanted = False
while True:
replanted = replanted or replant_dead_pumpkin()
if not move_in_snake_way(offset_x, offset_y, grid_size_x, grid_size_y):
navigate_to_position(offset_x, offset_y)
break
if not_replanted_cnt >= 1:
break
if not replanted:
not_replanted_cnt += 1
else:
not_replanted_cnt = 0
return False, offset_x, offset_y, grid_size_x, grid_size_y
def prepare_dinosaur(index, offset_x, offset_y, grid_size_x, grid_size_y):
if index > 0:
return True, offset_x, offset_y, grid_size_x, grid_size_y
size = get_world_size()
return False, 0, 0, size, size
## PHASES
def maze_phase(index, offset_x, offset_y):
navigate_to_position(offset_x, offset_y)
quick_print(get_time(), "Drone:", index, "in the maze at", offset_x, offset_y)
while num_drones() < max_num_drones():
wait_n_seconds(1)
maze_triggered = True
size = get_world_size()
speed_factor = round(get_speed_factor())
if not is_in_the_maze() and index == 0:
wait_n_seconds(size // max(speed_factor, 2) + 1)
if get_entity_type() != Entities.Bush:
plant_crop(Entities.Bush)
_, maze_triggered = use_weird_substance()
quick_print(get_time(), "Drone:", index, "triggered maze", maze_triggered)
waited_seconds = 0
while not is_in_the_maze():
wait_n_seconds(1)
waited_seconds += 1
if num_drones() < max_num_drones() or waited_seconds >= size:
break
solved = solve_maze()
if solved:
quick_print(get_time(), "Drone:", index, "has saved the maze!")
if index == 0:
pet_the_piggy()
navigate_to_position(offset_x, offset_y)
else:
quick_print(get_time(), "Drone:", index, "fought well in the maze, but failed.")
def companion_planting_phase(crop, offset_x, offset_y, grid_size_x, grid_size_y):
companion_map = {}
while True:
varied_crop = vary_crop(crop)
companion_type, target_x, target_y = plant_with_companion(varied_crop)
if companion_type != "none":
plant_pos = get_pos_x(), get_pos_y()
companion_map[plant_pos] = (companion_type, target_x, target_y)
if not move_in_snake_way(offset_x, offset_y, grid_size_x, grid_size_y):
navigate_to_position(offset_x, offset_y)
break
for plant_pos in companion_map:
(companion_type, target_x, target_y) = companion_map[plant_pos]
ensure_companion(
companion_type, target_x, target_y,
offset_x, offset_y, grid_size_x, grid_size_y,
)
navigate_to_position(offset_x, offset_y)
def harvest_preparation_phase(crop, index, offset_x, offset_y, grid_size_x, grid_size_y):
if crop == Entities.Cactus:
return prepare_cacti(index, offset_x, offset_y, grid_size_x, grid_size_y)
if crop == Entities.Pumpkin:
return prepare_pumpkins(index, offset_x, offset_y, grid_size_x, grid_size_y)
if crop == Entities.Dinosaur:
return prepare_dinosaur(index, offset_x, offset_y, grid_size_x, grid_size_y)
return False, offset_x, offset_y, grid_size_x, grid_size_y
def harvest_phase(crop, index, offset_x, offset_y, grid_size_x, grid_size_y):
if crop == Entities.Sunflower:
harvest_sunflowers_optimally(offset_x, offset_y, grid_size_x, grid_size_y)
return False
if crop == Entities.Dinosaur:
harvest_apples_optimally(index, offset_x, offset_y, grid_size_x, grid_size_y)
return False
if crop == Entities.Pumpkin or crop == Entities.Cactus:
if index > 0:
return True
while num_drones() > 1:
wait_n_seconds(1)
harvest_if_possible()
return False
missed_cnt = 0
while True:
water_if_needed()
harvested = harvest_if_possible()
if not harvested:
missed_cnt += 1
if missed_cnt >= grid_size_x * grid_size_y // 2:
break
if harvested and crop == Entities.Cactus:
break
if not move_in_snake_way(offset_x, offset_y, grid_size_x, grid_size_y):
navigate_to_position(offset_x, offset_y)
break
return False
## TASKING
def drone_task(index, do_maze, offset_x, offset_y, grid_size_x, grid_size_y):
quick_print(
get_time(),
"Drone:", index,
"is starting task at area:", offset_x, offset_y, grid_size_x, grid_size_y
)
find_fashionable_hat(index)
# Maze
if do_maze:
maze_phase(index, offset_x, offset_y)
return
# Crop selection
crop = decide_what_to_plant(True)
quick_print(get_time(), "Drone:", index, "selected crop:", crop)
# Companion planting phase
companion_planting_phase(crop, offset_x, offset_y, grid_size_x, grid_size_y)
# Preparation phase
early_exit, offset_x, offset_y, grid_size_x, grid_size_y = harvest_preparation_phase(
crop, index, offset_x, offset_y, grid_size_x, grid_size_y
)
if early_exit:
return
# Harvest phase
early_exit = harvest_phase(crop, index, offset_x, offset_y, grid_size_x, grid_size_y)
if early_exit:
return
quick_print(get_time(), "Harvested:", crop)
## MAIN
def main_loop(once=False):
if OVERRIDE_WORLD_SIZE != "none":
set_world_size(OVERRIDE_WORLD_SIZE)
if OVERRIDE_EXECUTION_SPEED != "none":
set_execution_speed(OVERRIDE_EXECUTION_SPEED)
clear()
consecutive_mazes = 0
while True:
automate_upgrades()
guess = 1 - random()
probability = calculate_maze_probability() / (consecutive_mazes + 1)
do_maze = guess < probability
if do_maze:
consecutive_mazes += 1
else:
consecutive_mazes = 0
if OVERRIDE_CROP_SELECTION != "none":
do_maze = False
num_drones_to_spawn = max_num_drones()
quick_print(
get_time(),
"Starting application.",
"Doing maze:", do_maze, "guess was:", guess, "probability:", probability,
"Number of drones to spawn:", num_drones_to_spawn
)
def create_drone_task(idx, ox, oy, gx, gy):
def task():
navigate_to_position(ox, oy)
quick_print(get_time(), "Drone", idx, "arrived at:", get_pos_x(), get_pos_y())
drone_task(idx, do_maze, ox, oy, gx, gy)
return task
# Spawn drones for different grid sections
size = get_world_size()
spawned_drones = []
for j in range(num_drones_to_spawn - num_drones()):
drone_idx = j + 1 # Start from 1, main thread is 0
offset_x, offset_y, grid_x, grid_y = get_drone_grid_assignment(
drone_idx, size, num_drones_to_spawn
)
drone = spawn_drone(create_drone_task(drone_idx, offset_x, offset_y, grid_x, grid_y))
if drone:
quick_print(get_time(), "Spawned drone", drone_idx, "at section", offset_x, offset_y, grid_x, grid_y)
spawned_drones.append(drone)
# Main thread handles its own section
offset_x, offset_y, grid_x, grid_y = get_drone_grid_assignment(
0, size, num_drones_to_spawn
)
create_drone_task(0, offset_x, offset_y, grid_x, grid_y)()
# wait for drones
for drone in spawned_drones[:]:
wait_for(drone)
spawned_drones.remove(drone)
if once:
break
## EXEC
main_loop(False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment