
Método
vlm_macro_client.py se conecta a la pantalla de Qt y pregunta una vez cada vez que aparece una pieza nueva.
- Dibuja el tablero como una imagen de 20 píxeles por casilla. Cada tipo de pieza tiene un color distinto.
- Junto con el nombre de la pieza (I, O, T…), pregunta por "un sitio donde colocarla plana, sin huecos y de forma que se borren líneas".
- La respuesta es un JSON con target_rot (0~3) y target_x (0~9).
- Ajusta el giro, desplaza la pieza hasta x y la deja caer de golpe.
Resultados
Jugamos 2 partidas en el mismo motor.
- 12 y 11 piezas, 0 líneas, 50 y 46 huecos
- Se le preguntó 23 veces y respetó el formato JSON las 23 veces.
- target_x fue 4 las 23 veces. Solo cambió el giro, entre 1 (17 veces) y 0 (6 veces).
- Cada pregunta tardó 5.7 segundos de media.
El resultado es el mismo que el del DQN de macroacciones. Construye una torre en el centro y termina en torno a las 12 piezas.
¿Por qué solo sale x=4?
- La imagen no tiene números de columna ni líneas de cuadrícula. Para saber la columna hay que contar casillas de 20 píxeles, y eso es difícil para un modelo de 3B. También en el gomoku, cuando el VLM elegía coordenadas mirando solo la imagen, a menudo elegía sitios ya ocupados.
- En el momento de preguntar, la pieza nueva está en las filas ocultas y no aparece en la imagen. La pieza solo se indica por su nombre.
- El prompt describe target_x como una "columna", pero la x del motor es el borde izquierdo de una caja de 4×4. Aunque elija la columna correcta, las piezas verticales caen una o dos casillas más a la derecha. El problema de la columna de más a la izquierda de la entrada 3 también sigue ahí.
En lugar de dejar que el VLM se invente las coordenadas, cambiamos a que el código calcule todos los sitios posibles y al modelo solo le quede elegir.
El código real de esta etapa
Esta es la pregunta que se envía al 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."
)Pregunta una vez cuando aparece una pieza nueva y, a partir de ahí, envía acciones de bajo nivel hasta llegar al objetivo.
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)La siguiente entrada es "5. El código calcula los lugares y el LLM solo elige".
COMMENTS · CHAPTER 04
Dejar que el VLM elija directamente el lugar de la pieza 0 comentarios
Todavía no hay comentarios. Deja una pregunta o algo que quieras añadir.
Para publicar un comentario, empieza con Google y registra un apodo y un correo.
Empezar con Google