Skip to content

Instantly share code, notes, and snippets.

@vincent4vx
Last active December 16, 2015 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vincent4vx/5462513 to your computer and use it in GitHub Desktop.
Save vincent4vx/5462513 to your computer and use it in GitHub Desktop.
<?php
define('BASE', __DIR__.DIRECTORY_SEPARATOR);
/**
* @property-read Input $input
* @property-read Loader $loader
* @property-read Router $router
*/
class Core implements ArrayAccess{
/**
* @var Core
*/
private static $_instance = null;
private $vars=array();
private function __construct() {
self::$_instance = $this;
$autoload = array('Input', 'Router');
$this->loader = new Loader($autoload);
}
public function __get($name){
return isset($this[$name]) ? $this[$name] : null;
}
public function __isset($name) {
return isset($this[$name]);
}
public function __set($name, $value){
$this[$name] = $value;
}
public function offsetSet($offset, $value) {
$this->vars[$offset] = $value;
}
public function offsetGet($offset) {
return isset($this->vars[$offset]) ? $this->vars[$offset] : null;
}
public function offsetExists($offset) {
return isset($this->vars[$offset]);
}
public function offsetUnset($offset) {
unset($this->vars[$offset]);
}
public function execute(){
$function = $this->router->selectRoute();
$exec_param = array();
$reflec = new ReflectionFunction($function);
foreach($reflec->getParameters() as $param){
$value = $this->input->{$param->getName()};
if($value===false){
if($param->isDefaultValueAvailable())
$value = $param->getDefaultValue();
else
$value = null;
}
$exec_param[] = $value;
}
$reflec->invokeArgs($exec_param);
}
/**
* @return Core
*/
public static function instance(){
if(self::$_instance===null)
new self;
return self::$_instance;
}
}
abstract class Component{
/**
* @var Core
*/
private $_instance;
public function __construct() {
$this->_instance = Core::instance();
}
public function __get($name) {
return $this->_instance->$name;
}
public function __set($name, $value) {
$this->_instance->$name = $value;
}
}
class Loader extends Component{
public function __construct(array $autoload) {
parent::__construct();
foreach($autoload as $class)
$this->load($class);
}
public function get($class_name){
if($this->{strtolower($class_name)}===null)
$this->load($class_name);
return $this->{strtolower($class_name)};
}
public function load($name){
if(!class_exists($name)){
throw new Exception(<<<MSG
La classe "$name" n'existe pas, ou n'est pas encore incluse !
MSG
);
}
if($this->{strtolower($name)}!==null){
throw new Exception(<<<MSG
La class "$name" est déjà chargée !
MSG
);
}
$this->{strtolower($name)} = new $name;
}
}
class Router{
private $action = '';
private $_routes = array();
public function __construct() {
if(!($this->action=Core::instance()->input->action))
$this->action = 'layout';
}
public function register($name, callable $function){
$this->_routes[$name] = $function;
}
public function selectRoute(){
foreach($this->_routes as $name=>$function){
if((~$name & $this->action)===str_repeat(chr(0), strlen($this->action))){
return $function;
}
}
throw new Exception('Erreur 404');
}
}
class Cache{
const EXT = '.cache';
public function get($name){
$file = self::processName($name);
if(!file_exists($file))
return false;
$data = unserialize(file_get_contents($file));
if($data['destruct_time'] < time()){
unlink($file);
return false;
}
return $data['content'];
}
public function set($name, $value, $time = 60){
$file = self::processName($name);
if(!is_dir(dirname($file)))
mkdir(dirname ($file), 0777, true);
$data = array(
'content' => $value,
'destruct_time' => time() + $time
);
return file_put_contents($file, serialize($data));
}
private static function processName($name){
return BASE.'cache'.DIRECTORY_SEPARATOR.str_replace('.', DIRECTORY_SEPARATOR, $name).self::EXT;
}
}
class Input{
public function __get($name){
foreach($_GET + $_POST as $k => $v){
if(($k & $name)==$name)
return urldecode(trim($v));
}
return false;
}
}
class HtmlPage{
private $code = '';
public function addContent($content){
$this->code.=$content;
return $this;
}
public function __toString() {
return $this->code;
}
}
class HtmlTag{
private $content = '';
private $name = '';
private $attributes = array();
public function __construct($name, array $attributes = array()){
$this->name = $name;
$this->attributes = $attributes;
}
public function addContent($content){
$this->content.=$content;
return $this;
}
public function __toString() {
$open = '<'.$this->name.' ';
foreach($this->attributes as $name=>$value){
if(is_numeric($name))
$open.=$value.' ';
else
$open.=$name.'="'.addslashes($value).'" ';
}
$open.='>';
$close = '</'.$this->name.'>';
return $open.$this->content.$close;
}
}
class Invader{
private static $pattern = [
[0, 0, 1, 0, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 0, 1, 0],
[0, 1, 0, 1, 0, 1, 0],
[1, 1, 1, 1, 1, 1, 1],
[1, 0, 1, 0, 1, 0, 1]
];
private $color;
private $eyes = array();
public function __construct() {
$rand = new Rand(12);
$this->color = $rand->nextInt(0, 0xFFFFFF);
$this->eyes = array_fill(0, 6, array_fill(0, 7, 0));
$this->eyes[$rand->nextInt(2, 3)][2] = 1;
$this->eyes[$rand->nextInt(2, 3)][4] = 1;
}
/**
* @return Mapper
*/
public function getMap($size_x, $size_y){
$rand = new Rand(12);
$map = new Mapper($size_x, $size_y);
$pos_x = $rand->nextInt(0, $size_x - count(self::$pattern[0]));
$pos_y = $rand->nextInt(0, $size_y - count(self::$pattern));
$map->fill(self::$pattern, $this->color, $pos_x, $pos_y);
$map->fill($this->eyes, 0, $pos_x, $pos_y);
return $map;
}
}
class Mapper{
private $map;
private $X;
private $Y;
public function __construct($x, $y){
$this->map = array_fill(0, $y, array_fill(0, $x, null));
$this->X = $x;
$this->Y = $y;
}
public function fill(array $pattern, $color, $x_pos, $y_pos){
foreach($pattern as $y => $row){
foreach($row as $x => $fill){
if($fill)
$this->map[($y_pos + $y) % $this->Y][($x_pos + $x) % $this->X] = $this->intToHexColor($color);
}
}
}
private function intToHexColor($i){
$hex = dechex($i);
while(strlen($hex) < 6){
$hex = '0'.$hex;
}
return '#'.$hex;
}
public function toJSON(){
return json_encode($this->map);
}
}
class Rand{
private $current = 0;
private $values = array();
public function __construct($advence = 623){
$this->values[] = microtime(true);
for($i = 1; $i < $advence; $i++){
$v = 1812433253 * ($this->values[$i - 1] ^ (($this->values[$i - 1]) >> 30 )) + 1;
$v = decbin($v);
while(strlen($v) < 32){
$v = '0'.$v;
}
$this->values[] = bindec(substr($v, strlen($v) - 32));
}
}
private function generate(){
foreach($this->values as $i => $value){
$y = ($value & 0x80000000) + ($this->values[($i + 1) % count($this->values)] & 0x7fffffff);
$this->values[$i] = $this->values[($i + 397) % count($this->values)] ^ ($y >> 1);
if(($y % 2)!==0){
$this->values[$i] = $this->values[$i] ^ 2567483615;
}
}
}
public function getNext(){
if($this->current === 0)
$this->generate();
$value = $this->values[$this->current];
$value ^= ($value >> 11);
$value ^= (($value << 7) & 2636928640);
$value ^= (($value << 15) & 4022730752);
$value ^= ($value >> 18);
$this->current = ($this->current + 1) % count($this->values);
return $value;
}
public function nextInt($min = 0, $max = null){
if(!$max)
$max = self::max_value();
$value = $this->getNext() % ($max + 1);
while($value < $min){
$value = ($value + $min) % ($max + 1);
}
return $value;
}
public static function max_value(){
return pow(2, 32) - 1;
}
}
$core = Core::instance();
set_exception_handler(function(Exception $e){
echo '<pre>', $e, '</pre>';
exit;
});
$core->router->register(
'layout',
function($size_x = 40, $size_y = 30, $speed = 1500) use($core){
$size_x = abs((int)$size_x);
$size_y = abs((int)$size_y);
$speed = abs((int)$speed);
if(!($data=$core->loader->get('Cache')->get('layout'))){
$data = new HtmlPage();
$head = new HtmlTag('head');
$x = (100 / $size_x) - 1;
$y = (100 / $size_y) - 1;
$head->addContent((new HtmlTag('style'))->addContent(<<<TXT
div{
margin: 1px;
width: $x%;
height: $y%;
padding: 3px;
display: inline-block;
}
TXT
));
$head->addContent((new HtmlTag('script', array('type'=>'text/javascript')))->addContent(<<<SCRIPT
var X = $size_x;
var Y = $size_y;
window.setTimeout(loadInvader, 1000);
function loadInvader(){
xhr = new XMLHttpRequest();
xhr.open("GET", "index.php?action=invader&size_x=" + X + "&size_y=" + Y, false);
xhr.send(null);
fillPage(JSON.parse(xhr.responseText));
window.setTimeout(loadInvader, $speed);
}
function fillPage(map){
for(var y in map){
for(var x in map[y]){
var id = "block_" + x + "_" + y;
document.getElementById(id).style.background = map[y][x];
}
}
}
SCRIPT
));
$data->addContent($head);
$body = new HtmlTag('body');
for($y = 0; $y < $size_y; $y++){
for($x = 0; $x < $size_x; $x++){
$id = 'block_'.$x.'_'.$y;
$body->addContent((new HtmlTag('div', array('id'=>$id)))->addContent(' '));
}
$body->addContent('<br/>');
}
$data = (string)$data->addContent($body);
$core->cache->set('layout.'.$size_x.'x'.$size_y.'@'.$speed, $data, 3600);
}
echo $data;
}
);
$core->router->register('invader', function($size_x = 40, $size_y = 30){
$invader = new Invader;
echo $invader->getMap(abs((int)$size_x), abs((int)$size_y))->toJSON();
});
$core->execute();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment