Skip to content
kamarli-mertPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🎮 TankMan Arena — Algoritma Geliştirici Dokümantasyonu

Bu belge, TankMan Arena için yapay zeka algoritması yazan geliştiricilere yönelik hazırlanmıştır. Bu belgeyi GPT/Claude gibi bir yapay zekaya vererek otomatik olarak iyi bir algoritma ürettirmenize yardımcı olacak detaylarda tasarlanmıştır.


İçindekiler

  1. Genel Konsept
  2. Arena ve Oyun Sabitleri
  3. MLPlay Sınıfı — Zorunlu Yapı
  4. scene_info — Bilgi Paketi
  5. Komutlar — Ne Yapabilirsin?
  6. Oyun Mekaniği
  7. Açı Hesaplama Rehberi
  8. Görüş Hattı (LOS)
  9. Kaynak Yönetimi (HP & Yakıt & Mermi)
  10. Harita Editörü & Duvarlar
  11. Örnek Algoritmalar

Genel Konsept

TankMan Arena, 1 ila 4 tankın birbirine karşı savaştığı bir top-down arena oyunudur. Senin görevin, MLPlay adında bir Python sınıfı yazarak bir tanka beyin olmaktır.

Her oyun karesinde (frame) motor sana scene_info adlı bir Python sözlüğü verir. Sen de buna karşılık bir komut listesi (list) dönersin. Motor bu komutu uygular, ekranı günceller ve bir sonraki karede aynısını tekrarlar.

Oyun 30 FPS hızında çalışır. Her saniye 30 kez update() çağrılır.


Arena ve Oyun Sabitleri

Arena Genişliği : 1000 piksel (X ekseni: 0 → 1000)
Arena Yüksekliği: 700 piksel  (Y ekseni: 0 → 700)
Merkez Nokta    : (500, 350)

Tank Boyutu     : 50x50 piksel (merkez noktası x,y koordinatıdır)
Tank Hızı       : 3 piksel/frame = 90 piksel/saniye
Dönüş Hızı     : 5 derece/frame
Mermi Hızı     : 10 piksel/frame = 300 piksel/saniye
Ateş Cooldown  : 30 frame = 1 saniye (her atıştan sonra bekleme)

Başlangıç Değerleri:
  HP (Can)      : 5 (max: 10, min: 0 → ölüm)
  Ammo (Mermi)  : 50
  Oil (Yakıt)   : 100.0 (max: 200, min: 0 → hareket edemez)

Koordinat Sistemi:

  • x = 0 sol kenar, x = 1000 sağ kenar
  • y = 0 üst kenar, y = 700 alt kenar
  • Açılar 0° = sağ (doğu), 90° = aşağı (güney), 180° = sol (batı), 270° = yukarı (kuzey)

MLPlay Sınıfı — Zorunlu Yapı

Algoritma dosyan mutlaka aşağıdaki yapıya sahip olmalıdır:

import math

class MLPlay:
    def __init__(self, *args, **kwargs):
        """
        Oyun başladığında SADECE BİR KEZ çağrılır.
        Değişkenlerini burada başlat. (State, sayaçlar, hedef bilgileri vb.)
        """
        self.frame_count = 0
        # Burada istediğin kadar değişken tanımlayabilirsin
    
    def update(self, scene_info, *args, **kwargs):
        """
        Her frame'de çağrılır (30 kez/saniye).
        
        Args:
            scene_info (dict): Mevcut oyun durumunu içeren bilgi paketi.
        
        Returns:
            list[str]: Uygulanacak komutların listesi.
                       Boş liste döndürmek geçerlidir (hiçbir şey yapma).
                       Birden fazla komut aynı anda verilebilir.
        """
        self.frame_count += 1
        commands = []
        
        # Buraya mantığını yaz
        
        return commands
    
    def reset(self):
        """
        Oyun yeniden başladığında çağrılır.
        Değişkenlerini sıfırla.
        """
        self.frame_count = 0

scene_info — Bilgi Paketi (Ne Görürsün?)

update(scene_info) fonksiyonuna gelen scene_info, her tankın kendi bakış açısından hazırlanan bir Python sözlüğüdür.

Tam scene_info Yapısı

scene_info = {
    # --- KENDİ TANIK BİLGİLERİ ---
    "x"        : float,  # Tankının X koordinatı (0–1000)
    "y"        : float,  # Tankının Y koordinatı (0–700)
    "angle"    : float,  # Tank gövdesinin açısı (0–360 derece)
    "gun_angle": float,  # Namlu açısı (gövde açısı + namlu offset'i, 0–360)
    
    # --- KAYNAKLAR ---
    "lives"    : int,    # Mevcut HP (0–10). 0 olursa tank ölür.
    "power"    : int,    # Mevcut mermi sayısı. 0 ise ateş edemezsin.
    "oil"      : float,  # Mevcut yakıt (0.0–200.0). 0 ise hareket edemezsin.
    
    # --- DÜŞMAN BİLGİLERİ ---
    "competitor_info": [
        {
            "id"        : int,   # Düşman tank kimliği (1, 2, 3 veya 4)
            "x"         : float, # Düşmanın X koordinatı
            "y"         : float, # Düşmanın Y koordinatı
            "angle"     : float, # Düşmanın baktığı yön (derece)
            "is_visible": bool   # True = görüş hattı açık (duvar yok arada)
                                 # False = bir duvar arada, GÖREMEZSIN
        },
        # ... (hayatta olan her düşman için bir kayıt)
    ],
    
    # --- HARİTA BİLGİLERİ ---
    "walls_info": [
        {
            "x"     : float,  # Duvarın sol üst köşesi X
            "y"     : float,  # Duvarın sol üst köşesi Y
            "width" : float,  # Genişliği (genellikle 50)
            "height": float   # Yüksekliği (genellikle 50)
        },
        # ... (haritadaki her duvar bloğu için)
    ],
    
    # --- MERMİ BİLGİLERİ ---
    "bullets_info": [
        {
            "x": float,  # Merminin X konumu
            "y": float   # Merminin Y konumu
        },
        # ... (aktif her mermi için)
    ],
    
    # --- PICKUP (TOPLANABILIR EŞYA) BİLGİLERİ ---
    "pickups_info": [
        {
            "type": str,   # "hp" | "ammo" | "oil"
            "x"   : float, # Pickup'ın X merkez koordinatı
            "y"   : float  # Pickup'ın Y merkez koordinatı
        },
        # ...
    ]
}

Pratik Kullanım Örnekleri

def update(self, scene_info, *args, **kwargs):
    # Kendi pozisyon ve kaynaklarına eriş
    my_x    = scene_info["x"]
    my_y    = scene_info["y"]
    my_angle = scene_info["angle"]
    gun_angle = scene_info.get("gun_angle", my_angle)
    hp      = scene_info["lives"]
    ammo    = scene_info["power"]
    oil     = scene_info["oil"]
    
    # Düşman listesini al
    enemies = scene_info.get("competitor_info", [])
    
    # Duvarları al
    walls = scene_info.get("walls_info", [])
    
    # Pickup'ları al
    pickups = scene_info.get("pickups_info", [])
    
    # Mermileri al
    bullets = scene_info.get("bullets_info", [])
    
    # Hayatta düşman var mı?
    if not enemies:
        return ["TURN_LEFT"]  # Bekle, keşfet
    
    # En yakın düşmanı bul
    nearest = min(enemies, key=lambda e: math.hypot(e["x"] - my_x, e["y"] - my_y))
    ...

Komutlar — Ne Yapabilirsin?

update() fonksiyonun bir liste döndürür. Listedeki her string bir komuttur.

Komut Açıklama
"FORWARD" Tankı baktığı yönde 3 px/frame ilerletir.
"BACKWARD" Tankı baktığı yönün tersine 3 px/frame geri götürür.
"TURN_LEFT" Tank gövdesini sola döndürür (–5°/frame).
"TURN_RIGHT" Tank gövdesini sağa döndürür (+5°/frame).
"AIM_LEFT" Namluyu gövdeden bağımsız sola döndürür (–5°/frame).
"AIM_RIGHT" Namluyu gövdeden bağımsız sağa döndürür (+5°/frame).
"SHOOT" Mermi atar. Cooldown (30 frame) süresince tekrar atamazsın.

Önemli Notlar

  • Birden fazla komut aynı anda verilebilir. Örneğin ["FORWARD", "TURN_RIGHT", "SHOOT"] hepsi aynı frame'de uygulanır.
  • "AIM_LEFT" / "AIM_RIGHT" namluyu gövdeden bağımsız döndürür. Bu sayede hedefe baktırırken farklı yönde hareket edebilirsin.
  • "TURN_LEFT" / "TURN_RIGHT" hem gövdeyi hem de namlunun görüntüsünü etkilese de, namlu relatif açısı (offset) korunur. Namlunun mutlak açısı = gövde_açısı + namlu_offset.
  • Mermi cooldown: Her "SHOOT" komutundan sonra 30 frame (1 saniye) boyunca yeni mermi atamazsın. Bu süre dolmadan verilen "SHOOT" komutu dikkate alınmaz.
  • Yakıt tüketimi: "FORWARD" veya "BACKWARD" her kullanımda 0.1 yakıt tüketir. Yakıt 0'a düşünce hareket edemezsn, ateş etmeye devam edebilirsin.

Oyun Mekaniği

Hasar & Ölüm

  • Her mermi çarptığında tank 1 HP kaybeder.
  • HP 0'a düşen tank oyundan elenir.
  • Başlangıçta: HP = 5, maksimum HP = 10.
  • Bir düşmanı öldürmek: +50 puan, bir düşmana mermi isabet ettirmek: +10 puan.

Mermi Fiziği (Seken Mermiler)

  • Mermiler bir duvara veya arena kenarına çarptığında yansıyarak yoluna devam eder.
  • Her mermi yalnızca 1 kez yansıyabilir. İkinci çarpışmada yok olur.
  • Yansıma açısı, çarpılan yüzeyin yönüne göre hesaplanır (fizik yasaları).

Pickup'lar (Toplanabilir Eşyalar)

Haritada rastgele konumlarda 3 çeşit pickup belirir:

Pickup Etki
"hp" (kırmızı kalp) +2 HP (maksimum 10)
"ammo" (mermi ikonu) +5 mermi
"oil" (yağ damlası) +30 yakıt (maksimum 200)
  • Başlangıçta 4 pickup doğar.
  • Sonrasında her 5 saniyede bir (150 frame) yeni pickup doğar.
  • Bir tanka 40 piksel mesafesine girince pickup toplanır.
  • HP maksimum (10) ya da Oil maksimum (200) ise ilgili pickup toplanamaz (heba olmaz, haritada kalır).

Çarpışma Kuralları

  • Tanklar duvarlara ve arena kenarlarına çarpınca durur (hasar almaz).
  • Tanklar birbirine çarptığında da durur (biri kazanamaz, sadece ilerleme durur).
  • Kendi mermen sana hasar vermez; yalnızca başka tankların mermileri sana zarar verir.

Açı Hesaplama Rehberi

TankMan'de açı sistemi şu şekilde çalışır:

  • 0° = Sağ (pozitif X yönü)
  • 90° = Aşağı (pozitif Y yönü, ekranın aşağısı)
  • 180° = Sol
  • 270° = Yukarı
import math

def hedef_acisini_hesapla(my_x, my_y, target_x, target_y):
    """A noktasından B noktasına bakış açısı (0-360)"""
    dx = target_x - my_x
    dy = target_y - my_y
    return math.degrees(math.atan2(dy, dx)) % 360

def donus_yonu(mevcut_aci, hedef_aci):
    """
    Hangi yöne dönmek daha kısa? Pozitif = sağa, negatif = sola.
    Sonuç: -180 ile +180 arasında bir değer.
    """
    diff = (hedef_aci - mevcut_aci + 180) % 360 - 180
    return diff  # > 0 ise TURN_RIGHT, < 0 ise TURN_LEFT

# Kullanım örneği:
def update(self, scene_info):
    my_x, my_y = scene_info["x"], scene_info["y"]
    my_angle = scene_info["angle"]
    enemies = scene_info.get("competitor_info", [])
    commands = []
    
    if enemies:
        target = enemies[0]  # İlk düşmanı hedef al
        
        hedef_aci = hedef_acisini_hesapla(my_x, my_y, target["x"], target["y"])
        fark = donus_yonu(my_angle, hedef_aci)
        
        if abs(fark) > 5:
            commands.append("TURN_RIGHT" if fark > 0 else "TURN_LEFT")
        else:
            commands.append("FORWARD")  # Hedefe yönel, ilerle
    
    return commands

Namlu Kontrolü (Bağımsız Nişan Alma)

def update(self, scene_info):
    my_x, my_y = scene_info["x"], scene_info["y"]
    my_gun_angle = scene_info.get("gun_angle", scene_info["angle"])
    enemies = scene_info.get("competitor_info", [])
    commands = ["FORWARD"]  # Sürekli hareket et
    
    if enemies:
        target = min(enemies, key=lambda e: math.hypot(e["x"]-my_x, e["y"]-my_y))
        target_angle = math.degrees(math.atan2(target["y"]-my_y, target["x"]-my_x)) % 360
        
        # Namluyu hedefe çevir (gövdeden bağımsız)
        gun_diff = (target_angle - my_gun_angle + 180) % 360 - 180
        if abs(gun_diff) > 2:
            commands.append("AIM_RIGHT" if gun_diff > 0 else "AIM_LEFT")
        
        # Nişan yeterince iyi ve düşman görünürse ateş et
        dist = math.hypot(target["x"]-my_x, target["y"]-my_y)
        if abs(gun_diff) < 10 and dist < 600 and target.get("is_visible", True):
            commands.append("SHOOT")
    
    return commands

Görüş Hattı (LOS)

competitor_info içindeki her düşmanın is_visible alanı, o düşmanın görüş hattında olup olmadığını gösterir. Görüş hattı, senin tankın ile düşman arasındaki düz çizgide duvar olup olmadığını kontrol eder.

# Görüş hattı kontrolü
for enemy in scene_info.get("competitor_info", []):
    if enemy["is_visible"]:
        # Düşman görünür → Ateş edebilirsin
        pass
    else:
        # Düşman bir duvarın arkasında → Ateş etmek mantıksız
        # Belki etrafından dolaş, veya bekle
        pass

İPUCU: is_visible = False iken ateş etmek mermini boşa harcar. Duvarlardan yansıyan mermileri hesaba katmak istiyorsan kendi yansıma hesabını yapman gerekir.


Kaynak Yönetimi

def update(self, scene_info):
    hp    = scene_info["lives"]   # Can
    ammo  = scene_info["power"]   # Mermi
    oil   = scene_info["oil"]     # Yakıt
    pickups = scene_info.get("pickups_info", [])
    my_x, my_y = scene_info["x"], scene_info["y"]
    
    # 1. ACİL DURUM: Can veya Yakıt kritik seviyede → pickup'a koş
    if hp <= 2 or oil <= 20:
        hp_pickups = [p for p in pickups if p["type"] in ("hp", "oil")]
        if hp_pickups:
            target = min(hp_pickups, key=lambda p: math.hypot(p["x"]-my_x, p["y"]-my_y))
            # Hedefe yönel...
    
    # 2. Mermi bitmek üzere → ammo pickup'a koş
    if ammo <= 5:
        ammo_pickups = [p for p in pickups if p["type"] == "ammo"]
        # ...
    
    # 3. Yakıt bitti → hareket etemezsin, sadece dön ve ateş et
    if oil <= 0:
        return ["TURN_RIGHT", "SHOOT"]  # Yerinde dön ve ateş et

Harita Editörü & Duvarlar

Haritaya duvar eklenebilir. Duvarlar scene_info["walls_info"] içinde gelir.

Her duvar şu yapıdadır:

{
    "x": float,      # Sol üst köşe X
    "y": float,      # Sol üst köşe Y
    "width": float,  # Genellikle 50
    "height": float  # Genellikle 50
}

Yolda Duvar Var mı? (Basit Kontrol)

def yolda_duvar_var_mi(x1, y1, x2, y2, walls, margin=15):
    """
    (x1,y1) ile (x2,y2) arasında duvar var mı?
    margin: Tankın kaçınma mesafesi (piksel)
    """
    steps = 10
    for i in range(1, steps + 1):
        check_x = x1 + (x2 - x1) * (i / steps)
        check_y = y1 + (y2 - y1) * (i / steps)
        for wall in walls:
            if (wall["x"] - margin < check_x < wall["x"] + wall["width"] + margin and
                wall["y"] - margin < check_y < wall["y"] + wall["height"] + margin):
                return True
    return False

# Kullanım:
walls = scene_info.get("walls_info", [])
target_x, target_y = 500, 350  # Hedef nokta

if yolda_duvar_var_mi(my_x, my_y, target_x, target_y, walls):
    # Alternatif yol dene
    for offset in [45, -45, 90, -90]:
        alt_angle = (target_angle + offset) % 360
        rad = math.radians(alt_angle)
        alt_x = my_x + math.cos(rad) * 100
        alt_y = my_y + math.sin(rad) * 100
        if not yolda_duvar_var_mi(my_x, my_y, alt_x, alt_y, walls):
            target_angle = alt_angle
            break

Örnek Algoritmalar

1. Minimal Başlangıç (En Basit Algoritma)

class MLPlay:
    """Sadece dümdüz gider. Başlangıç için referans."""
    def __init__(self, *args, **kwargs):
        pass
    
    def update(self, scene_info, *args, **kwargs):
        return ["FORWARD"]
    
    def reset(self):
        pass

2. Keskin Nişancı (Sniper)

Hedefe namlu ile nişan alır, ideal mesafede (200-450px) yatay hareket yaparak vurulmayı zorlaştırır.

import math

class MLPlay:
    def __init__(self, *args, **kwargs):
        self.strafe_dir = 1    # Yanal hareket yönü (+1 veya -1)
        self.strafe_timer = 0  # Yön değişim sayacı

    def update(self, scene_info, *args, **kwargs):
        commands = []
        my_x, my_y   = scene_info["x"], scene_info["y"]
        my_angle      = scene_info["angle"]
        my_gun_angle  = scene_info.get("gun_angle", my_angle)
        enemies       = scene_info.get("competitor_info", [])
        pickups       = scene_info.get("pickups_info", [])

        # Düşman yoksa pickup'a git
        if not enemies:
            if pickups:
                target = min(pickups, key=lambda p: math.hypot(p["x"]-my_x, p["y"]-my_y))
                dx, dy = target["x"] - my_x, target["y"] - my_y
                t_angle = math.degrees(math.atan2(dy, dx)) % 360
                diff = (t_angle - my_angle + 180) % 360 - 180
                commands.append("FORWARD")
                if abs(diff) > 5:
                    commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
            else:
                commands += ["AIM_RIGHT", "TURN_LEFT"]
            return commands

        # En yakın düşmanı hedef al
        target = min(enemies, key=lambda e: math.hypot(e["x"]-my_x, e["y"]-my_y))
        dist = math.hypot(target["x"]-my_x, target["y"]-my_y)
        dx, dy = target["x"]-my_x, target["y"]-my_y
        target_angle = math.degrees(math.atan2(dy, dx)) % 360

        # Namluyu hedefe çevir (bağımsız nişan alma)
        gun_diff = (target_angle - my_gun_angle + 180) % 360 - 180
        if abs(gun_diff) > 2:
            commands.append("AIM_RIGHT" if gun_diff > 0 else "AIM_LEFT")

        # Yanal hareket (Strafing) — her 1.5 saniyede yön değiştirir
        self.strafe_timer += 1
        if self.strafe_timer % 45 == 0:
            self.strafe_dir *= -1

        body_diff = (target_angle - my_angle + 180) % 360 - 180

        if dist > 450:      # Uzaksa yaklaş
            commands.append("FORWARD")
            if abs(body_diff) > 5:
                commands.append("TURN_RIGHT" if body_diff > 0 else "TURN_LEFT")
        elif dist < 200:    # Çok yakınsa geri çekil
            commands.append("BACKWARD")
            if abs(body_diff) > 10:
                commands.append("TURN_RIGHT" if body_diff > 0 else "TURN_LEFT")
        else:               # İdeal menzil: hedefe 90° → daire çiz
            strafe_target = (target_angle + 90 * self.strafe_dir) % 360
            strafe_diff = (strafe_target - my_angle + 180) % 360 - 180
            commands.append("FORWARD")
            if abs(strafe_diff) > 5:
                commands.append("TURN_RIGHT" if strafe_diff > 0 else "TURN_LEFT")

        # Nişan yeterliyse ateş et
        if abs(gun_diff) < 10 and dist < 600 and target.get("is_visible", True):
            commands.append("SHOOT")

        return commands

    def reset(self):
        self.strafe_timer = 0

3. Hayatta Kalma (Survivalist)

Kaynakları önceliklendirir: Hem pickup toplar hem düşmandan kaçar.

import math

class MLPlay:
    def __init__(self, *args, **kwargs):
        pass

    def update(self, scene_info, *args, **kwargs):
        commands = []
        my_x, my_y = scene_info["x"], scene_info["y"]
        my_angle   = scene_info["angle"]
        hp         = scene_info.get("lives", 5)
        oil        = scene_info.get("oil", 100)
        ammo       = scene_info.get("power", 0)
        pickups    = scene_info.get("pickups_info", [])
        enemies    = scene_info.get("competitor_info", [])

        # --- ACİL: Düşman çok yakınsa kaç ---
        for enemy in enemies:
            dist = math.hypot(enemy["x"]-my_x, enemy["y"]-my_y)
            if dist < 200:
                # Düşmandan ters yöne kaç
                escape_angle = (math.degrees(math.atan2(enemy["y"]-my_y, enemy["x"]-my_x)) + 180) % 360
                diff = (escape_angle - my_angle + 180) % 360 - 180
                commands.append("FORWARD")
                if abs(diff) > 5:
                    commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
                if ammo > 0 and enemy.get("is_visible", True):
                    commands.append("SHOOT")
                return commands

        # --- KAYNAK KRİTİK: Hp veya Yakıt az → pickup'a koş ---
        if (hp < 3 or oil < 50) and pickups:
            p_filtered = [p for p in pickups if p["type"] in ("hp", "oil")] or pickups
            target = min(p_filtered, key=lambda p: math.hypot(p["x"]-my_x, p["y"]-my_y))
            dx, dy = target["x"]-my_x, target["y"]-my_y
            t_angle = math.degrees(math.atan2(dy, dx)) % 360
            diff = (t_angle - my_angle + 180) % 360 - 180
            if abs(diff) > 5:
                commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
            if abs(diff) <= 30:
                commands.append("FORWARD")
            return commands

        # --- NORMAL: En yakın pickup'a git ---
        if pickups:
            target = min(pickups, key=lambda p: math.hypot(p["x"]-my_x, p["y"]-my_y))
            dx, dy = target["x"]-my_x, target["y"]-my_y
            t_angle = math.degrees(math.atan2(dy, dx)) % 360
            diff = (t_angle - my_angle + 180) % 360 - 180
            if abs(diff) > 5:
                commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
            if abs(diff) <= 30:
                commands.append("FORWARD")
        else:
            # Pickup yoksa merkeze git
            dx, dy = 500-my_x, 350-my_y
            if math.hypot(dx, dy) > 100:
                t_angle = math.degrees(math.atan2(dy, dx)) % 360
                diff = (t_angle - my_angle + 180) % 360 - 180
                commands.append("FORWARD")
                if abs(diff) > 5:
                    commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
            else:
                commands.append("TURN_LEFT")  # Keşif dönüşü

        return commands

    def reset(self):
        pass

4. Agresif Saldırgan (+ Duvar Kaçınma)

Hem pickup hem düşman kovalar, yolda duvar varsa alternatif açı dener.

import math

class MLPlay:
    def __init__(self, *args, **kwargs):
        self.target_pickup = None   # Hedeflenen pickup
        self.revenge_mode  = 0      # Pickup çalınınca intikam sayacı
        self.revenge_id    = None

    def _is_blocked(self, x1, y1, x2, y2, walls, margin=15):
        """x1,y1 → x2,y2 yolunda duvar var mı?"""
        steps = 10
        for i in range(1, steps + 1):
            cx = x1 + (x2 - x1) * i / steps
            cy = y1 + (y2 - y1) * i / steps
            for w in walls:
                if (w["x"]-margin < cx < w["x"]+w["width"]+margin and
                    w["y"]-margin < cy < w["y"]+w["height"]+margin):
                    return True
        return False

    def update(self, scene_info, *args, **kwargs):
        commands = []
        my_x, my_y = scene_info["x"], scene_info["y"]
        my_angle   = scene_info["angle"]
        pickups    = scene_info.get("pickups_info", [])
        enemies    = scene_info.get("competitor_info", [])
        walls      = scene_info.get("walls_info", [])

        target_pos = None

        # 1. İNTİKAM: Pickup çalındıysa hırsıza git
        if self.revenge_mode > 0:
            self.revenge_mode -= 1
            thief = next((e for e in enemies if e.get("id") == self.revenge_id), None)
            if thief:
                target_pos = (thief["x"], thief["y"])
            else:
                self.revenge_mode = 0

        # 2. Önceki pickup hâlâ orada mı?
        if not target_pos and self.target_pickup:
            pickup_still_here = any(
                p["x"] == self.target_pickup["x"] and p["y"] == self.target_pickup["y"]
                for p in pickups
            )
            if pickup_still_here:
                target_pos = (self.target_pickup["x"], self.target_pickup["y"])
            else:
                # Birisi aldı! En yakın düşman = hırsız
                if enemies:
                    thief = min(enemies, key=lambda e: math.hypot(
                        e["x"]-self.target_pickup["x"], e["y"]-self.target_pickup["y"]))
                    self.revenge_mode = 45
                    self.revenge_id = thief.get("id")
                    target_pos = (thief["x"], thief["y"])
                self.target_pickup = None

        # 3. Yeni hedef seç
        if not target_pos:
            if pickups:
                self.target_pickup = min(pickups, key=lambda p: math.hypot(p["x"]-my_x, p["y"]-my_y))
                target_pos = (self.target_pickup["x"], self.target_pickup["y"])
            elif enemies:
                t = min(enemies, key=lambda e: math.hypot(e["x"]-my_x, e["y"]-my_y))
                target_pos = (t["x"], t["y"])
            else:
                return ["FORWARD", "TURN_LEFT"]

        # 4. Hedefe hareket (duvar varsa alternatif açı)
        dx, dy = target_pos[0]-my_x, target_pos[1]-my_y
        dist = math.hypot(dx, dy)
        target_angle = math.degrees(math.atan2(dy, dx)) % 360

        if self._is_blocked(my_x, my_y, target_pos[0], target_pos[1], walls):
            for offset in [45, -45, 90, -90]:
                alt_ang = (target_angle + offset) % 360
                rad = math.radians(alt_ang)
                ax, ay = my_x + math.cos(rad)*100, my_y + math.sin(rad)*100
                if not self._is_blocked(my_x, my_y, ax, ay, walls):
                    target_angle = alt_ang
                    break

        diff = (target_angle - my_angle + 180) % 360 - 180
        if abs(diff) > 30:
            commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
        elif abs(diff) > 5:
            commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")
            commands.append("FORWARD")
        else:
            commands.append("FORWARD")

        # 5. Yakın düşman varsa ve nişan açısı uygunsa ateş et
        if scene_info.get("power", 0) > 0:
            for enemy in enemies:
                e_dist = math.hypot(enemy["x"]-my_x, enemy["y"]-my_y)
                if e_dist < 400 and enemy.get("is_visible", True):
                    e_angle = math.degrees(math.atan2(enemy["y"]-my_y, enemy["x"]-my_x)) % 360
                    e_diff = (e_angle - my_angle + 180) % 360 - 180
                    if abs(e_diff) < 20:
                        commands.append("SHOOT")
                        break

        return commands

    def reset(self):
        self.target_pickup = None
        self.revenge_mode  = 0
        self.revenge_id    = None

5. Kaçak Zigzag (Dodger)

Her 12 frame'de yön değiştirir, hayatta kalmayı önceliklendirir.

import math
import random

class MLPlay:
    def __init__(self, *args, **kwargs):
        self.frame_count = 0
        self.move_dir = 1  # +1 sol, -1 sağ

    def update(self, scene_info, *args, **kwargs):
        self.frame_count += 1
        commands = ["FORWARD"]  # Daima hareket et!

        # ZIG-ZAG: Her 12 frame'de yön değiştir (30% ihtimalle pas geç)
        if self.frame_count % 12 == 0:
            if random.random() > 0.3:
                self.move_dir *= -1
        commands.append("TURN_LEFT" if self.move_dir == 1 else "TURN_RIGHT")

        # Düşman yakınsa ve görünürse ateş et
        my_x, my_y = scene_info["x"], scene_info["y"]
        enemies = scene_info.get("competitor_info", [])
        if scene_info.get("power", 0) > 0:
            for enemy in enemies:
                if math.hypot(enemy["x"]-my_x, enemy["y"]-my_y) < 450 and enemy.get("is_visible", True):
                    commands.append("SHOOT")
                    break
            # Düşman yoksa %3 ihtimalle rastgele ateş (baskı)
            elif random.random() < 0.03:
                commands.append("SHOOT")

        # Kenarlara yaklaşınca merkeze dön
        margin = 120
        if (my_x < margin or my_x > 1000 - margin or
            my_y < margin or my_y > 700 - margin):
            dx, dy = 500 - my_x, 350 - my_y
            t_angle = math.degrees(math.atan2(dy, dx)) % 360
            diff = (t_angle - scene_info["angle"] + 180) % 360 - 180
            if abs(diff) > 10:
                commands = [c for c in commands if c not in ("TURN_LEFT", "TURN_RIGHT")]
                commands.append("TURN_RIGHT" if diff > 0 else "TURN_LEFT")

        return commands

    def reset(self):
        self.frame_count = 0

GPT/Claude'a Verebileceğin Prompt Şablonu

Bu belgeyi AI'ya verdikten sonra şu yazıyı ekleyerek algoritmayı yazdırabilirsin:

Yukarıdaki TankMan Arena dokümantasyonuna göre benim için bir MLPlay algoritması yaz.

Strateji isteğim:
- [Örnek: Düşmanların etrafında daire çizerek ateş etsin]
- [Örnek: Can düşünce önce HP pickup'ına koşsun]
- [Örnek: Duvarlara çarpmaktan kaçınsın]
- [Örnek: ... vb.]

Kodu sadece mlplay.py olarak yaz, import math ve class MLPlay yapısına uy.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages