恐龙轻量捷径
预计算路径表、用环形队列维护蛇身,长度达到 512 后直接沿完整回路移动。
使用说明
- 复制完整文件到游戏中运行,脚本会连续刷骨头。资源不足、科技未解锁或遇到增长死路时停止。
- DINO_SHORTCUT_LIMIT 默认 512;已有验证以这个阈值为准。详细模型、测试与历史结果见本主题的辅助文件。
运行前提与限制
独立脚本需要 32×32 农场、恐龙科技和足够支付一局苹果的材料;每局开始与结束都会清场,运行前停止其他无人机。
当前轻量捷径保留了原策略的增长死路,不保证每局填满。起点 (0,0)、苹果依次为 (0,1) 和 (1,0) 就是已知反例;遇到死路后收尾并停止。
20 个随机种子的本地模型中,轻量版与旧版移动步数一致,算法主体预计 tick 减少约 92.3%。这是成本模型估算,尚未由游戏引擎实测确认;综合脚本中的恐龙实现仍是旧策略。
运行环境:游戏内代码窗口。说明由 AI 辅助整理;更多对照版本、测试和记录见恐龙与骨头目录。
完整源码
dinosaur_32.py · 166 行。代码块右上角可复制完整代码。
# The Farmer Was Replaced - standalone 32x32 lightweight dinosaur farm.
# Run in the game with no other drones working on the farm.
# Each round clears the farm before and after playing and consumes apple materials.
# Cached shortcuts + ring queue, then direct cycle movement at tail length 512.
# Keeps the original shortcut policy, including its possible growth dead ends.
WORLD_SIZE = 32
DINO_SHORTCUT_LIMIT = 512
def dino_cycle_index(x, y):
if y == 0:
return x
if x == 0:
return WORLD_SIZE * WORLD_SIZE - y
if y % 2 == 1:
return WORLD_SIZE + (y - 1) * (WORLD_SIZE - 1) + WORLD_SIZE - 1 - x
return WORLD_SIZE + (y - 1) * (WORLD_SIZE - 1) + x - 1
def follow_dino_route(route, head_index, target_index):
# Split at the wrap point: no modulo, position queries, scoring or queue
# operations in the movement loop. The game tracks growth and the tail.
if target_index < head_index:
for index in range(head_index, WORLD_SIZE * WORLD_SIZE):
if not move(route[index]):
return False
head_index = 0
for index in range(head_index, target_index):
if not move(route[index]):
return False
return True
def build_shortcut_tables():
area = WORLD_SIZE * WORLD_SIZE
route = []
neighbors = []
for index in range(area):
route.append(None)
neighbors.append(None)
directions = [East, North, West, South]
for y in range(WORLD_SIZE):
for x in range(WORLD_SIZE):
head = dino_cycle_index(x, y)
xs = [x + 1, x, x - 1, x]
ys = [y, y + 1, y, y - 1]
options = []
for index in range(4):
nx = xs[index]
ny = ys[index]
if nx >= 0 and nx < WORLD_SIZE and ny >= 0 and ny < WORLD_SIZE:
next_head = dino_cycle_index(nx, ny)
advance = (next_head - head) % area
entry = [directions[index], next_head, advance]
options.append(entry)
position = len(options) - 1
while position > 0 and options[position - 1][2] < advance:
options[position] = options[position - 1]
position -= 1
options[position] = entry
if advance == 1:
route[head] = directions[index]
neighbors[head] = options
return [route, neighbors]
def new_shortcut_state():
ring = []
for index in range(WORLD_SIZE * WORLD_SIZE):
ring.append(0)
# Ring, read cursor, write cursor, tail length, current head cycle rank.
return [ring, 0, 0, 0, 0]
def move_shortcut_to(target_x, target_y, state, tables):
area = WORLD_SIZE * WORLD_SIZE
ring = state[0]
read = state[1]
write = state[2]
length = state[3]
head = state[4]
target = dino_cycle_index(target_x, target_y)
grow = True
ok = True
while head != target:
if length >= DINO_SHORTCUT_LIMIT:
# The minimum positive cycle advance is always the successor.
# Never re-enable shortcuts this round; let the game track the tail.
ok = follow_dino_route(tables[0], head, target)
if ok:
head = target
if grow:
length += 1
break
limit = (target - head) % area
if length > 0:
tail_distance = (ring[read] - head) % area
if grow:
tail_distance -= 1
if tail_distance < limit:
limit = tail_distance
if limit <= 0:
ok = False
break
# Body ranks stay ordered. The tail is the first occupied rank ahead,
# so this interval check also replaces the occupied dictionary.
for entry in tables[1][head]:
if entry[2] <= limit:
direction = entry[0]
next_head = entry[1]
break
if not move(direction):
ok = False
break
if grow:
length += 1
grow = False
else:
read = (read + 1) % area
ring[write] = head
write = (write + 1) % area
head = next_head
state[1] = read
state[2] = write
state[3] = length
state[4] = head
return ok
def dinosaur_once(tables):
if num_unlocked(Unlocks.Dinosaurs) == 0:
return False
cost = get_cost(Entities.Apple)
if cost == None:
return False
for item in cost:
if num_items(item) < cost[item] * WORLD_SIZE * WORLD_SIZE:
return False
clear()
change_hat(Hats.Dinosaur_Hat)
state = new_shortcut_state()
next_apple = measure()
ok = True
while next_apple != None:
if not move_shortcut_to(next_apple[0], next_apple[1], state, tables):
ok = False
break
next_apple = measure()
change_hat(Hats.Straw_Hat)
clear()
return ok
def main():
if get_world_size() != WORLD_SIZE:
quick_print("Requires a 32x32 farm.")
return
tables = build_shortcut_tables()
while dinosaur_once(tables):
pass
quick_print("Stopped: check materials, unlocks, or shortcut dead end.")
main()