Skip to content

Instantly share code, notes, and snippets.

@tvlooy
Created October 7, 2020 15:34
Show Gist options
  • Save tvlooy/d1f27d5be7a6ac9076333fee00bdfb06 to your computer and use it in GitHub Desktop.
Save tvlooy/d1f27d5be7a6ac9076333fee00bdfb06 to your computer and use it in GitHub Desktop.
sfmatrix - simulates the display from "The Matrix"
#!/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