§ 1Mutable Wrapper: global 대체
global 키워드가 안 되므로, 리스트로 값을 감싼다.
패턴: Mutable Wrapper
# global 없이 상태 공유 _SV = [None] # visited 맵 _MZ_H = [[]] # 드론 핸들 _phase = [""] # 현재 단계 _spawn_i = [0] # 스폰 인덱스 _FE = [None] # 현재 엔티티 # 사용 _phase[0] = "plant" _SV[0][x][y] = True me = _spawn_i[0] _spawn_i[0] = _spawn_i[0] + 1
직관
리스트는 mutable이다.
_phase = [""]는 리스트 객체를 만들고, _phase[0] = "plant"는 리스트의 내용을 수정한다. 변수 자체를 재할당하는 게 아니라, 리스트 내용을 바꾸는 것이므로 global이 필요 없다.
§ 2인라인 수학: tuple 회피
튜플 언패킹이 안 되므로, 모든 좌표 계산을 인라인으로 한다:
인라인 방향 계산
nx = x
ny = y
if di == 0:
ny = (y + 1) % WORLD_SIZE
elif di == 1:
nx = (x + 1) % WORLD_SIZE
elif di == 2:
ny = (y - 1) % WORLD_SIZE
else:
nx = (x - 1) % WORLD_SIZE
주의
nx, ny = nb_pos(x, y, d) 같은 헬퍼 함수를 쓰고 싶겠지만, 튜플 반환→튜플 언패킹이 모두 금지되어 있다. 인라인 if/elif 체인이 유일한 방법이다.
§ 3방향 상수 규칙
can_move(0)은 크래시. 반드시 can_move(North)를 사용해야 한다.
하지만 정수 연산으로 방향을 관리해야 할 때가 있다. 해결: DIRS = [North, East, South, West] 배열을 만들고 DIRS[di]로 변환한다.
DIRS 배열 패턴
DIRS = [North, East, South, West] # 정수로 계산 back = (di + 2) % 4 # 반대 방향 # 상수로 사용 can_move(DIRS[di]) move(DIRS[back])
§ 4for 루프 함정
for i in range(N): ...; i += 2는 i를 건너뛰지 않는다! Python의 for는 range 이터레이터에서 매 반복마다 i를 덮어쓴다.
해결: range(start, end, step)을 사용하거나, i * step 공식을 사용한다.
for 루프 함정 vs 올바른 패턴
STEP 01 / 4
§ 5버그 카탈로그
실제로 겪은 버그들. 모두 "조용히 실패"하는 것들이다.
| 버그 | 원인 | 해결 |
|---|---|---|
| 드론이 (0,0)에서 멈춤 | tuple 언패킹 | 인라인 수학 |
| 함수가 실행 안 됨 | global 키워드 | [value] 래퍼 |
| 모든 드론이 같은 열 | 공유 카운터 레이스 | 클로저 팩토리 |
| can_move() 크래시 | 정수 방향 | DIRS[idx] 상수 |
| for 루프 스킵 안 됨 | i += 무시됨 | range(step) 사용 |
| 리스트 인덱스 에러 | [None]*N 실패 | 명시적 for+append |
| harvest 타이밍 | while 안에 harvest | while 밖으로 이동 |
핵심
이 게임에서 디버깅은 print() 하나다. 에러 메시지가 없으므로, 의심되는 지점에 print()를 넣고 출력이 나오는지 확인하는 것이 유일한 방법이다. "조용한 실패"가 가장 위험한 적이다.