완전한 월드 상태, 대기 없음
플레이어 16명의 자원과 식량, 최대 1024개 유닛의 체력/마나, 오더, 공격 대상, 스킬 쿨다운, 버프, 인벤토리, 바닥 아이템, 나무, 생산 대기열, 낮과 밤. 런타임이 공유 메모리에 푸시하며, 한 번 읽는 데 약 0.4 ms입니다.
War3AI는 게임을 Agent를 위한 인터페이스로 바꿉니다. 50 ms마다 맵 전체의 완전한 상태를 푸시하고, 시맨틱 명령은 약 1프레임 만에 반영되며, 모든 명령에 회신과 사유 코드가 있습니다. 문서를 Claude, GPT, Gemini, Qwen 등 어떤 Agent에게든 건네세요. Bot을 작성하고, 대전에 나가고, 결과를 읽고, 스스로 개선합니다.
Windows 10/11 · 워크래프트 III 1.27a · start.bat을 더블클릭하면 나머지는 자동 설치
휴먼. 영웅 체력이 40% 아래로 떨어지면 본진으로 후퇴. 밤이 되면 병력이 3기 이상일 때 가장 가까운 크립 캠프를 공격.
llms.txt와 api.json을 읽고 night_raider.py를 생성했습니다. 검증된 API 8개만 사용합니다.
from openwar3 import Bot
class NightRaider(Bot):
def on_tick(self, g): # 초당 약 5회
halls = g.my_buildings({"htow", "hkee", "hcas"})
army, camps = g.my_army(), g.creeps()
if not halls:
return
home = halls[0]
with g.batch(): # 이번 틱의 명령을 한 번에 제출
for h in g.my_heroes():
if h.hp < h.hp_max * 0.4: # 영웅 생존
g.move(h, home.x, home.y)
if g.is_night() and len(army) >= 3 and camps:
camp = min(camps, key=lambda c: g.path_distance(home, c) or 1e9)
g.attack_move(army, camp.x, camp.y) # 밤에 크립 사냥
def on_event(self, g, ev):
if ev.kind == "production.done" and ev.owner == g.me():
print("완료", ev.done_code, f"{ev.value:.1f}s") 코드를 작성하거나 JSON을 출력할 수 있는 모든 모델·Agent와 호환
수치는 1.27 테스트 인스턴스에서 실게임으로 측정한 값(2026-09-23 / 24)이며, 측정 방법은 플랫폼 · 성능에 있습니다.
프로그래밍을 몰라도 괜찮습니다. 여러분은 어떻게 싸우길 원하는지 분명히 말하고, Agent는 코드를 쓰고, 대전에 나가고, 결과를 보고, 만족할 때까지 고칩니다.
“휴먼, 아크메이지 먼저. 병영 두 개에서 보병과 소총병. 병력 12기가 모이면 상대 멀티 공격. 영웅 체력이 30% 아래면 후퇴.”
llms.txt, api.json, 매뉴얼을 건네세요. API는 게임 속 명칭(4자리 코드, 스킬 이름)을 쓰므로 모델이 바로 이해합니다.
tools/play.py가 게임 실행, 주입, 게임 시작, Bot 실행까지 처리합니다. 배속, 종족, 난이도, 공정 모드는 모두 파라미터입니다.
모든 명령에 회신과 사유 코드가 있고, 이벤트 스트림은 모든 피해, 처치, 생산을 기록합니다. Agent는 이를 근거로 문제를 찾고, 코드를 고치고, 한 판 더 합니다.
관찰은 대기 없이, 명령에는 회신이, 결과는 이벤트로. 모델에게 필요한 것은 바로 이렇게 구조화되고, 검증 가능하며, 스스로 오류를 고칠 수 있는 피드백입니다.
플레이어 16명의 자원과 식량, 최대 1024개 유닛의 체력/마나, 오더, 공격 대상, 스킬 쿨다운, 버프, 인벤토리, 바닥 아이템, 나무, 생산 대기열, 낮과 밤. 런타임이 공유 메모리에 푸시하며, 한 번 읽는 데 약 0.4 ms입니다.
이동, 공격, 채집, 건설, 훈련, 시전, 스킬 습득, 부활, 아이템 사용, 구매…… 수락됐는지, 왜 거부됐는지를 같은 프레임에 알려 줍니다.
유닛 등장 / 사망, 오더 변경, 영웅 레벨 업, 아이템 등장. 엔진 수준의 모든 피해(출처, 공격 유형, 방어력 적용 전 피해)와 생산 완료. 상대의 것도 포함됩니다.
with g.batch() 안의 명령을 한 배치로 모아 제출합니다. 실측 결과 이동 명령 8개가 68 ms에서 6.5 ms로 줄었습니다.
stats / time_to_kill은 게임 자체 상성표와 실시간 기술 레벨을 사용하고, path_distance / walk_path는 엔진 지형 그리드에서 A*를 실행합니다.
시야 안의 유닛, 아이템, 생산, 이벤트만 보입니다. last_seen은 전장의 안개 속 적을 기억합니다. 아레나 규칙도 이와 같습니다.
api.json은 코드에서 생성되며, 모든 API에 실측 상태, 지연 등급, 내부 메커니즘이 표시되어 있어 모델이 추측할 필요가 없습니다. llms.txt / llms-full.txt로 Agent가 사이트 전체 문서를 한 번에 읽습니다.
런타임이 원본 게임에 주입되어 게임 스레드에서 월드 전체를 수집하고, 명령을 실행하고, 결과를 보고합니다. 여러분의 AI는 버전이 붙은 W3P 프로토콜로 런타임과 대화합니다. Python SDK를 써도 되고, 공유 메모리를 읽고 쓸 수 있는 어떤 언어를 써도 됩니다.
파사드는 클래스 두 개뿐입니다. Bot은 틱을, Game은 보기와 실행을 맡습니다. 유닛은 4자리 코드로, 스킬은 오더 이름으로 지정하며 게임 속 명칭과 같습니다.
None queue='after' from openwar3 import Bot
class FocusFire(Bot):
"""가장 가까운 적이 아니라 '가장 빨리 잡을 수 있는' 적을 점사하고, 체력 낮은 병력은 본진으로 뺀다."""
def on_tick(self, g):
army, halls = g.my_army(), g.my_buildings()
foes = [e for e in g.enemies(fighters_only=True) if e.visible_to(g.me())]
if not army or not foes or not halls:
return
home = halls[0]
# 상성표, 방어력, 공격/방어 업그레이드, 대상의 실시간 체력까지 계산
target = min(foes, key=lambda e: g.time_to_kill(army, e) or 1e9)
with g.batch(): # 명령이 수십 개여도 게임 스레드는 한 번만 대기
for u in army:
if u.hp < u.hp_max * 0.35:
g.move(u, home.x, home.y) # 체력 낮은 유닛 빼기
elif (t := g.current_target(u)) is None or t.handle != target.handle:
g.attack(u, target) # 대상을 공격하고 있지 않은 유닛에게만 명령 brains/examples/micro_bot.py에 있습니다(점사, 체력 낮은 유닛 빼기, 영웅 생존, 밤에 크립 사냥). 워크래프트 III 1.27용 AI(Python)를 작성해 주세요. api.json에 나열된 Game 메서드만 사용하고,
존재하지 않는 메서드를 지어내지 마세요. openwar3.Bot을 상속해 on_start(g)와 on_tick(g)를 구현하세요.
규칙:
- on_tick은 초당 약 5회 호출되므로 빨라야 합니다(안에서 sleep하지 마세요).
- 읽을 수 없는 값은 0이 아니라 None입니다. 먼저 확인하고 사용하세요.
- 명령은 회신을 반환합니다. `if r:`이면 엔진이 수락한 것이고, 거부되면 r.reason에 이유가 적혀 있습니다.
- 특정 적을 공격할 때는 g.attack(병력, 적)을 쓰세요. 보이지 않는 대상은 거부됩니다(1001).
- 영웅이 죽으면 g.revive(제단)으로 부활시키세요. 새로 훈련할 수는 없습니다.
- 한 틱에 명령을 많이 내릴 때는 with g.batch(): 안에 넣으세요.
내가 원하는 전략:
휴먼. 시작하면 일꾼 5명은 금 채집, 1명은 벌목. 아크메이지 먼저. 병영 두 개에서 보병과 소총병.
병력 12기가 모이면 영웅과 함께 상대 멀티를 공격. 영웅 체력이 30% 아래면 본진으로 후퇴. >>> r = g.train(barracks, "hfoo")
>>> bool(r), r.reason
(False, 'rejected(人口不够)')
>>> r = g.attack(footmen, grunt_in_fog)
>>> r.verdict, r.reason
(1001, 'rejected(目标看不见(在迷雾/黑区里))')
>>> r = g.move(footmen, 1200, -800)
>>> bool(r), r.exec_us # 이 명령이 게임 스레드에서 쓴 마이크로초
(True, 6)
>>> g.can_do(altar, "Hamg") # 명령 전에 엔진에 먼저 질의: 185 = 제단에서 영웅 부활 중
185 // 심판이 매 틱 Bot에게 보내는 관찰(Bot의 시야 안에 있는 것만 포함)
{"t": "obs", "tick": 57, "gameMs": 11400, "me": 1,
"res": {"gold": 320, "lumber": 150, "food": [18, 30]},
"units": [
{"id": 101, "type": "hfoo", "owner": 1,
"x": -4500, "y": 2200, "hp": 380, "hpMax": 420}],
"visibleEnemies": [
{"id": 733, "type": "ogru", "owner": 2,
"x": -3900, "y": 2500, "hp": 700}],
"deadlineMs": 180}
// Bot이 돌려주는 행동(어떤 언어, 어떤 모델이든 생성 가능)
{"t": "act", "tick": 57, "actions": [
{"do": "attack", "unit": 101, "target": 733},
{"do": "train", "unit": 5, "code": "hfoo"},
{"do": "cast", "unit": 7, "spell": "thunderbolt", "target": 733}]} 다섯 가지는 지금 바로 쓸 수 있고, 하나는 개발 중입니다. 서로 배타적이지 않습니다. 한 게임 안에서 Agent가 작성한 Bot이 실행하고, 로컬 모델이 참모를 맡고, 또 다른 모델이 유닛 대사를 맡고, 여러분은 Claude Code에서 언제든 한마디 끼어들 수 있습니다.
Claude Code, Cursor, Codex, ChatGPT…… 문서를 읽고 bot.py를 작성하고, 대전에서 회신과 이벤트를 보고 다시 고칩니다. 가장 빠른 입문 방법이며 프로그래밍을 몰라도 됩니다.
몇 게임초마다 한 페이지 분량의 게임 상황을 모델에 넘기고 엄격한 JSON을 받습니다. 진단, 일꾼 배분, 생산 우선순위, 이번 1분의 운영 방침. 규칙 레이어의 화이트리스트 + 클램핑을 거쳐 실행합니다.
어떤 유닛이든, 어떤 신분으로든 머리 위에 말풍선을 띄우고 로컬 LLM의 스트리밍 출력을 연결합니다. 일꾼 수다 모임, 영웅 대화, 전황 해설.
Claude Code, Claude Desktop 또는 MCP를 지원하는 어떤 클라이언트든 서버 하나를 연결하면, LLM이 직접 게임 상황을 보고, 명령을 내리고, 화면에서 플레이어에게 말하고, 카드를 띄워 플레이어에게 묻고, 스크린숏으로 화면을 봅니다. 코드를 먼저 쓸 필요가 없습니다.
WebSocket / JSON 게이트웨이가 공개 API를 그대로 밖으로 내보냅니다. JS, C#, Go, 브라우저 페이지, 다른 컴퓨터의 프로그램 모두 게임 상황을 보고, 명령을 내리고, 이벤트를 구독하고, 게임에 버튼을 놓을 수 있습니다. 선수 역할은 자기 유닛만 지휘하고 자기 시야만 봅니다.
아레나: 심판이 시야 기준으로 관찰을 필터링하고, 유닛 소유권을 검증하고, 게임 시간에 맞춰 틱을 진행해, 외부 AI 두 개가 같은 게임에서 승부를 가리게 합니다. 어떤 언어든, 어떤 모델이든 직접 대전할 수 있습니다.
화면 위에 나만의 UI를 그리면 그 버튼은 클릭되고 단축키는 반응합니다. 맵 제작자가 쓰는 함수 전부를 외부에서 호출하고, RPG 맵에서 함께 싸워 줄 AI 동료를 곁에 두세요. 새로운 게임 방식 하나를 통째로 모드로 작성하면, AI 스킴처럼 클릭 한 번으로 전환하고 손쉽게 공유할 수 있습니다.
텍스트 상자, 패널, 진행 바, 이미지, 지형에 붙는 원, 화살표가 달린 경로. 유닛을 따라다니며 CJK 폰트, 둥근 모서리, 반투명을 마음대로 정할 수 있습니다. 내 화면에만 그리므로 멀티플레이 게임에서도 안전합니다.
맵 제작자가 쓸 수 있는 함수를 이름으로 바로 호출합니다. 유닛 생성, 이펙트, 패널, 대화 상자, 사운드, 카메라, 전장의 안개…… Farsight 콘솔, 명령줄, HTTP, Python 어디서든 쓸 수 있고, 채팅 명령, 버튼 메뉴, 방향키도 연결됩니다.
여러분을 따라다니며 사냥을 돕고, 체력이 낮으면 치유해 주고, 말동무가 되어 줍니다. 대사는 로컬 LLM에 연결할 수 있습니다. 동맹, 내 유닛, 맵 유닛 인수, 말만 하기의 네 가지 형태가 있으며, 커스텀 유닛의 이름은 맵에서 바로 읽어 옵니다.
AI 하나가 폴더 하나입니다. 클릭 한 번으로 전환하며, 진행 중인 게임도 다른 AI에게 넘길 수 있습니다. zip으로 내보내면 그대로 공유되고, 다른 사람의 스킴은 신뢰를 확인한 뒤 실행합니다. 스킴마다 전적이 자동으로 집계됩니다.
화면에 그린 버튼과 선택 카드를 클릭할 수 있고, 마우스를 올리면 자동으로 강조됩니다. 단축키를 등록하고, 지면을 클릭해 위치를 고르고, 마우스가 가리키는 곳을 읽습니다. 플레이어가 무엇을 선택했는지, 어떤 스킬을 썼는지, 채팅에 무엇을 입력했는지 모두 이벤트 스트림에 들어옵니다. 버튼은 마우스 포인터 아래에 그려지며, 버튼을 누른 클릭은 게임에 전달되지 않습니다.
여러분이 직접 플레이하고, 모드가 과제를 냅니다. 시작 배치, 시간에 따른 몬스터 생성, 레벨 업 때 셋 중 하나 고르기, 단축키로 웨이브 부르기, 지면을 클릭해 탑 세우기, 승패 판정. openwar3.Mod를 상속해 함수 몇 개만 쓰면 됩니다. 영웅 로그라이크와 무한 디펜스, 두 가지 예제가 내장되어 있습니다.
프로세스 간 통신 자체는 느리지 않습니다. 느린 것은 “요청 하나마다 메시지 펌프를 한 번 기다리는 것”과 “시스템 전체에 걸린 락 하나”입니다. 고속 레인은 클라이언트마다 레인 하나를 독점하게 하고, 락 없이 게임 스레드의 이벤트 디스패치 안에서 배치로 실행합니다.
게임을 띄우고 AI의 생각을 들여다보는 것부터 복기와 방송 해설까지, 모두 준비된 도구가 있습니다.
P0 ~ P3, P5, 게임플레이 확장, 게이트웨이와 MCP는 이미 1.27에서 동작합니다. 다음은 다중 버전 지원과 아레나입니다.
로컬, LAN, 직접 만든 게임에서만 사용합니다. 디스크의 Game.dll을 수정하지 않고, 블리자드 파일을 배포하지 않으며(게임 데이터는 여러분의 게임에서 추출), Battle.net이나 안티치트가 있는 어떤 서버에서도 사용할 수 없습니다.