Skip to content

Instantly share code, notes, and snippets.

@BEcraft
Last active August 15, 2019 01:55
Show Gist options
  • Save BEcraft/f3e5ea7a58d0376dab3f53ac49f9c7de to your computer and use it in GitHub Desktop.
Save BEcraft/f3e5ea7a58d0376dab3f53ac49f9c7de to your computer and use it in GitHub Desktop.
Un simple concepto de logros en PHP
<?php declare(strict_types = 1);
namespace Logros;
use ReflectionFunction, Exception, OutOfRangeException, ArrayObject;
###############################################################
# > Ejemplo simple de un sistema de logros por BEcraft. #
###############################################################
# > Clase principal para los logros:
abstract class Logro
{
protected $evento, $ejecutor, $descripcion, $configuracion;
public function __construct(array $datos = [], callable $ejecutor, string $descripcion)
{
$this->validarEjecutor($ejecutor);
$this->ejecutor = $ejecutor;
$this->descripcion = $descripcion;
$this->configuracion = new Configuracion($datos);
}
public function validarEjecutor(callable $ejecutor): void
{
$parametros = (new ReflectionFunction($ejecutor))->getParameters();
if (count($parametros) < 2)
{
throw new OutOfRangeException("El número de parametros dado en el ejecutor ha de ser mayor a 1.");
}
$secuencia = ["Logros\Evento", "Logros\Configuracion"]; //Clases
foreach ($secuencia as $i => $tipo)
{
$parametro = (string) $parametros[$i]->getType();
if ( ! (class_exists($parametro, false)) || ! (is_a($parametro, $tipo, true)))
{
throw new Exception("No se ha podido encontrar una relacion de \"{$tipo2}\" con la clase {$tipo}.");
}
$secuencia[$i] = $parametro;
}
$this->evento = $secuencia[0];
}
public function procesarEvento(Evento $evento): void
{
if ($this->Completado() || get_class($evento) !== $this->evento)
{
return;
}
if (($respuesta = ($this->ejecutor)($evento, $this->configuracion)) === 0)
{
return;
}
$this->configuracion->Progreso($respuesta);
}
public function Completado(): bool
{
return ($this->configuracion->Progreso() >= 100);
}
public function GuardarLogro(int $banderas = 0): string
{
return json_encode($this->configuracion, ($banderas | JSON_PRETTY_PRINT));
}
public function Descripcion(): string
{
return $this->descripcion;
}
}
# > Logro #1:
class SaludarLogro extends Logro
{
public function __construct(array $datos = [])
{
parent::__construct($datos, function (HablarEvento $evento, Configuracion $configuracion) {
if (strtolower($evento->Mensaje()) !== "hola")
{
return 0;
}
return 100;
}, "Escribe \"Hola\"");
}
}
# > Logro #2:
class ContarHastaCinco extends Logro
{
public function __construct(array $datos = [])
{
parent::__construct($datos, function (HablarEvento $evento, Configuracion $configuracion) {
$numero = (int) $evento->Mensaje();
$conteo = (int) $configuracion->offsetGet("conteo");
if (++$conteo === $numero)
{
$configuracion->offsetSet("conteo", $numero); return (($numero / 5) * 100);
}
return 0;
}, "¡Debes contar hasta 5!");
}
}
# > Almacenamiento para los datos del logro, puede ser un arreglo cualquiera.
class Configuracion extends ArrayObject
{
public function __construct(array $datos)
{
parent::__construct($datos, ArrayObject::ARRAY_AS_PROPS);
}
public function Progreso(?float $progreso = null): float
{
if ($progreso === null)
{
return (float) ($this->offsetGet("progreso") ?? 0);
}
$this->offsetSet("progreso", $progreso); return 0;
}
}
# > Inicio de simulación de eventos:
class HablarEvento extends Evento
{
private $mensaje;
public function __construct(Usuario $usuario, string $mensaje)
{
parent::__construct($usuario);
$this->mensaje = $mensaje;
}
public function Mensaje(): string
{
return $this->mensaje;
}
}
abstract class Evento
{
protected $usuario;
public function __construct(Usuario $usuario)
{
$this->usuario = $usuario;
}
public function Usuario(): Usuario
{
return $this->usuario;
}
}
# > Fin de simulación de eventos.
class Usuario
{
protected $nombre;
public function __construct(string $nombre)
{
$this->nombre = $nombre;
}
public function Nombre(): string
{
return $this->nombre;
}
}
$logros = [new SaludarLogro(), new ContarHastaCinco()]; # > Puedes crear una clase de trabaje con los logros.
$usuario = new Usuario("Edita");
$guardado = [];
echo "Logros disponibles: " . PHP_EOL;
foreach ($logros as $logro)
{
echo get_class($logro) . " -> " . $logro->Descripcion() . PHP_EOL;
}
# > Método solo de prueba.
function procesar()
{
global $logros, $usuario, $guardado;
while(count($logros) > 0)
{
$evento = new HablarEvento($usuario, trim(fgets(STDIN)));
# > Ejemplo de como se guardan los logros:
if ($evento->Mensaje() === "guardar")
{
# > Al guardar el logro:
foreach ($logros as $logro)
{
$guardado[get_class($logro)] = $logro->GuardarLogro();
}
$logros = [];
echo "Logros guardados: " . implode(", ", array_map(function ($i) use ($guardado) {
return key($guardado) . " -> " . $i; next($guardado);
}, $guardado)) . PHP_EOL;
# > Al cargar el logro:
foreach ($guardado as $i => $datos)
{
$logros[] = new $i(json_decode($datos, true));
}
$guardado = [];
return procesar();
}
# > Procesar el evento:
foreach ($logros as $i => $logro)
{
$logro->procesarEvento($evento);
if ($logro->Completado())
{
echo("[¡] Se ha completado el logro " . get_class($logro) . PHP_EOL); unset($logros[$i]);
}
}
}
}
procesar();
if ($logros === [])
{
echo "¡Felicidades " . $usuario->Nombre() . ", has completado todos los logros!" . PHP_EOL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment