
방식
vlm_macro_client.py는 Qt 화면에 붙어 새 블록이 나올 때마다 한 번 묻습니다.
- 판을 칸당 20픽셀 그림으로 그립니다. 블록 종류마다 색이 다릅니다.
- 블록 이름(I, O, T…)과 함께 “평평하게, 구멍 없이, 줄을 지우도록 놓을 자리”를 묻습니다.
- 답은 target_rot(0~3)와 target_x(0~9) JSON입니다.
- 회전을 맞추고 x까지 옮긴 뒤 바로 떨어뜨립니다.
결과
같은 엔진에서 2판을 돌렸습니다.
- 블록 12개와 11개, 0줄, 구멍 50개와 46개
- 23번 물어 23번 모두 JSON 형식을 지켰습니다.
- target_x는 23번 모두 4였습니다. 회전만 1(17번)과 0(6번)으로 바뀌었습니다.
- 한 번 묻는 데 평균 5.7초 걸렸습니다.
결과는 매크로 DQN과 같습니다. 가운데에 탑을 쌓고 12개 안팎에서 끝납니다.
왜 x=4만 나오나
- 그림에 열 번호나 격자선이 없습니다. 20픽셀 칸을 세어 열을 알아내야 하는데 3B 모델에게는 어렵습니다. 오목에서도 VLM이 그림만 보고 좌표를 고르면 돌이 있는 자리를 자주 골랐습니다.
- 묻는 순간 새 블록은 숨은 줄에 있어서 그림에 보이지 않습니다. 블록은 이름으로만 알려 줍니다.
- 프롬프트는 target_x를 “열”이라고 설명하지만 엔진의 x는 4×4 상자의 왼쪽 끝입니다. 맞는 열을 골라도 세로 블록은 한두 칸 오른쪽에 떨어집니다. 3편의 맨 왼쪽 열 문제도 그대로 있습니다.
VLM에게 좌표를 지어내게 하는 대신, 놓을 수 있는 자리를 코드가 다 계산하고 고르기만 맡기는 쪽으로 바꿨습니다.
이 단계의 실제 코드
VLM에게 보내는 질문입니다.
vlm_macro_client.py
def get_macro_action(self, obs: np.ndarray, current_piece_name: str) -> tuple[int, int]:
img = _grid_to_image(obs)
prompt = (
"You are an expert Tetris AI.\n"
f"A new piece ({current_piece_name}) has just appeared at the top of the board.\n"
"Look at the current board state and decide the best final resting position for this piece.\n"
"Return your decision strictly as JSON with two keys:\n"
'- "target_rot": an integer from 0 to 3 representing the number of clockwise rotations.\n'
'- "target_x": an integer representing the target column (0-9 for a standard board, from left to right).\n'
"Try to keep the stack flat, avoid creating holes, and clear lines if possible.\n"
"Return ONLY the JSON string. Do not output anything else."
)새 블록이 나올 때 한 번 묻고, 그 뒤로는 목표까지 저수준 행동을 보냅니다.
vlm_macro_client.py
if piece_index > current_piece_index:
# New piece spawned. Ask VLM for macro action
piece_name = name_piece(piece_type)
print(f"\n--- New Piece Spawned: {piece_name} (Index: {piece_index}) ---")
current_piece_index = piece_index
target_rot, target_x = agent.get_macro_action(grid, piece_name)
target_x = max(0, min(target_x, w - 1))
print(f"VLM Decision -> Target Rot: {target_rot}, Target X: {target_x}")
# Translate target macro state to next micro action
micro = next_micro_for_target(piece_type, cur_rot, cur_x, target_rot, target_x)다음 글은 ‘5. 자리는 코드가 계산하고 LLM은 고르기만’입니다.
COMMENTS · CHAPTER 04
VLM에게 블록 자리를 직접 고르게 하기 댓글 0
아직 댓글이 없습니다. 읽다가 궁금한 점이나 보탤 내용을 남겨 주세요.
댓글을 등록하려면 구글로 시작하기를 눌러 닉네임과 메일 주소를 등록해 주세요.
구글로 시작하기