Locate nearest tree and pathfind to it

This commit is contained in:
Tanner Collin 2020-05-21 00:27:51 -06:00
parent e124983414
commit b0c27a98c1
2 changed files with 157 additions and 1 deletions

View File

@ -183,6 +183,26 @@ NON_SOLID = [
] ]
SINGLE_SNOW = 3919 SINGLE_SNOW = 3919
LOGS = [
'minecraft:oak_log',
'minecraft:spruce_log',
'minecraft:birch_log',
'minecraft:jungle_log',
'minecraft:acacia_log',
'minecraft:dark_oak_log',
]
LEAVES = [
'minecraft:oak_leaves',
'minecraft:spruce_leaves',
'minecraft:birch_leaves',
'minecraft:jungle_leaves',
'minecraft:acacia_leaves',
'minecraft:dark_oak_leaves',
]
NON_SOLID_IDS = set([SINGLE_SNOW]) NON_SOLID_IDS = set([SINGLE_SNOW])
for block_name in NON_SOLID: for block_name in NON_SOLID:
for state in BLOCKS[block_name]['states']: for state in BLOCKS[block_name]['states']:
@ -192,3 +212,13 @@ AVOID_IDS = set()
for block_name in AVOID: for block_name in AVOID:
for state in BLOCKS[block_name]['states']: for state in BLOCKS[block_name]['states']:
AVOID_IDS.add(state['id']) AVOID_IDS.add(state['id'])
LOG_IDS = set()
for block_name in LOGS:
for state in BLOCKS[block_name]['states']:
LOG_IDS.add(state['id'])
LEAF_IDS = set()
for block_name in LEAVES:
for state in BLOCKS[block_name]['states']:
LEAF_IDS.add(state['id'])

128
bot.py
View File

@ -1,7 +1,9 @@
import os import os
import time import time
import functools import functools
from math import ceil, floor, hypot from math import ceil, floor, hypot, sqrt
from itertools import count
import blocks import blocks
@ -318,6 +320,116 @@ class MazeSolver(AStar):
(x2, y2, z2) = n2 (x2, y2, z2) = n2
return hypot(x2 - x1, z2 - z1) return hypot(x2 - x1, z2 - z1)
def spiral(n):
# return x, 0, z coords along a spiral at step n
n += 1
k = ceil((sqrt(n)-1)/2)
t = 2 * k + 1
m = t**2
t = t - 1
if n >= m-t:
return k-(m-n), 0, -k
else:
m = m-t
if n >= m-t:
return -k, 0, -k+(m-n)
else:
m = m-t
if n >= m-t:
return -k+(m-n), 0, k
else:
return k, 0, k-(m-n-t)
def alternate(n, amount):
# return 0, y, 0 where y alternates +/- by amount
# example: 0, 2, -2, 4, -4, 6, -6 for amount = 2
sign = 1 if n % 2 else -1
return (0, ceil(n/2) * sign * amount, 0)
BLOCK_ABOVE = (0, +1, 0)
BLOCK_BELOW = (0, -1, 0)
CHECK_NORTH = (0, 0, -1)
CHECK_SOUTH = (0, 0, +1)
CHECK_EAST = (+1, 0, 0)
CHECK_WEST = (-1, 0, 0)
CHECK_DIRECTIONS = [
CHECK_NORTH,
CHECK_SOUTH,
CHECK_EAST,
CHECK_WEST,
]
class MCWorld:
def __init__(self, chunks):
self.chunks = chunks
def block_at(self, x, y, z):
return self.chunks.get_block_at(x, y, z)
def find_blocks(self, center, distance, block_ids, limit=0):
# search in a spiral from center to all blocks with ID
result = []
for n in count():
offset = spiral(n)
check = padd(center, offset)
if self.block_at(*check) in block_ids:
if hypot(*offset) < distance:
result.append(check)
if limit and len(result) == limit:
return result
if offset[0] > distance:
return result
def find_tree(self, center, distance):
logs = []
for i in range(5):
check = padd(center, alternate(i, 4))
logs.extend(self.find_blocks(center, distance, blocks.LOG_IDS, 5))
for log in logs:
# crawl to the top log
while self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LOG_IDS:
log = padd(log, BLOCK_ABOVE)
# make sure it's a tree
if self.block_at(*padd(log, BLOCK_ABOVE)) in blocks.LEAF_IDS:
break
else: # for
return None
# crawl to the bottom log
while self.block_at(*padd(log, BLOCK_BELOW)) in blocks.LOG_IDS:
log = padd(log, BLOCK_BELOW)
return log
def find_tree_openings(self, tree):
# returns coords in a cardinal direction where we can stand by tree
maze_solver = MazeSolver(self.chunks)
result = []
for distance in range(5):
for direction in CHECK_DIRECTIONS:
offset = (0, 0, 0)
for _ in range(distance):
offset = padd(offset, direction)
if maze_solver.check_traverse(tree, offset):
result.append(padd(tree, offset))
return result
def navigate_to_opening(self, start, opening):
maze_solver = MazeSolver(self.chunks)
try:
return list(maze_solver.astar(start, opening))
except AStarTimeout:
return None
TICK = 0.05 TICK = 0.05
ANGLE_DIR = LVector3f(x=0, y=0, z=-1) ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
ANGLE_REF = LVector3f(x=0, y=1, z=0) ANGLE_REF = LVector3f(x=0, y=1, z=0)
@ -497,6 +609,20 @@ def main(connection, player_info):
except BaseException as e: except BaseException as e:
import traceback import traceback
print(traceback.format_exc()) print(traceback.format_exc())
elif '!tree' in chat_packet.json_data:
try:
mc_world = MCWorld(player_info.chunks)
start = time.time()
coords = mc_world.find_tree(pint(player_info.pos), 100)
print(coords)
openings = mc_world.find_tree_openings(coords)
print(openings)
path = mc_world.navigate_to_opening(pint(player_info.pos), openings[0])
print(path)
print(round(time.time() - start, 3), 'seconds')
except BaseException as e:
import traceback
print(traceback.format_exc())
connection.register_packet_listener( connection.register_packet_listener(