# 15가지 규칙

> 모두 실제 대전에서 부딪히며 얻은 규칙입니다. Bot을 작성할 때 한 번씩 대조해 보면 디버깅 시간을 대부분 아낄 수 있습니다.

출처: https://war3ai.com/ko/docs/rules/

> **팁**
>
> 이 페이지를 [`api.json`](https://war3ai.com/ko/api.json)과 함께 LLM에 건네면, 훨씬 덜 헤매는 Bot을 작성합니다.

## 상태 읽기

### 1. 읽을 수 없으면 0이 아니라 `None`

`resources()`, `time_of_day()`, `production()`, `cooldown()`은 모두 `None`을 반환할 수 있습니다(로딩 중, 유닛에 세부 정보가 없음, 건물이 생산 중이 아님……). 먼저 확인하고 사용하세요.

```python
res = g.resources()
if res is None:
    return
```

### 2. 유닛은 주소가 아니라 핸들로 식별하기

주소는 새 유닛이 재사용합니다. 예전 주소가 새로 태어난 유닛을 가리킬 수 있습니다. 여러 틱에 걸쳐 특정 유닛을 기억하려면 `u.handle`을 저장하고 `g.unit(handle)`로 다시 찾으세요.

### 3. 이벤트 스트림은 전역입니다

`production.done`, `unit.died`에는 상대와 크립의 이벤트도 들어 있습니다. `ev.owner`(또는 건물 핸들)로 필터링하세요.

```python
if ev.kind == "production.done" and ev.owner == g.me():
    ...
```

### 4. 금광에 들어간 일꾼은 스냅샷에 없습니다

일꾼은 금광에 들어가는 순간 스냅샷에서 사라집니다(`unit.removed`이며, 죽은 것이 아님). 금광마다 인원을 집계하려면 **직접 기록**하고, 스냅샷에 없다고 장부에서 지우지 마세요. 그러지 않으면 이미 가득 찬 금광에 일꾼을 더 보내게 됩니다.

## 명령 내리기

### 5. 회신 "수락" ≠ 완료

숲속 건설 지점도 엔진은 그 자리에서 수락하고, 일꾼이 도착해서야 실패합니다. 스킬은 끊길 수 있습니다. 효과는 스냅샷과 이벤트로 확인하세요. 건물은 `build_near`로 짓고(건설 부지가 나타나는지 추적함), 스킬은 `g.cooldown()`이 쿨다운에 들어갔는지 봅니다.

### 6. 보이지 않는 대상은 공격할 수 없습니다

전장의 안개 속 적에게 대상 지정 명령을 내리면 사유 코드 **1001**로 거부됩니다. 안개 속 적을 쫓으려면 마지막으로 보였던 위치로 `attack_move`하세요.

### 7. 쉬고 있는 유닛에게만 명령하기

매 틱 같은 유닛에게 같은 명령을 다시 내리면 동작이 끊깁니다. 병력은 제자리에서 버벅이고, 일꾼의 채집 주기는 처음부터 다시 시작됩니다. "쉬고 있는지"는 `g.order_of(u)`(이번 틱에 방금 내린 명령 포함)로 판단하고, 스냅샷의 `u.order`(스냅샷이 아직 따라잡지 못함)는 쓰지 마세요.

### 8. Shift는 "현재 명령 바로 뒤에 끼워 넣기"만 됩니다

엔진에는 "맨 끝에 추가"가 없습니다. `queue='after'`로 B, C를 연달아 보내면 A, C, B가 됩니다. 여러 지점을 순서대로 돌려면 `g.path(units, 지점 목록)`을, 일꾼 한 명이 여러 채를 연속으로 지으려면 `g.build_queue(worker, 계획)`을 쓰세요. 둘 다 역순으로 끼워 넣어 순서를 알아서 맞춰 줍니다.

### 9. 한 틱의 명령은 한 배치로

명령 수십 개를 하나씩 보내면 게임 스레드를 수십 번 기다려야 합니다. `with g.batch():`로 감싸면 한 번만 기다립니다.

## 경제와 생산

### 10. 금광 하나에 일꾼은 최대 5명

더 늘려도 수입이 늘지 않습니다. 일꾼 목표는 금광 수에 맞춥니다. 금광마다 채금 5명에 벌목 몇 명을 더합니다.

### 11. 훈련 대기열에는 1개만

7칸을 다 채우면 돈이 대기열에 묶입니다(실측: 본진 건물에 일꾼 4명을 예약해 금 300이 묶였고, 초반이 크게 느려졌음). `g.queue(b)`가 비면 다음 것을 넣으세요.

### 12. 식량 막힘은 생산 테이블로 확인하기

`g.production(b).blocked` = 대기열에 있지만 시작되지 않음이며, 대개 식량 부족이 원인입니다. "식량이 거의 찼을 때 짓기"보다 한발 빠릅니다. 교전으로 병력을 한꺼번에 잃고 보충하다가 대기열이 막히면 바로 알 수 있습니다.

### 13. 영웅은 유일하고, 본진 대기열이 비어 있지 않으면 티어 업 불가

- 영웅이 죽으면 `g.revive(제단)`으로만 되살릴 수 있고, 다시 훈련하면 거부됩니다(221). 부활에도 식량이 필요합니다(영웅은 5).
- 본진 건물 대기열에 무언가 남아 있으면 본진 건물을 업그레이드할 수 없습니다(사유 코드 185, "건물이 사용 중").

## 시간과 공간

### 14. 2배속에서는 실제 시간으로 기다리지 않기

게임 시간 3초를 기다리려면 `sleep(1.5)`가 아니라 `g.clock()`이 3 늘었는지 보세요. 배속에서는 엔진 시계가 실제 시간보다 빨리 흐릅니다.

### 15. 섬 맵과 숲 맵에서는 직선 거리를 쓰지 않기

크립 캠프나 멀티 자리를 고를 때는 `g.path_distance(a, b)`(지상 A*, 숲·절벽·건물을 우회)를 쓰세요. 갈 수 없으면 `None`을 반환합니다. 직선으로 가장 가까운 지점이 바다 건너편일 수도 있습니다.

## 하나 더: 공정 모드 기준으로 작성하기

`--fair`에서는 시야 안의 유닛, 아이템, 생산, 이벤트만 보이며, 아레나 규칙도 이와 같습니다. 지금부터 공정 모드 기준으로 작성하면 나중에 [아레나](https://war3ai.com/ko/arena/)에 올라갈 때 고칠 필요가 없습니다. 자세한 내용은 [공정 모드](https://war3ai.com/ko/docs/fair-mode/)를 참고하세요.
