From ccdd51aad3ad129c0f5861d11ed4cb30df900ab0 Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Wed, 20 May 2020 17:57:22 -0600 Subject: [PATCH] Add timeout to pathfinding, optimize --- blocks.py | 8 ++++---- bot.py | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/blocks.py b/blocks.py index f0ad897..d6647c4 100644 --- a/blocks.py +++ b/blocks.py @@ -183,12 +183,12 @@ NON_SOLID = [ ] SINGLE_SNOW = 3919 -NON_SOLID_IDS = [SINGLE_SNOW] +NON_SOLID_IDS = set([SINGLE_SNOW]) for block_name in NON_SOLID: for state in BLOCKS[block_name]['states']: - NON_SOLID_IDS.append(state['id']) + NON_SOLID_IDS.add(state['id']) -AVOID_IDS = [] +AVOID_IDS = set() for block_name in AVOID: for state in BLOCKS[block_name]['states']: - AVOID_IDS.append(state['id']) + AVOID_IDS.add(state['id']) diff --git a/bot.py b/bot.py index e3fe362..ed50d4e 100644 --- a/bot.py +++ b/bot.py @@ -1,5 +1,6 @@ import os import time +import functools from math import ceil, floor, hypot import blocks @@ -11,6 +12,9 @@ from minecraft.networking.packets import Packet, clientbound, serverbound from minecraft.compat import input from minecraft.managers import ChunksManager +class AStarTimeout(Exception): + pass + class DataManager: def __init__(self): self.blocks_states = {} @@ -107,19 +111,41 @@ PARKOUR = [ PARKOUR_WEST, ] +HYPOT_LUT = { + (0, -1): 1.0, + (0, 1): 1.0, + (1, 0): 1.0, + (-1, 0): 1.0, + (1, -1): 1.414, + (-1, -1): 1.414, + (1, 1): 1.414, + (-1, 1): 1.414, + (0, 2): 2.0, + (-2, 0): 2.0, + (2, 0): 2.0, + (0, -2): 2.0, +} + + def padd(p1, p2): return (p1[0] + p2[0], p1[1] + p2[1], p1[2] + p2[2]) def pint(p): return (int(p[0]), int(p[1]), int(p[2])) +# larger started being slower +BLOCK_CACHE_SIZE = 2**14 + class MazeSolver(AStar): def __init__(self, chunks): self.chunks = chunks + self.start_time = time.time() + @functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) def bair(self, p): return self.chunks.get_block_at(*p) in blocks.NON_SOLID_IDS + @functools.lru_cache(maxsize=BLOCK_CACHE_SIZE) def bavoid(self, p): return self.chunks.get_block_at(*p) in blocks.AVOID_IDS @@ -225,18 +251,19 @@ class MazeSolver(AStar): return True def check_parkour(self, node, offset): - if not self.check_ascend(node, offset): - return False - dest = padd(node, offset) - half_offset = tuple(int(0.5*x) for x in offset) + half_offset = (int(offset[0]/2), offset[1], int(offset[2]/2)) middle = padd(node, half_offset) - middle_head = padd(middle, BLOCK_ABOVE) # dont jump if we can walk instead if not self.bair(padd(middle, BLOCK_BELOW)): return False + if not self.check_ascend(node, offset): + return False + + middle_head = padd(middle, BLOCK_ABOVE) + if not self.bair(middle_head): return False @@ -270,12 +297,16 @@ class MazeSolver(AStar): if self.check_parkour(node, offset): results.append(padd(node, offset)) + if not results: + if time.time() - self.start_time > 2.0: + raise(AStarTimeout) + return results def distance_between(self, n1, n2): (x1, y1, z1) = n1 (x2, y2, z2) = n2 - return hypot(x2 - x1, z2 - z1) + return HYPOT_LUT[x2 - x1, z2 - z1] def heuristic_cost_estimate(self, n1, n2): (x1, y1, z1) = n1 @@ -407,10 +438,13 @@ def main(connection, player_info): s['goal'] = LPoint3f(x=p.location[0], y=p.location[1], z=p.location[2]) print('new waypoint:', s['goal']) + start = time.time() solution = MazeSolver(player_info.chunks).astar(pint(player_info.pos), pint(s['goal'])) if solution: - s['path'] = list(solution) - print(s['path']) + solution = list(solution) + s['path'] = solution + print(len(solution)) + print(round(time.time() - start, 3), 'seconds') else: packet = serverbound.play.ChatPacket() packet.message = 'No path found'