Location: PHPKode > scripts > PHP Mud Names > mudnames.php
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; expandtab -*- */
/**
 *  This code was inspired by MudNames by Ragnar Hojland Espinosa. <ragnar (at) ragnar-hojland (dot) com>
 *  This php version was written by Xrogaan. <xrogaan - gmail - com>
 *
 * @author xrogaan <xrogaan - gmail - com> (c) 2009
 * @license http://opensource.org/licenses/mit-license.php MIT license
 * @version 1.4
 */


class Mudnames_Dictionnaries {

    protected $_directory;
    protected $_dictionnaries = array();
    protected $_dictionnaries_instance = array();

    /**
     * Capability : different possibilities of connection between several particles
     */
    private $_caplist = array(
        "PS", "PMS", "PM", "N", "X",
        "NA", "XA" , "NX"
    );

    public $_actions = array();

    /**
     * Build a list of files as dictionnaries list.
     *
     * @param string $directory directory where the dictionnaries can be found
     */
    public function __construct($directory='./data/') {
        if (!file_exists($directory)) {
            throw new InvalidArgumentException ('Directory \''. $directory . '\' doesn\'t exists.');
        }

        if (!is_dir($directory)) {
            throw new InvalidArgumentException ('Directory \''. $directory . '\' isn\'t a directory.');
        }

        $this->_directory = $directory;

        $dh = opendir($this->_directory);
        while(false !== ($file = readdir($dh))) {
            if ($file[0] == '.' || substr($file,-4) == '.cap') {
                continue;
            }
            $this->_dictionnaries[$file] = $this->_directory . $file;
        }
        closedir($dh);
        ksort($this->_dictionnaries);
    }

    /**
     * Return true if the dictionnary file exists. If not, return false.
     *
     * @param string $name dictionnary name
     * @return boolean
     */
    public function dictionnary_exists($name) {
        return array_key_exists($name, $this->_dictionnaries);
    }

    /**
     * Check if a dictionnary object is already loaded into memory.
     *
     * @param string $name
     * @return boolean
     */
    public function opened_dictionnary($name) {
        return isset($this->_dictionnaries_instance[$name]);
    }

    /**
     * Open a dictionnary object and return its instance.
     *
     * @param string $name
     * @return Mydnames_Dictionnary
     */
    public function open_dictionnary($name='random') {
        
        if (self::opened_dictionnary($name)) {
            return $this->_dictionnaries_instance[$name];
        }

        switch ($name) {
            case '':
            case 'random':
                $keys = array_keys($this->_dictionnaries);
                $name = $keys[rand(0,count($keys)-1)];
            default:
                if (!self::dictionnary_exists($name)) {
                    throw new UnexpectedValueException("Dictionnary '$name' doesn't exists.");
                }
        }
        $this->_dictionnaries_instance[$name] = new Mudnames_Dictionnary($this->_dictionnaries[$name]);

        $this->_actions['dictionnaries'][$name]['capabilities'] = $this->_dictionnaries_instance[$name]->get_file_capability_list();
        $this->_actions['dictionnaries'][$name]['file'] = $this->_dictionnaries_instance[$name]->__toString();
        $this->_actions['dictionnaries'][$name]['is_forced'] = $this->_dictionnaries_instance[$name]->is_forced();

        return $this->_dictionnaries_instance[$name];
    }

    public function get_name($dictionnary) {
        $current_cap = $this->_dictionnaries_instance[$dictionnary]->select_capability();

        switch ($current_cap) {
            case 'N':
                $capability = 'NN';
                break;
            case 'X':
                $capability = 'XX';
                break;
            case 'XA':
                $capability = 'N' . (rand(0,1) ? 'A' : 'X' );
                break;
            case 'NX':
                $capability = (rand(0, 1) ? 'N' : 'A') . 'A';
                break;
            default:
                $capability = $current_cap;
        }

        $name = '';
        for ($i = 0, $len = strlen($capability); $i < $len; $i++) {
            $particle = $this->_dictionnaries_instance[$dictionnary]->plite2full($capability[$i]);
            $name.= $this->_dictionnaries_instance[$dictionnary]->random_particle_from($particle);
        }

        $name = ucfirst($name);
        $this->_actions['dictionnaries'][$dictionnary]['generated'][$name] = array (
            'capability' => $capability,
            'particles' => $particle
        );

        return $name;
    }

    /**
     * Return a list of files indexed by their basename
     *
     * @return array
     */
    public function get_dictionnaries_list() {
        return $this->_dictionnaries;
    }

    public function get_name_informations($dico, $name) {
        if (!isset($this->_action['dictionnaries'][$dico]['generated'][$name])) {
            return false;
        }
        return $this->_actions['dictionnaries'][$dico]['generated'][$name];
    }

    public function get_file_informations($file) {
        return $this->_actions['dictionnaries'][$file];
    }
}

class Mudnames_Dictionnary {
    /**
     * Name's Particles
     * Currently used : PRE, MID, SUF.
     */
    private $_particle = array(
        'PRE' => 'P',  'MID' => 'M',  'SUF'  => 'S',
        'NOUN' => 'N', 'ADJ' => 'A',  'NADJ' => 'X',
    );

    protected $capabilities = array();
    protected $dictionnary_name;

    /**
     * true if the capabilities isn't random
     * @var boolean
     */
    protected $forcedcap;

    /**
     * Capabilities if forced.
     */
    protected $forced_capability;
    
    /**
     * File's particles list.
     * @var array
     */
    protected $file_particles = array();

    public $debug;

    private $filename;

    public function __construct($filename) {
        if (file_exists($filename)) {
            $this->filename = $filename;
        } else {
            throw new InvalidArgumentException('File <em>' . $filename . '</em> not found');
        }

        $line = 0;
        $handle = @fopen($this->filename, 'r');

        if ($handle === false) {
            throw new RuntimeException('Can not open file ' . $this->filename . '.');
        }

        while (!feof($handle)) {
            $line++;
            $buffer = fgets($handle, 4096);
            if (strpos($buffer,'#') === 0) {
                $current_part = ltrim(rtrim($buffer,"\r\n"),'#');
                if (array_key_exists($current_part,$this->_particle)) {
                    $this->file_particles[$current_part] = array();
                } else {
                    trigger_error ($this->filename . ":$line: Unknow particle '$current_part'.", E_USER_WARNING);
                }
            } elseif (strlen($buffer) > 1 && strpos($buffer,'-----') === false) {
                $this->file_particles[$current_part][] = rtrim($buffer,"\r\n");
            } elseif (strlen($buffer) === 1) {
                continue;
            }
        }
        fclose($handle);

        self::set_capabilities();
    }

    public function set_capabilities() {
        // Build the acronym to know the capacity of the file.
        $check_particle = array_map(array($this, 'pfull2lite'), array_keys($this->file_particles));
        
        if (in_array('P', $check_particle) && in_array('S', $check_particle)) {
            $this->capabilities[] = 'PS';
            if (in_array('M', $check_particle)) {
                $this->capabilities[] = 'PMS';
            }
        }

        if (in_array('N', $check_particle) && in_array('A', $check_particle)) {
            $this->capabilities[] = 'NA';
        }

        if (in_array('N', $check_particle) && in_array('X', $check_particle)) {
            $this->capabilities[] = 'NX';
        }

        if (in_array('X', $check_particle) && in_array('A', $check_particle)) {
            $this->capabilities[] = 'XA';
        }

        if (in_array('N', $check_particle)) {
            $this->capabilities[] = 'N';
        }

        if (in_array('X', $check_particle)) {
            $this->capabilities[] = 'X';
        }
    }

    /**
     * Détecte si un fichier doit avoir une génération statique de noms.
     */
    function force_capability($cap) {
        if (in_array($cap,$this->capabilities)) {
            $this->currentcap = $cap;
            $this->forcedcap = true;
            return true;
        }
        return false;
    }
    
    /**
     * Sélectionne une association de capacité de façons aléatoire et la retourne.
     */
    public function select_capability() {

        self::check_cap_file();

        // If a forced capability exists, we apply it.
        if (!empty($this->forced_capability)) {
            foreach ($this->forced_capability as $fnct => $args) {
                if ($fnct == 'void') {
                    self::force_capability($args);
                } else {
                    call_user_func_array(array($this,$fnct),$args);
                }
            }
        }

        if (!$this->forcedcap) {
            if (count($this->capabilities)>1) {
                $this->currentcap = $this->capabilities[rand(0, count($this->capabilities) - 1)];
            } elseif (count($this->capabilities) == 1) {
                $this->currentcap = $this->capabilities[0];
            } else {
                trigger_error ($this->directory.$this->file . ":select_capability: No capability found.",E_USER_WARNING);
            }
        }

        return $this->currentcap;
    }

    /**
     * Check if a capability file is present for the current file.
     *
     * If it's present, its content is loaded into the core. It is usefull
     * to force actions in the choice of particles. Some dictionnary have 3
     * set of particles like 'PMS', but if the object return only a name
     * containing the parts 'P' and 'S', the name could mean absolutly nothing.
     * So, the capability file is here to force the object to get the full
     * capacities of the dictionnary by triggering the method self::force_capability().
     *
     * .cap files format :
     * [functionName][:arguments]
     */
    private function check_cap_file() {
        // Non-lethal error here. If we can't open it, we leave it alone.
        if (file_exists($this->filename. '.cap') && is_readable($this->filename . '.cap')) {

            $this->forced_cap = true;
            $handle = @fopen($this->filename . '.cap', 'r');

            if ($handle) {
                while (!feof($handle)) {
                    $buffer = fgets($handle, 4096);

                    if (!empty($buffer)) {
                        if (ctype_lower($buffer[0])) {
                            list($function, $args) = explode(':',$buffer);
                        } else {
                            $function = 'void';
                            $args = $buffer;
                        }

                        if ($function != 'void' && !method_exists($this,$function)) {
                            trigger_error('Method `<em>'.$function.'</em>` does\'nt exists',E_USER_WARNING);
                        } else {
                            $this->forced_capability[$function] = explode(',',trim($args));
                        }
                    }
                } // -- end while
                fclose($handle);
            } // -- end if
            return true;
        } else {
            return false;
        }
    }

    /**
     * Sors une partie de nom aléatoire selon le tag et le fichier associé.
     */
    public function random_particle_from($particle) {
        if (!isset($this->file_particles[$particle]))
            trigger_error ($this->filename . ":load_random_particle: Unknow particle '$particle'.",E_USER_WARNING);

        if (empty($this->file_particles[$particle]))
            return '';

        do {
            $randomId = rand(0,count($this->file_particles[$particle])-1);
            if (isset($this->file_particles[$particle][$randomId]))
                break;
        } while(1);

        $this->debug['particles_used'][$particle] = $this->file_particles[$particle][$randomId];

        return $this->file_particles[$particle][$randomId];

    }

    /**
     * retourne la liste des parties présente dans le fichier dictionnaire
     *
     * @return array
     */
    public function get_file_particle_list() {
        return array_keys($this->file_particles);
    }

    public function get_file_capability_list() {
        return $this->capabilities;
    }

    public function __toString() {
        return basename($this->filename);
    }

    /**
     * Retourne la version courte d'un tag
     */
    public function pfull2lite($par) {
        return $this->_particle[$par];
    }

    /**
     * Retourne la version longue d'un tag
     */
    public function plite2full($par) {
        return array_search($par,$this->_particle);
    }

    public function is_forced() {
        return $this->forcedcap;
    }

}

class Mudnames {
    protected static $_instance = null;

    private $_dictionnaries;
    
    private $latest_name, $latest_file;
     
    protected function __construct($config='') {
        if (!empty($config)) {
            $this->_dictionnaries = new Mudnames_Dictionnaries($config);
        } else {
            $this->_dictionnaries = new Mudnames_Dictionnaries();
        }
    }

    public static function getInstance($config = array(), $auto_create = true) {
        if ((bool) $auto_create && is_null(static::$_instance)) {
            static::$_instance = new static();
        }
        return static::$_instance;
    }
    
    public static function generate_name_from($file='') {
        $mudnames = Mudnames::getInstance();
        $dictionnary = $mudnames->_dictionnaries->open_dictionnary($file);
        $mudnames->latest_file  = $dictionnary->__toString();
        $mudnames->latest_name = $mudnames->_dictionnaries->get_name($dictionnary->__toString());
        return $mudnames->latest_name;
    }

    public static function generates_several_names($number, $file='') {
        $number = (int) $number;

        $names = array();
        while($number-- > 0) {
            $names[] = static::generate_name_from($file);
        }
        return $names;
    }

    public static function get_info($key, $file='') {
        $mudnames = Mudnames::getInstance();
        
        if (empty($file)) {
            $file = $mudnames->latest_file;
        }

        $info = $mudnames->_dictionnaries->get_file_informations($file);
        if (!isset($info[$key])) {
            return false;
        }

        return $info[$key];
    }

    /**
     * Return an array of all the dictionnaries files
     *
     * @return array
     */
    public static function get_file_list() {
        return array_keys(Mudnames::getInstance()->_dictionnaries->get_dictionnaries_list());
    }
}
Return current item: PHP Mud Names