[SOLVED] Battling Infinity: The loop of potential Doom!

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

[SOLVED] Battling Infinity: The loop of potential Doom!

Post by Szandor »

Help!

I'm creating a randomizer engine (you can find it here: http://minaphpprojekt.szandor.com/rannames/) that takes a template file and spits out random strings based on that. It is primarily built for short strings such as names, but I want it to be powerful enough to do more advanced stuff. I'm almost there, but I have a small problem that could potentially kill the server if a badly written template file is used.

First, let's look at a sample template:

Code: Select all

 
m:Description This template generates potions. Only the physical attributes of the potion are given, but in time it will define the effects of the potion as well.
 
.a A {DENSITY} {COLOR} {FORM}, smelling like {SMELL} and tasting like {TASTE}.
.b A {DENSITY} {COLOR} {FORM}, smelling and tasting like {TASTE}.
.c A tasteless, {DENSITY} {COLOR} {FORM}, smelling like {SMELL}.
.d An odorless, {DENSITY} {COLOR} {FORM}, tasting like {TASTE}.
.e A {DENSITY} {COLOR} {FORM} without odor or taste.
 
[SMELL]
{THING}
{STATE} {THING}
 
[TASTE]
{THING}
{STATE} {THING}
{THING} and {THING}
 
[FORM]
draught
elixir
fluid
liquid
mixture
potion
substance
tonic
 
[DENSITY]
bright
bubbling
chunky
clear
dark
fizzing
glowing
milky
muddy
oily
slimy
smoking
sparkling
swirling
thick
thin
viscious
watery
weak
 
[COLOR]
amber
black
blue
brown
cobolt
copper
ebony
emerald
gold
green
ivory
jade
obsidian
ochre
orange
pink
purple
red
rose
ruby
silver
teal
translucent
transparent
violet
white
yellow
 
[STATE]
ancient
boiled
bottled
cultivated
faded
fermented
fresh
hot
old
ripe
salty
smoky
sour
stored
strange
strong
sweetened
watered down
well tended
 
[THING]
acid
acorns
alchohol
ale
apples
blood
blueberries
boots
brandy
bread
cabbage
candy
caramel
carrots
cherries
chocolate
cinnamon
cloth
coffee
dust
eggs
fish
garlic
grapes
grass
herbs
honey
iron
lamp oil
leather
lemon
licorice
lime
liquor
mead
meat
metal
milk
mint
mud
oil
onions
paper
peaches
peanuts
pears
peppar
pepper
pus
rasberries
rhubarbs
roses
rot
rum
salt
spice
strawberries
sugar
sweat
tea
tomatoes
urine
vanilla
vomit
walnuts
water
wax
wine
wool
This template will, when runt through the script, generate a random potion. It starts off by randomly choosing one of the patterns (lines beginning with a dot), swap the tags (text enclosed by curly brackets) for an item from the corresponding list and return that. Should the item itself contain tags, those tags are also replaced by random items by recursively calling the function from within itself. As you understand, this can potentially cause an infinite loop if list A contains a tag for list B, and list B contains a tag for list A. The problem can be circumvented through proper syntax, but I'd rather the possibility of crashing the server was not there at all.

This is the code of the randomizer engine:

Code: Select all

<?
 
// First we open the template file for reading.
$file = fopen($namefile, "r") or exit("Unable to open file!");
 
// As long as we don't reach the end of the file, the following is run on each line.
while(!feof($file)) {
 
    // We go to the next line (or the first line, if run for the first time).
    $nextline = fgets($file);
 
    // Two consecutive slashes and anything after is removed, as are empty lines and beginning and trailing whitespaces.
    $nextline = preg_replace("/\/\/.+|(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "", $nextline);
    $nextline = preg_replace("/^[ \t]+|[ \t]+$|\n$/", "", $nextline);
    
    // If, after this, the line is not empty...
    if ($nextline != "") {
        // If the line begins with "m:" it is metadata and placed in the $metainfo array.
        if (preg_match('/^\m\:/',$nextline)) {
            $metatitle = preg_replace('/^\m\:/','',$nextline);
            $nextline = $metatitle;
            $metatitle = preg_replace('/(?=\s).*/','',$metatitle);
            $nextline = preg_replace('/^\S*/','',$nextline);
            $nextline = preg_replace('/^\s*/','',$nextline);
            $metainfo[$metatitle] = $nextline;
        // If the line begins with a dot it is a pattern and is placed in the $patterns array
        } elseif (preg_match('/^\./',$nextline)) {
            $pattitle = preg_replace('/^\./','',$nextline);
            $pattitle = preg_replace('/(?= ).*/','',$pattitle);
            $nextline = preg_replace('/^[^\n|^ ]*(?= )/','',$nextline);
            $nextline = preg_replace('/^ /','',$nextline);
            $patterns[$pattitle] = $nextline;
        // If the line begins with a square bracket it is a list header and is saved in a variable for use soon.
        } elseif (preg_match('/^\[.*/',$nextline)) {
            $nextline = preg_replace('/^\[/','',$nextline);
            $nextline = preg_replace('/\]$/','',$nextline);
            $sectline = $nextline;
        // If the line is neither of the above it's considered a part of a list and is placed in a multidimensional array under the previously saved header.
        } else {
            $elements[$sectline][] = $nextline;
        }
    }
}
 
$tags = $elements;
 
// When it's all over, we close the file. We won't be needing it anymore.
fclose($file);
 
// This function does the substituting.
function randel($anelement) {
    global $elements;   // We need this to be global.
    $anelement = preg_replace("/\{|\}/","",$anelement); // We strip away the curly brackets.
    $anelement = implode($anelement);   // It needs to be a string, not an array.
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;    // Since array_rand() can't be used on multi-dimensional arrays, we count the number of values in the selected sub-array, ...
    $anelement2 = rand(0,$anelement2);  // ... randomly choose a number ...
    $theelement = $elements[$anelement][$anelement2];   // ... and then call the sub array.
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel,$theelement);
    }
 
    return $theelement;
}
 
?>
First, the template file is read in, the contents are placed in appropriate arrays and the file is then closed. The page that contains the interface then calls the function, sending a tag to be processed. This page looks like this:

Code: Select all

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<?
include 'settings.php'; // Loads the settings.
include_once 'lang' . DIRECTORY_SEPARATOR . $settings[lang] . '.php'; // Loads the language of the GUI.
?>
<html xmlns="http://www.w3.org/1999/xhtml" lang="<? echo $settings[lang]; ?>" xml:lang="<? echo $settings['lang']; ?>">
    <head>
        <title><? echo $lang['title']; ?></title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <link href="rannames.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <h1><? echo $lang['title']; ?></h1>
        <p><? echo $lang['intro']; ?></p>
        <form method="post" action="<? $_SERVER['PHP_SELF'] ?>">
            <p>
                <select name="template">
<?
 
if (array_key_exists('_submit_check', $_POST)) {    // If a template has been set by the user,
    $namefile = "templates/" . $_POST['template'];  // that template is active.
} else {    // Otherwise,
    $namefile = "templates/" . $settings['def_temp'];   // the default template is active.
}
 
// This will find all documents with the ".name" file ending in the folder "templates" and list them in an array.
if ($handle = opendir('templates')) {   // We open the folder.
    $counter = 0;   // The initial position of the array to write to.
    while (false !== ($file = readdir($handle))) {  // Loops as long as there are files to list in the folder.
        if (preg_match('/^.+\.name$/',$file)) { // Makes sure only ".name"-files are processed.
            $templatedir[$counter] = $file; // The actual writing of the array.
            $counter = $counter + 1;    // The next position of the array to write to.
        }
    }
 
}
closedir($handle);  // Then we close the directory.
 
sort($templatedir); // Let's sort the list alphabetically.
 
foreach ($templatedir as $key => $val) {    // For every value in the array,
    if ($val != $_POST['template']) {   // if the template is not the active one,
        echo "\t\t\t\t\t<option value=\"$val\">$val</option>\n";    // we add it to the list of options.
    } else {    // If it´s the active template,
        echo "\t\t\t\t\t<option value=\"$val\" selected=\"selected\">$val</option>\n";  // we make it pre-selected.
    }
}
 
?>
                </select>
            </p>
            <p><input style="width:3em;" name="quantity" maxlength="3" value="<? if ($_POST['quantity'] != "") {    // If the user has set a quantity of names to list,
                echo $_POST['quantity'];    // we write out that quantity.
            } else {    // Otherwise,
                echo "10";  // we use a default.
            } ?>" /><input type="hidden" name="_submit_check" value="1" /></p>
            <p><button type="submit"><? echo $lang['button']; ?></button></p>
        </form>
        <h2><? echo $lang['metadata']; ?></h2>
<?
 
require 'engine.php';   // We'll need the actual randomizer engine now.
 
if (isset($metainfo)) {
    echo "<dl>\n";
    foreach($metainfo as $metatitle => $metatext) {
        echo "<dt>" . $metatitle . "</dt>\n";
        echo "<dd>" . $metatext . "</dd>\n";
    }
    echo "</dl>\n";
} else {
    echo "<p style=\"font-style:italic;\">No meta info.</p>\n";
}
 
/*if (isset($metainfo)) {
    echo "<pre>";
    print_r ($metainfo);
    echo "</pre>";
} else {
    echo "<p>No meta info.</p>\n";
}*/
 
?>
 
        <h2><? echo $lang['list']; ?></h2>
 
        <ul id="namelist">
<?
 
// If the user has set a quantity of names to list, we randomize a name that number of times. Otherwise, we do it ten times.
if ($_POST['quantity'] != "") {
    $b = $_POST['quantity'];
} else {
    $b = 10;
}
 
for($a = 0;$a != $b;$a++) { // This loops the number of times specified above.
 
    $thepatterntitle = array_rand($patterns);   // We choose a random pattern,
    $thepattern = $patterns[$thepatterntitle];  // and write it to a variable.
 
    $name = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel,$thepattern); // This replaces the pattern with a random name, based on that pattern.
    echo "\t\t\t<li>" . $name . "</li>\n";  // Then we just print it on the page.
}
 
?>
        </ul>
 
<?
 
// This lists all availible patterns in the template file.
/* echo "<h2>" . $lang['patterns'] . "</h2>\n<ul>";
foreach($patterns as $patnum => $patpat) {
    echo "<li>" . $patpat . "</li>\n";
}
echo "</ul>"; */
 
echo "<h2>Input file</h2>\n";
echo "<pre class=\"box\">\n";
$file = fopen($namefile, "r") or exit("Unable to open file!");
while(!feof($file)) {
    // $nextline = fgets($file);
    echo fgets($file);
}
echo "</pre>";
 
?>
 
    </body>
</html>
Does anyone know how I can prevent infinite loops from happening, even if I create an infinite reference between two (or more) lists? I somehow want to count the number of iterations run and limit them to a certain number so that it only loops for, say, 50 times.

Can it be done? If so, how?

(I suppose I could create 50 identical functions and call one after another, but that doesn't seem to be very correct.)
Last edited by Szandor on Mon Nov 16, 2009 8:32 pm, edited 1 time in total.
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Battling Infinity: The loop of potential Doom!

Post by requinix »

If you're doing it recursively (which I think you are) you can keep track of the tags replaced on each "branch" of the call "tree".

Give the function a optional second parameter: an array of tags replaced. When the function recurses it adds the tag being replaced to the list; if the tag is already present then there is a loop somewhere and it should stop.

The trick is to add the tag to a copy of the list so you don't modify the original one. If it starts with tags=(apple, banana, cucumber) then it makes a copy for each tag being replaced and adds the tag to the copy: tags=(apple, banana, cucumber, date) then tags=(apple, banana, cucumber, elderberry) then tags=(apple, banana, cucumber, fig) and so on.

Code: Select all

for each token being replaced
    if (token is in tags) stop
 
    tagscopy = tags
    tagscopy[] = token
    recurse(arg1, arg2, arg3, tagscopy)
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

tasairis wrote:If you're doing it recursively (which I think you are) you can keep track of the tags replaced on each "branch" of the call "tree".

Give the function a optional second parameter: an array of tags replaced. When the function recurses it adds the tag being replaced to the list; if the tag is already present then there is a loop somewhere and it should stop.

The trick is to add the tag to a copy of the list so you don't modify the original one. If it starts with tags=(apple, banana, cucumber) then it makes a copy for each tag being replaced and adds the tag to the copy: tags=(apple, banana, cucumber, date) then tags=(apple, banana, cucumber, elderberry) then tags=(apple, banana, cucumber, fig) and so on.

Code: Select all

for each token being replaced
    if (token is in tags) stop
 
    tagscopy = tags
    tagscopy[] = token
    recurse(arg1, arg2, arg3, tagscopy)
The main problem here is that I can't use (or don't know how to use) parameters with preg_replace_callback(). I use the following:

Code: Select all

preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel,$theelement);
This is used outside the function to start the replacement of tags, but also inside the function itself to replace any and all subtags. The regex I use with preg_replace_callback() makes sure each tag is found and processed individually using the function "randel". If I specify any other parameters by using "randel(par,par)", the separated tags are not sent.

Also, what tags have been replaced is unimportant, only the number of times they have been subreplaced. I don't wan't to limit what tags can be used, only make sure that an infinite loop does not occur.
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Battling Infinity: The loop of potential Doom!

Post by requinix »

Either you're overprotective or underprotective. The former means no infinite loops but possible false alarms while the latter means more flexibility but less security. You won't be able to get the middle ground.

What I gave was the former. If there is a chain of tags where the first tag appears later in the list there is a chance of an infinite loop, but it also means you can't nest tags somewhere inside themselves (many times you can get around that though).
For the arguments you can use preg_match and your own loop, or preg_replace and you construct the code to execute.
User avatar
iankent
Forum Contributor
Posts: 333
Joined: Mon Nov 16, 2009 4:23 pm
Location: Wales, United Kingdom

Re: Battling Infinity: The loop of potential Doom!

Post by iankent »

An alternative would be to use a counter and not worry about whether a tag has been matched before, just how many nested levels you've reached. Same problem though, you need to pass a counter variable to the function doing the replacements so it knows when its reached too many nested levels.

Personally I'd use preg_replace to call another function passing in the counter as an argument (the external call to the function would pass 0 and the internal ones would pass the variable). E.g.

Code: Select all

recursiveFunction(0); // call the function and pass 0
function recursiveFunction($counter) {
$counter++;
if($counter > 50) return;
recursiveFunction($counter); // start another nested level
}
Still means you need to pass a variable to the function though. I have this bit of code but I can't say exactly how it works (not a regex expert at all):
$text = preg_replace('regex here', "recursiveFunction($counter)", $text);

All I know is it works for me - when it finds a match based on the regex it calls the recursiveFunction() function, passing $counter along with it. So the example above expanded:

Code: Select all

 
$text = preg_replace('regex here', "recursiveFunction(0)", $text); //find a match and pass 0
function recursiveFunction($counter) {
$counter++;
if($counter > 50) return;
$text = preg_replace('regex here', "recursiveFunction($counter)", $text); // find another match and pass $counter
}
hth

edit:
just re-reading my post and I'm not sure it quite makes sense - its late and I'm tired lol... see if it applies to your problem and works, and if not, ignore me :)
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

iankent wrote:An alternative would be to use a counter and not worry about whether a tag has been matched before, just how many nested levels you've reached. Same problem though, you need to pass a counter variable to the function doing the replacements so it knows when its reached too many nested levels.

Personally I'd use preg_replace to call another function passing in the counter as an argument (the external call to the function would pass 0 and the internal ones would pass the variable). E.g.

Code: Select all

recursiveFunction(0); // call the function and pass 0
function recursiveFunction($counter) {
$counter++;
if($counter > 50) return;
recursiveFunction($counter); // start another nested level
}
Still means you need to pass a variable to the function though. I have this bit of code but I can't say exactly how it works (not a regex expert at all):
$text = preg_replace('regex here', "recursiveFunction($counter)", $text);

All I know is it works for me - when it finds a match based on the regex it calls the recursiveFunction() function, passing $counter along with it. So the example above expanded:

Code: Select all

 
$text = preg_replace('regex here', "recursiveFunction(0)", $text); //find a match and pass 0
function recursiveFunction($counter) {
$counter++;
if($counter > 50) return;
$text = preg_replace('regex here', "recursiveFunction($counter)", $text); // find another match and pass $counter
}
hth

edit:
just re-reading my post and I'm not sure it quite makes sense - its late and I'm tired lol... see if it applies to your problem and works, and if not, ignore me :)
And where in this code do I pass along the string to be replaced? I mean, if all the function does is loop itself X times it's not of much use, is it?
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

tasairis wrote:Either you're overprotective or underprotective. The former means no infinite loops but possible false alarms while the latter means more flexibility but less security. You won't be able to get the middle ground.

What I gave was the former. If there is a chain of tags where the first tag appears later in the list there is a chance of an infinite loop, but it also means you can't nest tags somewhere inside themselves (many times you can get around that though).
For the arguments you can use preg_match and your own loop, or preg_replace and you construct the code to execute.
So what you're saying is that my only option is to write 49 identical functions that are run after each other until it reaches function number 50 that returns an error?
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

I've now written code that does what I want, but in the long run it's not really useable. This is how it looks:

Code: Select all

<?
 
// First we open the template file for reading.
$file = fopen($namefile, "r") or exit("Unable to open file!");
 
// As long as we don't reach the end of the file, the following is run on each line.
while(!feof($file)) {
 
    // We go to the next line (or the first line, if run for the first time).
    $nextline = fgets($file);
 
    // Two consecutive slashes and anything after is removed, as are empty lines and beginning and trailing whitespaces.
    $nextline = preg_replace("/\/\/.+|(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "", $nextline);
    $nextline = preg_replace("/^[ \t]+|[ \t]+$|\n$/", "", $nextline);
    
    // If, after this, the line is not empty...
    if ($nextline != "") {
        // If the line begins with "m:" it is metadata and placed in the $metainfo array.
        if (preg_match('/^\m\:/',$nextline)) {
            $metatitle = preg_replace('/^\m\:/','',$nextline);
            $nextline = $metatitle;
            $metatitle = preg_replace('/(?=\s).*/','',$metatitle);
            $nextline = preg_replace('/^\S*/','',$nextline);
            $nextline = preg_replace('/^\s*/','',$nextline);
            $metainfo[$metatitle] = $nextline;
        // If the line begins with a dot it is a pattern and is placed in the $patterns array
        } elseif (preg_match('/^\./',$nextline)) {
            $pattitle = preg_replace('/^\./','',$nextline);
            $pattitle = preg_replace('/(?= ).*/','',$pattitle);
            $nextline = preg_replace('/^[^\n|^ ]*(?= )/','',$nextline);
            $nextline = preg_replace('/^ /','',$nextline);
            $patterns[$pattitle] = $nextline;
        // If the line begins with a square bracket it is a list header and is saved in a variable for use soon.
        } elseif (preg_match('/^\[.*/',$nextline)) {
            $nextline = preg_replace('/^\[/','',$nextline);
            $nextline = preg_replace('/\]$/','',$nextline);
            $sectline = $nextline;
        // If the line is neither of the above it's considered a part of a list and is placed in a multidimensional array under the previously saved header.
        } else {
            $elements[$sectline][] = $nextline;
        }
    }
}
 
$tags = $elements;
 
// When it's all over, we close the file. We won't be needing it anymore.
fclose($file);
 
function randel($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel2,$theelement);
    }
 
    return $theelement;
}
 
function randel2($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel3,$theelement);
    }
 
    return $theelement;
}
 
function randel3($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel4,$theelement);
    }
 
    return $theelement;
}
 
function randel4($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel5,$theelement);
    }
 
    return $theelement;
}
 
function randel5($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel6,$theelement);
    }
 
    return $theelement;
}
 
function randel6($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel7,$theelement);
    }
 
    return $theelement;
}
 
function randel7($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel8,$theelement);
    }
 
    return $theelement;
}
 
function randel8($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randel9,$theelement);
    }
 
    return $theelement;
}
 
function randel9($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = preg_replace_callback('/\{[^\{\}\r\n]*\}/',randellast,$theelement);
    }
 
    return $theelement;
}
 
function randellast($anelement) {
    global $elements;
    $anelement = preg_replace("/\{|\}/","",$anelement);
    $anelement = implode($anelement);
    $anelement2 = count($elements[$anelement], COUNT_RECURSIVE) - 1;
    $anelement2 = rand(0,$anelement2);
    $theelement = $elements[$anelement][$anelement2];
 
    if (preg_match('/^.*{.*?}.*$/', $theelement)!==0) {
        $theelement = "[overflow error]";
    }
 
    return $theelement;
}
 
?>
And this is only for ten iterations. If I want to raise that number to 100 I'll have quite a repetitive task of adding new functions ahead of me. Also, the code will grow to a rather large number of lines if I do that. Are you sure this is the only way of doing it? It seems rather poor. Isn't programming supposed to take care of the repetitive tasks for us?
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Battling Infinity: The loop of potential Doom!

Post by requinix »

Szandor wrote:So what you're saying is that my only option is to write 49 identical functions that are run after each other until it reaches function number 50 that returns an error?
No... Not even close.

What you tried, with all those functions, was more like what iankent mentioned: keeping a counter for how deep the recursion goes and stopping at some point. But using 50 functions is far from what he suggested.
I'm talking about keeping track of what happened in the past and using that knowledge to guess whether it's in a possibly-infinite loop or not.
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

tasairis wrote:
Szandor wrote:So what you're saying is that my only option is to write 49 identical functions that are run after each other until it reaches function number 50 that returns an error?
No... Not even close.

What you tried, with all those functions, was more like what iankent mentioned: keeping a counter for how deep the recursion goes and stopping at some point. But using 50 functions is far from what he suggested.
I'm talking about keeping track of what happened in the past and using that knowledge to guess whether it's in a possibly-infinite loop or not.
Yes, and the question still stands. How do I create such a counter in the function I have without breaking the functionality of the function?
Szandor
Forum Newbie
Posts: 12
Joined: Wed Aug 19, 2009 5:58 pm

Re: Battling Infinity: The loop of potential Doom!

Post by Szandor »

Never mind, I have solved it now. It works just the way I want it to. I used global variables to keep track of the iterations and while it isn't completely how I like it, it's close enough.

Thanks for the input though.
Post Reply