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.
- Genel Konsept
- Arena ve Oyun Sabitleri
- MLPlay Sınıfı — Zorunlu Yapı
- scene_info — Bilgi Paketi
- Komutlar — Ne Yapabilirsin?
- Oyun Mekaniği
- Açı Hesaplama Rehberi
- Görüş Hattı (LOS)
- Kaynak Yönetimi (HP & Yakıt & Mermi)
- Harita Editörü & Duvarlar
- Örnek Algoritmalar
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 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 = 0sol kenar,x = 1000sağ kenary = 0üst kenar,y = 700alt kenar- Açılar
0° = sağ (doğu),90° = aşağı (güney),180° = sol (batı),270° = yukarı (kuzey)
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 = 0update(scene_info) fonksiyonuna gelen scene_info, her tankın kendi bakış açısından hazırlanan bir Python sözlüğüdür.
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ı
},
# ...
]
}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))
...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. |
- 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ımda0.1yakıt tüketir. Yakıt 0'a düşünce hareket edemezsn, ateş etmeye devam edebilirsin.
- 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.
- 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ı).
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).
- 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.
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°= Sol270°= 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 commandsdef 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 commandscompetitor_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 = Falseiken ateş etmek mermini boşa harcar. Duvarlardan yansıyan mermileri hesaba katmak istiyorsan kendi yansıma hesabını yapman gerekir.
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ş etHaritaya 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
}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
breakclass 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):
passHedefe 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 = 0Kaynakları ö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):
passHem 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 = NoneHer 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 = 0Bu 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.