Update external bot agent with obstacle-aware distance navigation and safe pass fallback
This commit is contained in:
parent
85ee13a513
commit
5fb7e07103
|
|
@ -1,5 +1,6 @@
|
|||
"""External Bot Agent with deliberate decision-making logic:
|
||||
- Evaluates targets via Radar sensor.
|
||||
- Intelligently navigates around impassable obstacles (mountains and forests).
|
||||
- Decides whether to negotiate party formation or refuse & fight based on strength.
|
||||
- Explicitly engages in 3-bout D20 battles when adjacent to an opposing party/refusing bot.
|
||||
- Parses battle results, bout rolls, scores, and absorbed members.
|
||||
|
|
@ -138,10 +139,11 @@ class SmartBotAgent:
|
|||
party = res.json()
|
||||
print(f"✅ [PARTY FORMED] Squad '{party['name']}' established! Leader: {party['leader_name']} | Str: {party['total_strength']}")
|
||||
else:
|
||||
# Fallback: move into adjacent square to trigger engine merge
|
||||
self._pass_or_step()
|
||||
# Fallback: pass turn if party creation rejected
|
||||
requests.post(f"{BASE_URL}/players/{self.bot_id}/pass")
|
||||
except Exception as e:
|
||||
print(f"Party formation error: {e}")
|
||||
requests.post(f"{BASE_URL}/players/{self.bot_id}/pass")
|
||||
|
||||
def _initiate_battle(self, opponent_id: str):
|
||||
"""Explicitly call the 3-Bout D20 Battle endpoint."""
|
||||
|
|
@ -164,33 +166,56 @@ class SmartBotAgent:
|
|||
else:
|
||||
print(f"Battle failed ({res.status_code}): {res.text}")
|
||||
|
||||
def _get_best_move_towards(self, target_x: int, target_y: int, moves: Dict[str, Any]) -> Optional[str]:
|
||||
"""Pick the available direction that minimizes Chebyshev distance to (target_x, target_y), strictly avoiding obstacles."""
|
||||
valid_moves = {d: chk for d, chk in moves.items() if chk.get("available")}
|
||||
if not valid_moves:
|
||||
return None
|
||||
|
||||
def dist(chk: Dict[str, Any]) -> int:
|
||||
return max(abs(chk["target_x"] - target_x), abs(chk["target_y"] - target_y))
|
||||
|
||||
return min(valid_moves.keys(), key=lambda d: dist(valid_moves[d]))
|
||||
|
||||
def _step_or_attack(self, target: Dict[str, Any]):
|
||||
"""Move adjacent/towards the target."""
|
||||
"""Move adjacent/towards the target while avoiding obstacles."""
|
||||
moves_res = requests.get(f"{BASE_URL}/players/{self.bot_id}/available-moves").json()
|
||||
available = [d for d, chk in moves_res["moves"].items() if chk["available"]]
|
||||
if available:
|
||||
# Move towards target
|
||||
chosen = available[0]
|
||||
moves = moves_res.get("moves", {})
|
||||
chosen = self._get_best_move_towards(target["x"], target["y"], moves)
|
||||
|
||||
if chosen:
|
||||
res = requests.post(f"{BASE_URL}/players/{self.bot_id}/move", json={"direction": chosen}).json()
|
||||
if res.get("battle_triggered"):
|
||||
print(f"⚔️ Move triggered battle! Winner: {res['battle_result']['winner_party_name']}")
|
||||
elif res.get("party_formed_triggered"):
|
||||
print(f"🤝 Move resulted in party alliance!")
|
||||
else:
|
||||
print("⚠️ No passable moves adjacent to target (terrain/border constraint). Passing turn.")
|
||||
requests.post(f"{BASE_URL}/players/{self.bot_id}/pass")
|
||||
|
||||
def _navigate_towards_goal(self, radar_res: Dict[str, Any]):
|
||||
"""Move towards the nearest target or explore unvisited areas."""
|
||||
"""Move towards the nearest target routing around obstacles."""
|
||||
rec_dir = radar_res.get("recommended_direction")
|
||||
nearest = radar_res.get("nearest_target")
|
||||
moves_res = requests.get(f"{BASE_URL}/players/{self.bot_id}/available-moves").json()
|
||||
available = [d for d, chk in moves_res["moves"].items() if chk["available"]]
|
||||
moves = moves_res.get("moves", {})
|
||||
available = [d for d, chk in moves.items() if chk.get("available")]
|
||||
|
||||
if not available:
|
||||
print("🚫 No available moves. Passing turn.")
|
||||
print("🚫 All adjacent paths blocked by borders or obstacle terrain (mountains/forests). Passing turn.")
|
||||
requests.post(f"{BASE_URL}/players/{self.bot_id}/pass")
|
||||
return
|
||||
|
||||
chosen_dir = rec_dir if rec_dir in available else available[0]
|
||||
# 1. Prefer radar's obstacle-aware BFS pathfinder direction
|
||||
if rec_dir and rec_dir in available:
|
||||
chosen_dir = rec_dir
|
||||
# 2. Otherwise pick the available direction that minimizes distance to the nearest target
|
||||
elif nearest:
|
||||
chosen_dir = self._get_best_move_towards(nearest["x"], nearest["y"], moves) or available[0]
|
||||
# 3. Fallback to any valid open terrain cell
|
||||
else:
|
||||
chosen_dir = available[0]
|
||||
|
||||
print(f"🧭 Moving {chosen_dir} (Goal: {radar_res.get('bot_goal')}, Action: {radar_res.get('recommended_action')})")
|
||||
res = requests.post(f"{BASE_URL}/players/{self.bot_id}/move", json={"direction": chosen_dir}).json()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue