103 lines
4.0 KiB
Python
103 lines
4.0 KiB
Python
|
|
|
|
import random
|
|
|
|
from typing import List, Dict
|
|
|
|
|
|
|
|
|
|
|
|
class AIDecision:
|
|
|
|
def __init__(self, difficulty: str = "medium"):
|
|
|
|
self.difficulty = difficulty
|
|
|
|
self.last_decision_time = 0
|
|
|
|
self.decision_cooldown = self._get_decision_cooldown()
|
|
|
|
|
|
|
|
def decide(self, game_state, dt: float) -> List[Dict]:
|
|
|
|
self.last_decision_time += dt
|
|
|
|
if self.last_decision_time < self.decision_cooldown:
|
|
|
|
return []
|
|
|
|
|
|
|
|
commands = []
|
|
|
|
commands.extend(self.plan_expand(game_state))
|
|
|
|
commands.extend(self.plan_attack(game_state))
|
|
|
|
commands.extend(self.plan_build(game_state))
|
|
|
|
|
|
|
|
self.last_decision_time = 0
|
|
|
|
return commands
|
|
|
|
|
|
|
|
def plan_expand(self, game_state) -> List[Dict]:
|
|
|
|
commands = []
|
|
|
|
resources = getattr(game_state, 'resources', {})
|
|
|
|
minerals = getattr(resources, 'minerals', 0) if hasattr(resources, 'minerals') else 0
|
|
|
|
|
|
|
|
if minerals >= 400 and random.random() < 0.3:
|
|
|
|
commands.append({
|
|
|
|
'type': 'create_entity',
|
|
|
|
'entity_type': 'supply_depot',
|
|
|
|
'position': self._find_expansion_position(game_state)
|
|
|
|
})
|
|
|
|
|
|
|
|
return commands
|
|
|
|
|
|
|
|
def plan_attack(self, game_state) -> List[Dict]:
|
|
|
|
commands = []
|
|
|
|
entities = getattr(game_state, 'entities', [])
|
|
|
|
ai_units = [e for e in entities if getattr(e, 'owner', None) == 'ai']
|
|
|
|
player_units = [e for e in entities if getattr(e, 'owner', None) == 'player']
|
|
|
|
|
|
|
|
if len(ai_units) >= 5 and player_units and random.random() < 0.4:
|
|
|
|
target_unit = random.choice(player_units)
|
|
|
|
for unit in ai_units:
|
|
|
|
if getattr(unit, 'type', None) == 'unit' and getattr(unit, 'state', None) == 'idle':
|
|
|
|
commands.append({
|
|
|
|
'type': 'attack',
|
|
|
|
'entity_id': getattr(unit, 'id', None),
|
|
|
|
'target_id': getattr(target_unit, 'id', None)
|
|
|
|
})
|
|
|
|
|
|
|
|
return commands
|
|
|
|
|
|
|
|
def plan_build(self, game_state) -> List[Dict]:
|
|
|
|
commands = []
|
|
|
|
resources = getattr(game_state, 'resources', {})
|
|
|
|
minerals = getattr(resources, 'minerals', 0) if hasattr(resources, 'minerals') else 0
|
|
|
|
entities = getattr(game_state, 'entities', [])
|
|
|
|
ai_units = [e for e in entities if getattr(e, 'owner', None) == 'ai']
|
|
|
|
|
|
|
|
if minerals >= 150 and len(ai_units) < 8 and random.random() < 0.5:
|
|
|
|
commands.append({
|
|
|
|
'type': 'create_entity',
|
|
|
|
'entity_type': 'worker',
|
|
|
|
'position': self._find_build_position(game_state)
|
|
|
|
})
|
|
|
|
|
|
|
|
if minerals >= 300 and random.random() < 0.2:
|
|
|
|
commands.append({
|
|
|
|
'type': 'create_entity',
|
|
|
|
'entity_type': 'barracks',
|
|
|
|
'position': self._find_build_position(game_state)
|
|
|
|
})
|
|
|
|
|
|
|
|
return commands
|
|
|
|
|
|
|
|
def _find_expansion_position(self, game_state) -> tuple:
|
|
|
|
base_x = getattr(game_state, 'ai_base_x', 100)
|
|
|
|
base_y = getattr(game_state, 'ai_base_y', 100)
|
|
|
|
offset_x = random.randint(-200, 200)
|
|
|
|
offset_y = random.randint(-200, 200)
|
|
|
|
return (base_x + offset_x, base_y + offset_y)
|
|
|
|
|
|
|
|
def _find_build_position(self, game_state) -> tuple:
|
|
|
|
base_x = getattr(game_state, 'ai_base_x', 100)
|
|
|
|
base_y = getattr(game_state, 'ai_base_y', 100)
|
|
|
|
offset_x = random.randint(-50, 50)
|
|
|
|
offset_y = random.randint(-50, 50)
|
|
|
|
return (base_x + offset_x, base_y + offset_y)
|
|
|
|
|
|
|
|
def _get_decision_cooldown(self) -> float:
|
|
|
|
if self.difficulty == "easy":
|
|
|
|
return 3.0
|
|
|
|
elif self.difficulty == "medium":
|
|
|
|
return 2.0
|
|
|
|
elif self.difficulty == "hard":
|
|
|
|
return 1.0
|
|
|
|
else:
|
|
|
|
return 2.0
|
|
|