<?php

/*
*
* a PATH interpreter written in PHP by Alexis Ulrich (http://alx2002.free.fr)
* This code is in the public domain.
*
*/

class TuringMachine {

    var
$tape;
    var
$head;    // the head position in the $tape array representation (from 0 to sizeOf($tape))

    
function TuringMachine() {
        
$this->tape = array();
        
$this->head = 0;
    }
    
    
// moves the head one cell to the left
    
function toTheLeft() {
        if (
$this->head == 0) array_unshift($this->tape, 0);
        else
$this->head--;
    }

    
// moves the head one cell to the right
    
function toTheRight() {
        
array_push($this->tape, 0);
        
$this->head++;
    }

    
// increments the value of the current cell
    
function incrementCell() {
        
$this->tape[$this->head] += 1;
    }
    
    
// decrements the value of the current cell
    
function decrementCell() {
        
$this->tape[$this->head] -= 1;
    }
    
    
// writes the $value value in the current cell
    
function writeCell($value) {
        
$this->tape[$this->head] = $value;
    }
    
    
// returns the content of the current cell
    
function readCell() {
        return
$this->tape[$this->head];
    }
    
    
// dipslays the content of the Turing Machine tape
    
function showTape() {
        if (
sizeOf($this->tape) != 0) {
            foreach (
$this->tape as $cell)
                echo
"$cell*";
            echo
' (head on '.$this->head.')<br>';
        }
    }

}

// opens a path file and puts it in an array
function getPath($file_name) {
    return
file($file_name);
}

// displays the ASCII art array representation of a path program
function displayPath($path_array) {
    echo
"<pre>\n";
    foreach (
$path_array as $line) echo $line;
    echo
"</pre>\n";
}

// gets the character at the given coordinates
function getChar ($path_array, $coord) {
    
$line = $path_array[$coord[0]];
    return
substr($line,$coord[1],1);
}

// gets the next coordinates from a given coordinates and direction
function nextCoord ($direction, $coord) {
    switch (
$direction) {
        case
'right':
            return array(
$coord[0],$coord[1]+1);
            break;
        case
'left':
            return array(
$coord[0],$coord[1]-1);
            break;
        case
'up':
            return array(
$coord[0]-1,$coord[1]);
            break;
        case
'down':
            return array(
$coord[0]+1,$coord[1]);
            break;
    }
}


// gets the starter character ('$') position
function getStarter($path_array) {
    
$line_number = 0;
    foreach (
$path_array as $line) {
        
$start_pos = strpos($line, '$');
        if (
$start_pos !== False) return array($line_number,$start_pos);
        
$line_number++;
    }
    return
False;
}

// interprets the path program with a Turing Machine
function pathInterpreter($path_array, $input='') {
    global
$TM, $output, $consumption;
    if (
$input != '') $input_head = 0;
    
$starter = getStarter($path_array);
    
$consumption = '$';
    
$direction = 'right';
    
$coord = nextCoord($direction, $starter);
    
$char = getChar($path_array, $coord);
    
$consumption .= $char;
    
$jump_next_symbol = False;
    while (
$char != '#') {
        if (!
$jump_next_symbol) {
            switch (
$char) {
                case
'!':
                    
$jump_next_symbol = True;
                    break;
                case
'+':
                    
$TM->incrementCell();
                    break;
                case
'-':
                    
$TM->decrementCell();
                    break;
                case
'{':
                    
$TM->toTheLeft();
                    break;
                case
'}':
                    
$TM->toTheRight();
                    break;
                case
',':
                    
// read one character from $input string
                    
$TM->writeCell(ord($input[$input_head++]));
                    break;
                case
'.':
                    
$output .= chr($TM->readCell());
                    break;
                case
'/':
                    switch (
$direction) {
                        case
'right':
                            
$direction = 'up';
                            break;
                        case
'left':
                            
$direction = 'down';
                            break;
                        case
'up':
                            
$direction = 'right';
                            break;
                        case
'down':
                            
$direction = 'left';
                            break;
                    }
                    break;
                case
'\\':
                    switch (
$direction) {
                        case
'right':
                            
$direction = 'down';
                            break;
                        case
'left':
                            
$direction = 'up';
                            break;
                        case
'up':
                            
$direction = 'left';
                            break;
                        case
'down':
                            
$direction = 'right';
                            break;
                    }
                    break;
                case
'^':
                    if (
$TM->readCell() != 0) $direction = 'up';
                    break;
                case
'<':
                    if (
$TM->readCell() != 0) $direction = 'left';
                    break;
                case
'>':
                    if (
$TM->readCell() != 0) $direction = 'right';
                    break;
                case
'v':
                    if (
$TM->readCell() != 0) $direction = 'down';
                    break;
            }
        }
        else
$jump_next_symbol = False;
        
        
// reads the next character
        
$coord = nextCoord($direction, $coord);
        
$char = getChar($path_array, $coord);
        
$consumption .= $char;
    }
}

// counts the number of 'useful' characters in a path program
function pathCountChars($linearized_path) {
  return
count(preg_split("/[\}\{,.$#<>+-]/", $linearized_path)) - 3;
}

// removes all the 'unnecessary' characters from a path program
function pathCleaner($linearized_path) {
    
preg_match_all("/[\}\{,.$#<>+-]/", $linearized_path, $matches);
    return
implode('', $matches[0]);
}


$file_name = 'media.txt';
$path = getPath($file_name);
displayPath($path);
$TM = new TuringMachine();
$output = '';
$consumption = '';
pathInterpreter($path,'');
//$TM->showTape();
//echo "linearized program: $consumption<br>";
//echo "cleaned-up program: ".pathCleaner($consumption).'<br>';
//echo "which contains only ".pathCountChars($consumption).' useful characters (besides the begin and end characters).<br>';
echo "output: $output<br>";
?>