mover ^ rotar v bajar Espacio caida rapida ESC salir
* Ejecutar: php tetris.php
*
* Version Pascal original: https://programacion.net/codigo/tetris_63
* Version Python: https://programacion.net/codigo/tetris-python_1896
*/
declare(strict_types=1);
const FILAS = 20;
const COLS = 10;
define('ESC', chr(27));
define('RESET', ESC . "[0m");
define('VERDE', ESC . "[1;32m");
define('COLORES', [
'',
ESC . "[1;36m", // 1 I - cyan
ESC . "[1;33m", // 2 O - yellow
ESC . "[1;35m", // 3 T - magenta
ESC . "[1;32m", // 4 S - green
ESC . "[1;31m", // 5 Z - red
ESC . "[1;34m", // 6 J - blue
ESC . "[1;37m", // 7 L - white
]);
const FORMAS = [
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[0,1],[1,0],[1,1]],
[[0,0],[0,1],[0,2],[1,1]],
[[0,1],[0,2],[1,0],[1,1]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[1,0],[1,1],[1,2]],
[[0,2],[1,0],[1,1],[1,2]],
];
function limpiar(): void { echo ESC . "[2J" . ESC . "[H"; }
function cursor(bool $v): void { echo $v ? ESC . "[?25h" : ESC . "[?25l"; }
function rotar(array $f): array {
$r = array_map(fn($c) => [$c[1], -$c[0]], $f);
$minR = min(array_column($r, 0));
$minC = min(array_column($r, 1));
return array_map(fn($c) => [$c[0] - $minR, $c[1] - $minC], $r);
}
function valida(array $board, array $f, int $pr, int $pc): bool {
foreach ($f as [$dr, $dc]) {
$r = $pr + $dr; $c = $pc + $dc;
if ($r < 0 || $r >= FILAS || $c < 0 || $c >= COLS || $board[$r][$c]) return false;
}
return true;
}
function colocar(array &$board, array $f, int $pr, int $pc, int $col): void {
foreach ($f as [$dr, $dc]) $board[$pr + $dr][$pc + $dc] = $col;
}
function limpiarLineas(array &$board): int {
$nuevas = array_values(array_filter($board, fn($f) => in_array(0, $f, true)));
$n = FILAS - count($nuevas);
$board = array_merge(array_fill(0, $n, array_fill(0, COLS, 0)), $nuevas);
return $n;
}
function dibujar(array $board, array $f, int $pr, int $pc, int $col,
array $sf, int $sc, int $puntos, int $nivel, int $lineas): void {
limpiar();
echo VERDE . "<- -> mover ^ rotar v bajar Espacio: caida ESC: salir " .
"Puntos:$puntos Nivel:$nivel Lineas:$lineas" . RESET . "n";
$vista = $board;
foreach ($f as [$dr, $dc]) {
$r = $pr + $dr; $c = $pc + $dc;
if ($r >= 0 && $r < FILAS && $c >= 0 && $c < COLS) $vista[$r][$c] = $col;
}
echo '+' . str_repeat('--', COLS) . "+n";
foreach ($vista as $fila) {
echo '|';
foreach ($fila as $v) echo $v ? (COLORES[$v] . '[]' . RESET) : '. ';
echo "|n";
}
echo '+' . str_repeat('--', COLS) . "+n";
echo "n" . VERDE . "Sig:n" . RESET;
$maxR = max(array_column($sf, 0));
$maxC = max(array_column($sf, 1));
for ($r = 0; $r <= $maxR; $r++) {
for ($c = 0; $c <= $maxC; $c++) {
$ok = false;
foreach ($sf as [$dr, $dc]) if ($dr === $r && $dc === $c) { $ok = true; break; }
echo $ok ? (COLORES[$sc] . '[]' . RESET) : ' ';
}
echo "n";
}
}
function leerTecla(): string {
$c = fread(STDIN, 4);
return ($c === false || $c === '') ? '' : $c;
}
function nuevaPieza(): array {
$idx = array_rand(FORMAS);
return [FORMAS[$idx], $idx + 1];
}
register_shutdown_function(function(): void {
system('stty sane');
cursor(true);
echo RESET . "n";
});
cursor(false);
system('stty -icanon -echo min 0 time 0');
stream_set_blocking(STDIN, false);
$board = array_fill(0, FILAS, array_fill(0, COLS, 0));
[$forma, $color] = nuevaPieza();
[$sf, $sc] = nuevaPieza();
$pr = 0; $pc = (int)(COLS / 2) - 2;
$puntos = 0; $nivel = 1; $lineas = 0;
$ultimo = microtime(true);
while (true) {
$retardo = max(0.1, 0.5 - ($nivel - 1) * 0.04);
dibujar($board, $forma, $pr, $pc, $color, $sf, $sc, $puntos, $nivel, $lineas);
usleep(50_000);
$tecla = leerTecla();
if ($tecla === ESC) { exit(0); }
elseif ($tecla === ESC . "[D" && valida($board, $forma, $pr, $pc - 1)) $pc--;
elseif ($tecla === ESC . "[C" && valida($board, $forma, $pr, $pc + 1)) $pc++;
elseif ($tecla === ESC . "[A") {
$rot = rotar($forma);
if (valida($board, $rot, $pr, $pc)) $forma = $rot;
}
elseif ($tecla === ESC . "[B" && valida($board, $forma, $pr + 1, $pc)) $pr++;
elseif ($tecla === " ") { while (valida($board, $forma, $pr + 1, $pc)) $pr++; }
if (microtime(true) - $ultimo >= $retardo) {
$ultimo = microtime(true);
if (valida($board, $forma, $pr + 1, $pc)) {
$pr++;
} else {
colocar($board, $forma, $pr, $pc, $color);
$n = limpiarLineas($board);
$lineas += $n;
$puntos += [0, 100, 300, 500, 800][$n] * $nivel;
$nivel = intdiv($lineas, 10) + 1;
[$forma, $color] = [$sf, $sc];
[$sf, $sc] = nuevaPieza();
$pr = 0; $pc = (int)(COLS / 2) - 2;
if (!valida($board, $forma, $pr, $pc)) {
dibujar($board, $forma, $pr, $pc, $color, $sf, $sc, $puntos, $nivel, $lineas);
echo COLORES[5] . "n GAME OVER Puntos: $puntos" . RESET . "n";
sleep(3);
exit(0);
}
}
}
}
Tetris en PHP CLI
Tetris en modo texto para ejecutar desde la terminal con PHP. Implementa las siete piezas cl谩sicas con rotaci贸n, eliminaci贸n de l铆neas, niveles de dificultad progresivos y puntuaci贸n. Usa secuencias ANSI para los colores y stty para el modo raw no bloqueante. Requiere PHP 8.0+ en Linux o macOS.
Descargar adjuntos
COMPARTE ESTE TUTORIAL
COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP