Created
October 7, 2020 15:34
-
-
Save tvlooy/d1f27d5be7a6ac9076333fee00bdfb06 to your computer and use it in GitHub Desktop.
sfmatrix - simulates the display from "The Matrix"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env php | |
<?php | |
require __DIR__.'/vendor/autoload.php'; | |
use Symfony\Component\Console\Cursor; | |
use Symfony\Component\Console\Input\InputInterface; | |
use Symfony\Component\Console\Output\OutputInterface; | |
use Symfony\Component\Console\SingleCommandApplication; | |
use Symfony\Component\Console\Terminal; | |
define('SPEED', 25000); | |
(new SingleCommandApplication()) | |
->setCode(function (InputInterface $input, OutputInterface $output) { | |
$terminal = new Terminal(); | |
$width = $terminal->getWidth(); | |
$height = $terminal->getHeight(); | |
$cursor = new Cursor($output); | |
$cursor->hide(); | |
$cursor->clearScreen(); | |
// Make background black | |
for ($row = 0; $row < $height; $row++) { | |
for ($col = 0; $col < $width; $col++) { | |
$cursor->moveToPosition($col, $row); | |
$output->write('<bg=#000000> </>'); | |
} | |
} | |
// Keep used columns locked to avoid overwrite | |
$lockedX = []; | |
$traces = []; | |
while (true) { | |
// Maintain a certain amount of active traces | |
while (count($traces) < round($width * 0.7)) { | |
// Generate start coordinates | |
$x = array_rand(array_diff(range(0, $width - 1), $lockedX)); | |
$lockedX[] = $x; | |
$y = rand(0, $height - 5); | |
// Generate random code for the trace | |
$code = []; | |
$length = rand(5, round(($height - $y - 1) * 0.7)); | |
for ($i = 0; $i < $length; $i++) { | |
$code[] = chr(rand(33, 49)); | |
// $code[] = mb_chr(rand(12448, 12543)); | |
} | |
$traces[] = new Trace( | |
$output, | |
$cursor, | |
$x, | |
$y, | |
$code | |
); | |
} | |
foreach ($traces as $i => $trace) { | |
$trace->write(); | |
// Cleanup erased traces | |
if (! $trace->visible()) { | |
unset($lockedX[array_search($trace->x(), $lockedX)]); | |
unset($traces[$i]); | |
} | |
} | |
usleep(SPEED); | |
} | |
return 0; | |
})->run(); | |
class Trace | |
{ | |
private OutputInterface $output; | |
private Cursor $cursor; | |
private int $x; | |
private int $y; | |
private array $code; | |
private int $lenght; | |
private int $offset; | |
public function __construct(OutputInterface $output, Cursor $cursor, int $x, int $y, array $code) | |
{ | |
$this->output = $output; | |
$this->cursor = $cursor; | |
$this->x = $x; | |
$this->y = $y; | |
$this->code = $code; | |
$this->length = count($code); | |
$this->offset = 0; | |
} | |
public function write(): void | |
{ | |
$this->offset++; | |
for ($y = $this->y, $code = 0; $y < $this->y + $this->offset; $y++, $code++) { | |
$this->cursor->moveToPosition($this->x, $y); | |
// Code is printed, erase first character | |
if ($code == $this->offset - $this->length) { | |
$this->output->write('<bg=#000000> </>'); | |
continue; | |
} | |
// Code is printed | |
if ($code >= count($this->code)) { | |
continue; | |
} | |
// Print previous character green | |
if ($code === $this->offset - 2) { | |
$this->output->write('<fg=#00ff00;bg=#000000>'.$this->code[$code].'</>'); | |
continue; | |
} | |
// Print first character white | |
if ($code === $this->offset - 1) { | |
$this->output->write('<fg=#ffffff;bg=#000000>'.$this->code[$code].'</>'); | |
} | |
} | |
} | |
public function x(): int | |
{ | |
return $this->x; | |
} | |
public function visible(): bool | |
{ | |
return $this->length > $this->offset - $this->length; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment