Locate nearest tree and pathfind to it
This commit is contained in:
parent
e124983414
commit
b0c27a98c1
30
blocks.py
30
blocks.py
|
@ -183,6 +183,26 @@ NON_SOLID = [
|
|||
]
|
||||
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])
|
||||
for block_name in NON_SOLID:
|
||||
for state in BLOCKS[block_name]['states']:
|
||||
|
@ -192,3 +212,13 @@ AVOID_IDS = set()
|
|||
for block_name in AVOID:
|
||||
for state in BLOCKS[block_name]['states']:
|
||||
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
128
bot.py
|
@ -1,7 +1,9 @@
|
|||
import os
|
||||
import time
|
||||
import functools
|
||||
from math import ceil, floor, hypot
|
||||
from math import ceil, floor, hypot, sqrt
|
||||
from itertools import count
|
||||
|
||||
|
||||
import blocks
|
||||
|
||||
|
@ -318,6 +320,116 @@ class MazeSolver(AStar):
|
|||
(x2, y2, z2) = n2
|
||||
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
|
||||
ANGLE_DIR = LVector3f(x=0, y=0, z=-1)
|
||||
ANGLE_REF = LVector3f(x=0, y=1, z=0)
|
||||
|
@ -497,6 +609,20 @@ def main(connection, player_info):
|
|||
except BaseException as e:
|
||||
import traceback
|
||||
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(
|
||||
|
|
Loading…
Reference in New Issue
Block a user