Pacman en PHP CLI

Implementación del clásico Pacman en modo texto para ejecutar desde la terminal con PHP. Usa secuencias de escape ANSI para los colores y el posicionamiento del cursor, y pone el terminal en modo raw no bloqueante con stty. Compatible con Linux y macOS; requiere PHP 8.0+ en CLI.
				<?php
/**
 * pacman.php — Juego tipo Pacman en modo texto (CLI)
 *
 * Versión PHP del clásico Pacman en C (2003) de Dorian Butrón y Dr. Gustavo Calderón.
 * Usa secuencias de escape ANSI para color y posicionamiento del cursor.
 * Requiere PHP-CLI en Linux o macOS con terminal compatible con ANSI.
 *
 * Autor: David Carrero Fernandez-Baillo
 * Web:   https://carrero.es
 *
 * Requisitos: PHP 8.0+ CLI, terminal ANSI (Linux/macOS)
 * Ejecutar:   php pacman.php
 *
 * Versión C:      https://programacion.net/codigo/pacman_64
 * Versión Python: https://programacion.net/codigo/pacman-python_1894
 */

declare(strict_types=1);

const FILAS  = 10;
const COLS   = 20;
const DELAY  = 130_000;

define('ESC',      chr(27));
define('RESET',    ESC . "[0m");
define('AMARILLO', ESC . "[1;33m");
define('ROJO',     ESC . "[1;31m");
define('VERDE',    ESC . "[1;32m");

function limpiar(): void          { echo ESC . "[2J" . ESC . "[H"; }
function cursor(bool $v): void    { echo $v ? ESC . "[?25h" : ESC . "[?25l"; }

function generar_tablero(): array {
    $m = [];
    for ($i = 0; $i < FILAS; $i++)
        for ($j = 0; $j < COLS; $j++)
            $m[$i][$j] = '.';
    return $m;
}

function tablero_vacio(array $m): bool {
    foreach ($m as $fila)
        foreach ($fila as $celda)
            if ($celda === '.') return false;
    return true;
}

function dibujar(array $m, int $puntos): void {
    limpiar();
    echo VERDE . "Flechas=mover  ESC=salir  Puntos: " . ($puntos * 15) . RESET . "n";
    for ($i = 0; $i < FILAS; $i++) {
        for ($j = 0; $j < COLS; $j++) {
            $c = $m[$i][$j];
            echo match (true) {
                $c === '@'           => AMARILLO . '@' . RESET . ' ',
                $c === 1 || $c === 2 => ROJO     . 'M' . RESET . ' ',
                $c === 'X'           => ROJO     . 'X' . RESET . ' ',
                default              => $c . ' ',
            };
        }
        echo "n";
    }
}

function leer_tecla(): string {
    $c = fread(STDIN, 4);
    return ($c === false || $c === '') ? '' : $c;
}

function mensaje_fin(string $texto, string $color): void {
    limpiar();
    echo $color . "nn  " . $texto . RESET . "n";
    sleep(2);
}

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);

$m      = generar_tablero();
$py     = 0; $px = 0;
$m1y    = 0; $m1x = COLS - 1;
$m2y    = FILAS - 1; $m2x = COLS - 1;
$puntos = 0;

$m[$py][$px]   = '@';
$m[$m1y][$m1x] = 1;
$m[$m2y][$m2x] = 2;

while (true) {
    dibujar($m, $puntos);
    usleep(DELAY);

    $m[$m1y][$m1x] = ' ';
    $m[$m2y][$m2x] = ' ';

    if (tablero_vacio($m)) {
        mensaje_fin("*** ¡Ganaste! *** Puntos: " . ($puntos * 15), VERDE);
        exit(0);
    }

    $tecla = leer_tecla();
    if ($tecla !== '') {
        if ($tecla === ESC) { exit(0); }
        $m[$py][$px] = ' ';
        if     ($tecla === ESC . "[A" && $py > 0)        $py--;
        elseif ($tecla === ESC . "[B" && $py < FILAS - 1) $py++;
        elseif ($tecla === ESC . "[C" && $px < COLS - 1)  $px++;
        elseif ($tecla === ESC . "[D" && $px > 0)         $px--;
        if ($m[$py][$px] === '.') $puntos++;
        $m[$py][$px] = '@';
    }

    if (($m1x === $px && $m1y === $py) || ($m2x === $px && $m2y === $py)) {
        $m[$py][$px] = 'X';
        dibujar($m, $puntos);
        mensaje_fin("*** ¡Perdiste! *** Puntos: " . ($puntos * 15), ROJO);
        exit(0);
    }

    $m1x = rand(0, 1) ? min($m1x + 1, COLS - 1)  : max($m1x - 1, 0);
    $m1y = rand(0, 1) ? min($m1y + 1, FILAS - 1) : max($m1y - 1, 0);
    $m[$m1y][$m1x] = 1;

    $m2x = rand(0, 1) ? min($m2x + 1, COLS - 1)  : max($m2x - 1, 0);
    $m2y = rand(0, 1) ? min($m2y + 1, FILAS - 1) : max($m2y - 1, 0);
    $m[$m2y][$m2x] = 2;
}

			
Descargar adjuntos
COMPARTE ESTE TUTORIAL

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
TUTORIAL ANTERIOR

SIGUIENTE TUTORIAL