"""
tetris.py Juego Tetris en modo texto
Versión Python del clásico Tetris de Víctor Barbero (2001).
Usa el módulo curses de la biblioteca estándar.
Autor: David Carrero Fernandez-Baillo
Web: https://carrero.es
Requisitos: Python 3.8+, módulo curses (incluido en la biblioteca estándar)
- Linux/macOS: sin dependencias adicionales
- Windows: pip install windows-curses
Controles: ? ? mover ? rotar ? bajar Espacio caída rápida ESC salir
Ejecutar: python tetris.py
Versión Pascal original: https://programacion.net/codigo/tetris_63
Versión PHP: https://programacion.net/codigo/tetris-php_1895
"""
import curses
import random
import time
FILAS = 20
COLS = 10
FORMAS = [
[(0,0),(0,1),(0,2),(0,3)], # I
[(0,0),(0,1),(1,0),(1,1)], # O
[(0,0),(0,1),(0,2),(1,1)], # T
[(0,1),(0,2),(1,0),(1,1)], # S
[(0,0),(0,1),(1,1),(1,2)], # Z
[(0,0),(1,0),(1,1),(1,2)], # J
[(0,2),(1,0),(1,1),(1,2)], # L
]
def rotar(forma):
rotada = [(dc, -dr) for dr, dc in forma]
min_r = min(r for r, _ in rotada)
min_c = min(c for _, c in rotada)
return [(r - min_r, c - min_c) for r, c in rotada]
def valida(tablero, forma, pr, pc):
for dr, dc in forma:
r, c = pr + dr, pc + dc
if r < 0 or r >= FILAS or c < 0 or c >= COLS or tablero[r][c]:
return False
return True
def colocar(tablero, forma, pr, pc, color):
for dr, dc in forma:
tablero[pr + dr][pc + dc] = color
def limpiar_lineas(tablero):
nuevas = [fila for fila in tablero if not all(fila)]
n = FILAS - len(nuevas)
for _ in range(n):
nuevas.insert(0, [0] * COLS)
tablero[:] = nuevas
return n
def nueva_pieza():
idx = random.randrange(len(FORMAS))
return list(FORMAS[idx]), idx + 1
def dibujar(ven, tablero, forma, pr, pc, color, sig_forma, sig_color, puntos, nivel, lineas):
ven.erase()
try:
ven.addstr(0, 0,
f"? ? mover ? rotar ? bajar Espacio: caída ESC: salir "
f"Puntos:{puntos} Nivel:{nivel} Lineas:{lineas}",
curses.color_pair(8) | curses.A_BOLD)
ven.addstr(FILAS + 1, 0, '+' + '--' * COLS + '+')
for r in range(FILAS):
ven.addch(r + 1, 0, '|')
ven.addch(r + 1, COLS * 2 + 1, '|')
for r in range(FILAS):
for c in range(COLS):
if tablero[r][c]:
ven.addstr(r + 1, c * 2 + 1, '[]',
curses.color_pair(tablero[r][c]) | curses.A_BOLD)
else:
ven.addstr(r + 1, c * 2 + 1, '. ')
for dr, dc in forma:
r, c = pr + dr, pc + dc
if 0 <= r < FILAS and 0 <= c < COLS:
ven.addstr(r + 1, c * 2 + 1, '[]', curses.color_pair(color) | curses.A_BOLD)
ven.addstr(2, COLS * 2 + 3, 'Sig:', curses.color_pair(8))
for dr, dc in sig_forma:
ven.addstr(3 + dr, COLS * 2 + 3 + dc * 2, '[]',
curses.color_pair(sig_color) | curses.A_BOLD)
except curses.error:
pass
ven.refresh()
def jugar(ven):
curses.curs_set(0)
ven.nodelay(True)
curses.start_color()
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK) # I
curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK) # O
curses.init_pair(3, curses.COLOR_MAGENTA, curses.COLOR_BLACK) # T
curses.init_pair(4, curses.COLOR_GREEN, curses.COLOR_BLACK) # S
curses.init_pair(5, curses.COLOR_RED, curses.COLOR_BLACK) # Z
curses.init_pair(6, curses.COLOR_BLUE, curses.COLOR_BLACK) # J
curses.init_pair(7, curses.COLOR_WHITE, curses.COLOR_BLACK) # L
curses.init_pair(8, curses.COLOR_GREEN, curses.COLOR_BLACK) # HUD
tablero = [[0] * COLS for _ in range(FILAS)]
forma, color = nueva_pieza()
sig_forma, sig_color = nueva_pieza()
pr, pc = 0, COLS // 2 - 2
puntos = 0
nivel = 1
lineas = 0
ultimo = time.time()
while True:
retardo = max(0.1, 0.5 - (nivel - 1) * 0.04)
dibujar(ven, tablero, forma, pr, pc, color, sig_forma, sig_color, puntos, nivel, lineas)
tecla = ven.getch()
if tecla == 27:
return
elif tecla == curses.KEY_LEFT and valida(tablero, forma, pr, pc - 1):
pc -= 1
elif tecla == curses.KEY_RIGHT and valida(tablero, forma, pr, pc + 1):
pc += 1
elif tecla == curses.KEY_UP:
rot = rotar(forma)
if valida(tablero, rot, pr, pc):
forma = rot
elif tecla == curses.KEY_DOWN and valida(tablero, forma, pr + 1, pc):
pr += 1
elif tecla == ord(' '):
while valida(tablero, forma, pr + 1, pc):
pr += 1
if time.time() - ultimo >= retardo:
ultimo = time.time()
if valida(tablero, forma, pr + 1, pc):
pr += 1
else:
colocar(tablero, forma, pr, pc, color)
n = limpiar_lineas(tablero)
lineas += n
puntos += [0, 100, 300, 500, 800][n] * nivel
nivel = lineas // 10 + 1
forma, color = sig_forma, sig_color
sig_forma, sig_color = nueva_pieza()
pr, pc = 0, COLS // 2 - 2
if not valida(tablero, forma, pr, pc):
dibujar(ven, tablero, forma, pr, pc, color,
sig_forma, sig_color, puntos, nivel, lineas)
ven.nodelay(False)
try:
ven.addstr(FILAS // 2, 2, f"GAME OVER Puntos: {puntos}",
curses.color_pair(5) | curses.A_BOLD)
except curses.error:
pass
ven.refresh()
ven.getch()
return
time.sleep(0.02)
if __name__ == '__main__':
curses.wrapper(jugar)
Tetris en Python con curses
Tetris en modo texto para terminal, escrito en Python con el módulo curses de la biblioteca estándar. Incluye las siete piezas con rotación, eliminación de líneas, puntuación, niveles progresivos y muestra la siguiente pieza. Funciona en Linux y macOS sin instalar nada; en Windows solo requiere windows-curses.
Descargar adjuntos
COMPARTE ESTE TUTORIAL
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP