게임 인터페이스 — 알고리즘 vs 게임 분리
"같은 코드로 여러 게임"이 가능하려면 알고리즘과 게임을 분리해야 함.
📖 핵심 아이디어 — 인터페이스
알고리즘 측이 알아야 할 게임 정보:
- 현재 상태에서 가능한 수의 리스트
- 수를 두면 다음 상태
- 현재 상태가 종료인지
- 종료라면 누가 이김 (1, -1, 0)
- 현재 상태를 신경망 입력으로 변환
이 5개 함수만 있으면 알고리즘 동작. "게임 = 5개 함수의 묶음".
🎯 의사 코드 — Game 인터페이스
class Game:
def possible_moves(self):
"""가능한 수의 리스트"""
...
def play(self, move):
"""수를 두고 다음 상태 반환"""
...
def is_terminal(self):
"""게임 끝났나"""
...
def winner(self):
"""승자 (1 / -1 / 0)"""
...
def to_input(self):
"""신경망 입력 (numpy array)"""
...
# 게임마다 이 인터페이스 구현:
class GoGame(Game): ...
class ChessGame(Game): ...
class ShogiGame(Game): ...
class TicTacToeGame(Game): ...
# 알고리즘은 게임에 무관:
def mcts(game, net): ... # 모든 Game에 동작
def self_play(game, net): ... # 모든 Game에 동작
def train(games_data, net): ... # 모든 Game에 동작
💡 객체지향 설계의 힘
같은 코드로 여러 게임을 가능하게 하는 건 "인터페이스 기반 설계":
- 알고리즘 측: "Game이라는 추상 타입을 받음"
- 게임 측: "Game을 구현하면 자동으로 알고리즘에 호환"
- 새 게임 추가: 인터페이스만 구현하면 끝
이게 좋은 SW 설계의 본질이고 AlphaZero의 일반성의 비결.
📊 입력의 게임별 차이
- 바둑: 19x19x17 (현재 차례 8수 + 상대 8수 + 차례 표시)
- 체스: 8x8x119 (12 기물 종류 × 8수 + 추가 정보)
- 쇼기: 9x9x362 (14 기물 종류 × 8수 + 손에 든 기물 등)
입력 채널은 게임마다 다름. 그러나 신경망은 같은 구조 (잔차 39블록 등). 출력 크기만 게임마다 (361+1 vs 4672 vs 11259).